0
点赞
收藏
分享

微信扫一扫

android操作sdcard中的多媒体文件


 

最近做了一个android音乐播放器,个人感觉最难的就是“后台播放”以及有关“播放列表”的部分,但是总算是找到了实现的方式。不同的人实现的方式可能不一样,这里我就分享一下自己对“播放列表”这个模块的一些实现方法,“后台播放”会在下一篇博文中进行介绍,希望大家也能分享一下自己的一些思路。

     android使用ContentProvider来支持不同应用程序的数据共享,为了方便其他应用程序对sdcard中的数据进行操作,sdcard也提供了ContentProvider接口,这里就以访问音频文件为例,视频以及图片的操作也类似,这里就不在赘述。

  

<pre>Cursor c =            this           .getContentResolver().</pre>           


           <pre>query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,</pre>          


           /*这个字符串数组表示要查询的列*/




new            String[]{MediaStore.Video.Media.TITLE,             //音乐名           


            MediaStore.Audio.Media.DURATION,                       //音乐的总时间           


            MediaStore.Audio.Media.ARTIST,                     //艺术家           


            MediaStore.Audio.Media._ID,                        //id号           


            MediaStore.Audio.Media.DISPLAY_NAME,                   //音乐文件名           


            MediaStore.Audio.Media.DATA                    //音乐文件的路径           


           },           


            null           ,                                 //查询条件,相当于sql中的where语句           


            null           ,                                  //查询条件中使用到的数据           


            null           );                                //查询结果的排序方式



  通过MediaStore.Audio.Media.XXX来访问音乐文件的一些信息,这里只列出了一部分,可以根据需要进行增添和删除。



 至此,Cursor c就已经保存了sdcard内所以音频文件的信息,下面的操作就是围绕这个Cursor展开的。



首先定义三个数组:


private           int          [] _ids;              //存放音乐文件的id数组          


           private           String[] _titles;           //存放音乐文件的标题数组          


           private           String[] _path;             //存放音乐文件的路径



_ids保存了所有音乐文件的_ID,用来确定到底要播放哪一首歌曲,_titles存放音乐名,用来显示在播放界面,而_path存



放音乐文件的路径(删除文件时会用到)。



  接下来再定义一个变量,用来定位选择的是哪一首音乐:



private int pos;



  接下来将音乐文件的信息存放在相应的数组中:  



c.moveToFirst();          


            _ids =            new            int           [c.getCount()];           


            _titles =            new            String[c.getCount()];           


            _path =            new            String[c.getCount()];           


            for           (           int            i=0;i<c.getCount();i++){           


                       _ids[i] = c.getInt(3);                     


                       _titles[i] = c.getString(0);           


                       _path[i] = c.getString(5).substring(4);           


                       c.moveToNext();           


           }        



有人可能会问为什么获取路径的格式是_path[i]=c.geString(5).substring(4)?因为MediaStore.Audio.Media.DATA



得到的内容格式为/mnt/sdcard/[子文件夹名/]音乐文件名,而我们想要得到的是/sdcard/[子文件夹名]音乐文件名,



所以要做相应的裁剪操作。



  接下来把Cursor中的信息显示到listview中:




MusicListAdapter adapter =            new            MusicListAdapter(           this           , c);           


           listview.setAdapter(adapter);



MusicListAdapter是一个自定义的Adapter,继承自BaseAdapter,这里只贴出代码,不做讲解。



