在上一篇隨筆中,我介紹了如何在程式中查詢sdcard內的多媒體檔案,並且顯示到播放清單中,但是,如果在sdcard內刪除、增加一些多媒體檔案,如何讓播放清單也更新呢,這裡我分享一下自己在項目中的一些解決方案,希望對大家有所協助。 首先,我簡單介紹一下android是如何掃描sdcard內的多媒體資訊的,詳細請閱讀stay的博文:http://www.cnblogs.com/stay/articles/1957571.html 當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;@Overridepublic 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();}}}}
這裡我們定義了兩個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();}
同樣,刪除檔案後要想播放清單同步更新,也必須執行剛才介紹的一系列操作。