package com.alex.video;        


                  


         import android.content.Context;        


         import android.database.Cursor;        


         import android.view.LayoutInflater;        


         import android.view.View;        


         import android.view.ViewGroup;        


         import android.widget.BaseAdapter;        


         import android.widget.ImageView;        


         import android.widget.TextView;        


                  


          public          class          MusicListAdapter extends BaseAdapter{         


                   private          Context myCon;         


                   private          Cursor myCur;         


                   private          int          pos=-1;         


                   


                   public          MusicListAdapter(Context con,Cursor cur){         


                   this         .myCon = con;         


                   this         .myCur = cur;         


                   }         


                   


                   @Override         


                   public          int          getCount() {         


                   


                   return          this         .myCur.getCount();         


                   }         


                  


                   @Override         


                   public          Object getItem(         int          position) {         


                   


                   return          position;         


                   }         


                  


                   @Override         


                   public          long          getItemId(         int          position) {         


                   


                   return          position;         


                   }         


                  


                   @Override         


                   public          View getView(         int          position, View convertView, ViewGroup parent) {         


                   convertView = LayoutInflater.from(myCon).inflate(R.layout.musiclist,         


                   null         );         


                   myCur.moveToPosition(position);         


                   TextView videoTitle = (TextView)convertView.findViewById(R.id.musictitle);         


                   if          (myCur.getString(0).length()>24){         


                   try          {         


                   String musicTitle = bSubstring(myCur.getString(0).trim(),24);         


                   videoTitle.setText(musicTitle);         


                   }          catch          (Exception e) {         


                   


                   e.printStackTrace();         


                   }         


                   }         else          {         


                   videoTitle.setText(myCur.getString(0).trim());         


                   }         


                   TextView videoArtist = (TextView)convertView.findViewById(R.id.musicartist);         


                   if          (myCur.getString(2).equals(         "<unknown>"         )){         


                   videoArtist.setText(         "未知艺术家"         );         


                   }         else         {         


                   videoArtist.setText(myCur.getString(2));         


                   }         


                   TextView videoTime = (TextView)convertView.findViewById(R.id.musictime);         


                   videoTime.setText(toTime(myCur.getInt(1)));         


                   ImageView videoItem = (ImageView)convertView.findViewById(R.id.musicitem);         


                   videoItem.setImageResource(R.drawable.item);         


                   return          convertView;         


                   }         


                   


                   /*时间格式转换*/         


                   public          String toTime(         int          time) {         


                  


                   time /= 1000;         


                   int          minute = time / 60;         


                   int          hour = minute / 60;         


                   int          second = time % 60;         


                   minute %= 60;         


                   return          String.format(         "%02d:%02d"         , minute, second);         


                   }         


                  


                   /*字符串裁剪*/         


                   public          static          String bSubstring(String s,          int          length) throws Exception           


                   {           


                   


                   byte         [] bytes = s.getBytes(         "Unicode"         );           


                   int          n = 0;          // 表示当前的字节数           


                   int          i = 2;          // 要截取的字节数,从第3个字节开始           


                   for          (; i < bytes.length && n < length; i++)           


                   {           


                   // 奇数位置,如3、5、7等,为UCS2编码中两个字节的第二个字节           


                   if          (i % 2 == 1)           


                   {           


                   n++;          // 在UCS2第二个字节时n加1           


                   }           


                   else         


                   {           


                   // 当UCS2编码的第一个字节不等于0时,该UCS2字符为汉字,一个汉字算两个字节           


                   if          (bytes[i] != 0)           


                   {           


                   n++;           


                   }           


                   }           


                   }           


                   // 如果i为奇数时,处理成偶数           


                   if          (i % 2 == 1)           


                   


                   {           


                   // 该UCS2字符是汉字时,去掉这个截一半的汉字           


                   if          (bytes[i - 1] != 0)           


                   i = i - 1;           


                   // 该UCS2字符是字母或数字,则保留该字符           


                   else         


                   i = i + 1;           


                   }           


                   


                   return          new          String(bytes, 0, i,          "Unicode"         );           


                   }           


         }

在上一篇随笔中,我介绍了如何在程序中查询sdcard内的多媒体文件,并且显示到播放列表中,但是,如果在sdcard内删除、增加一些多媒体文件,如何让播放列表也更新呢,这里我分享一下自己在项目中的一些解决方法,希望对大家有所帮助。                                     


  首先,我简单介绍一下android是如何扫描sdcard内的多媒体信息的,详细请阅读stay的博文



  当android的系统启动的时候,系统会自动扫描sdcard内的多媒体文件,并把获得的信息保存在一个系统数据库中,以后在其他程序中如果想要访问多媒体文件的信息,其实就是在这个数据库中进行的,而不是直接去sdcard中取,理解了这一点以后,问题也随着而来:如果我在开机状态下在sdcard内增加、删除一些多媒体文件,系统会不会自动扫描一次呢?答案是否定的,也就是说,当你改变sdcard内的多媒体文件时,保存多媒体信息的系统数据库文件是不会动态更新的。



  那么如何让多媒体数据库中的数据更新呢?我们可以采用广播机制来实现:在应用程序中发送一个广播,让android系统扫描sdcard并更新多媒体数据库        



private             void             scanSdCard(){            


                         IntentFilter intentfilter =             new             IntentFilter( Intent.ACTION_MEDIA_SCANNER_STARTED);            


                         intentfilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);            


                         intentfilter.addDataScheme(            "file"            );            


                         scanSdReceiver =             new             ScanSdReceiver();            


                         registerReceiver(scanSdReceiver, intentfilter);            


                         sendBroadcast(            new             Intent(Intent.ACTION_MEDIA_MOUNTED,            


                         Uri.parse(            "file://"             + Environment.getExternalStorageDirectory().getAbsolutePath()))); }



  其中ScanSdReceiver是一个自定义的广播接收器,继承自BroadCastReceiver,因为android系统开始扫描sdcard以及扫描完毕时都会发送一个系统广播来表示当前扫描的状态,这样我们就可以很方便通过判断当前的扫描状态加一些自己的逻辑操作,ScanSdReceiver的代码如下:


public             class             ScanSdReceiver extends BroadcastReceiver {            


                        


                         private             AlertDialog.Builder  builder =             null            ;            


                         private             AlertDialog ad =             null            ;            


                         private             int             count1;            


                         private             int             count2;            


                         private             int             count;            


                         @Override            


                         public             void             onReceive(Context context, Intent intent) {            


                         String action = intent.getAction();            


                         if             (Intent.ACTION_MEDIA_SCANNER_STARTED.equals(action)){            


                         Cursor c1 = context.getContentResolver()            


                         .query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,            


                         new             String[]{MediaStore.Audio.Media.TITLE,            


                         MediaStore.Audio.Media.DURATION,            


                         MediaStore.Audio.Media.ARTIST,            


                         MediaStore.Audio.Media._ID,            


                         MediaStore.Audio.Media.DISPLAY_NAME },            


                         null            ,             null            ,             null            );            


                         count1 = c1.getCount();            


                         System.            out            .println(            "count:"            +count);            


                         builder =             new             AlertDialog.Builder(context);            


                         builder.setMessage(            "正在扫描存储卡..."            );            


                         ad = builder.create();            


                         ad.show();            


                         


                         }            else             if            (Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)){            


                         Cursor c2 = context.getContentResolver()            


                         .query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,            


                         new             String[]{MediaStore.Audio.Media.TITLE,            


                         MediaStore.Audio.Media.DURATION,            


                         MediaStore.Audio.Media.ARTIST,            


                         MediaStore.Audio.Media._ID,            


                         MediaStore.Audio.Media.DISPLAY_NAME },            


                         null            ,             null            ,             null            );            


                         count2 = c2.getCount();            


                         count = count2-count1;            


                         ad.cancel();            


                         if             (count>=0){            


                         Toast.makeText(context,             "共增加"             +             


                         count +             "首歌曲"            , Toast.LENGTH_LONG).show();            


                         }             else             {            


                         Toast.makeText(context,             "共减少"             +            


                         count +             "首歌曲"            , Toast.LENGTH_LONG).show();            


                         }               


                         }               


                         }            


            }


  

android操作sdcard中的多媒体文件_数据库


  

android操作sdcard中的多媒体文件_数据库_02



  这里我们定义了两个Cursor对象,分别用来存储扫描前后的多媒体信息,并给出相应的提示。  



  以前有很多朋友问过我,为什么扫描以后播放列表中的数据条数没有发生相应的改变。要实现播放列表在扫描后更新,必须重新读取多媒体信息到Cursor中,并且重新设置adapter,最后还要调用XXXAdapter.notifyDataSetChanged()来通知UI更新。(可以参考第一张的内容)



  上面的操作都是手动在SDCARD中添加或着删除多媒体文件,下面介绍如何在列表中删除SDCARD中的多媒体文件。



  在上一篇随笔中,我们使用了系统提供的ContentProvider来查询sdcard中的多媒体文件,我们同样可以使用这个ContentProvider来进行删除操作: 



private             void             deleteMusic(            int             position){            


                         this            .getContentResolver().delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,             


                         MediaStore.Audio.Media._ID +             "="             + _ids[position],             


                         null            );            


            }



   其中“多媒体文件的ID”可以从_ids数组中取得(关于_ids数组请参考第一张的内容)。这样,我们是否就已经从SDCARD中删除了指定_ID的多媒体文件了呢?  其实当你打开FileExplorer时会发现,原来的文件并没有被删除,— —!杯具,搞了半天文件还在,我第一次遇到这个问题的时候也是纠结了老半天。。。



为什么没有被删除,原因是上面的删除操作只是删除了系统多媒体数据库中的相应记录,而并没有删除SDCAED中的文件(注意:多媒体信息数据库和SDCARD中的多媒体文件并不会自动保持同步),这个时候如果再次扫描SDCARD,你会发现刚才从播放列表中删除的行会再次出现。



   其实要想真正的从SDCARD中删除多媒体文件并不难,可能有朋友会想到这样的方法:遍历SDCARD中的多媒体文件,然后把想要删除的文件和其他文件逐一比较,找到文件路径,最后进行删除。这种方法是可以实现删除操作的,不过效率很低,如果SDCARD中的文件夹以及文件很多,也不知道要用掉多少时间。。



  在上一张中我们从多媒体数据库中读出来一项很重要的信息:MediaStore.Audio.Media.DATA



并且取得里面的字串并存放在了_path数组中,最终的数据格式为:/SDCARD/[子文件夹名]文件名 ,又了这个路径,我们就可以很方便的从SDCARD中删除多媒体文件了


private             void             deleteMusicFile(            int             position){            


                         File file =             new             File(_path[position]);            


                         file.delete();            


            }



   同样,删除文件后要想播放列表同步更新,也必须执行刚才介绍的一系列操作。   



 

举报

相关推荐

0 条评论