这段时间一个MP3小项目,其中有一个功能就是扫描SD卡内所有MP3文件。
在这儿我首先就想到了一个方法:遍历SD卡内所有目录或文件
1.遍历SD卡内所有目录或文件
package com.wenhao.test.sddemo; import java.io.File; import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class MainDemo extends Activity { /** Called when the activity is first created. */ private Button button = null; private File path; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); button = (Button)findViewById(R.id.mybutton); //检测SD卡是否存在 if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { path = Environment.getExternalStorageDirectory(); }else{ Toast.makeText(this, "没有SD卡", Toast.LENGTH_LONG).show(); finish(); } button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub getAllFiles(path); } }); } // 遍历接收一个文件路径,然后把文件子目录中的所有文件遍历并输出来 private void getAllFiles(File root){ File files[] = root.listFiles(); if(files != null){ for (File f : files){ if(f.isDirectory()){ getAllFiles(f); }else{ System.out.println(f); } } } } }
但是这样做,我们先扫描所有文件或目录,然后将其加入到我们自己的数据库里。由于遍历全部文件或目录效率很低,所以这种方法不可取,这里只是顺带提及一下这个可行的方法。
2.利用Android系统自建数据库
上一篇文章里我们用到Android系统自建的数据库,使用ContentProvider提供联系人数据。
android.provider.ContactsContract.Contacts.CONTENT_URI
在Android机中,系统会根据SD卡内的目前所有MP3文件,定时更新(新建)音频文件信息数据库。这个数据在哪儿呢?
并不在SD卡里,root后的机器通过R.E.管理器就可以看到相关数据库了。
/data/data/com.android.providers.media/databases/external.db
我的手机(魅族MX2)external.db里面的表
将external.db用工具打开,
红色框就是音频文件的相关属性,一般能包含音频文件的大部分属性,若其中没有包含你要的属性,你可以自建数据库。否则,你可以利用此数据库,可以减少一部分代码。
由于我的音频属性中包含自带数据库中没有的属性,如:path,folder,format,channels,kbps,hz属性。
因此我选则了自建数据库。
下面是一段利用自带数据库获取SD卡内所有音频文件的路径代码:
/** * 获取SD卡内所有音频文件的路径 * 有多少条记录,List就有多大 * @return * ScanInfo类型的表 */ public List<ScanInfo> searchAllDirectory() { List<ScanInfo> list = new ArrayList<ScanInfo>(); StringBuffer sb = new StringBuffer();//存放data的缓存 //要返回的列(属性) String[] projection = { MediaStore.Audio.Media.DISPLAY_NAME,MediaStore.Audio.Media.DATA }; /* * 参数: * uri 提供内容的地址 * projection 查询要返回的列 * selection 查询where字句 * selectionArgs 查询条件属性值 * sortOrder 结果排序规则 */ Cursor cr = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, null,null, MediaStore.Audio.Media.DISPLAY_NAME); String displayName = null; String data = null; while (cr.moveToNext()) {//移动到下一刻度,返回boolean类型值 displayName = cr.getString(cr.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));//音频文件名 data = cr.getString(cr.getColumnIndex(MediaStore.Audio.Media.DATA));//音频文件路径+文件名 if(data!=null&&displayName!=null){ data = data.replace(displayName, " ");// 替换文件名留下它的上一级目录 } if (!sb.toString().contains(data)) { list.add(new ScanInfo(data, true));//默认全部勾选 sb.append(data);//加入到缓存里 } } cr.close();//关闭游标 return list; }
如果是获取音频文件其他属性也可类似用此方法。
好了,最后一个问题<当你往sd卡中添加一些音频文件的时候,android没有自动及时将它刷新到数据库中。那么我们怎么让它手动刷新呢,如下:
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED); intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED); intentFilter.addDataScheme("file"); scanReceiver = new ScanSdFilesReceiver(); registerReceiver(scanReceiver, intentFilter); sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory()))); private class ScanSdFilesReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (Intent.ACTION_MEDIA_SCANNER_STARTED.equals(action)) { scanHandler.sendEmptyMessage(STARTED); } if (Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)) { scanHandler.sendEmptyMessage(FINISHED); } } } private Handler scanHandler = new Handler() { public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case STARTED: MyDialog scanDialog = new MyDialog(LocalList.this); scanAlertDialog = scanDialog.scanFile(); scanAlertDialog.show(); Log.i(TAG, "showing"); break; case FINISHED: ArrayList<Song> tempSongs = ReadFileList.readDataFromSD(LocalList.this, LOCAL); if (tempSongs != null && tempSongs.size()>0) { if (songs != null && songs.size()>0) { songs.clear(); songs.addAll(tempSongs); songAdapter.notifyDataSetChanged(); }else { songs = new ArrayList<Song>(); songs.addAll(tempSongs); initSong_lv(); } }else { Toast.makeText(LocalList.this, "SD卡中没有歌曲,请添加后再扫描", Toast.LENGTH_SHORT).show(); } Log.i(TAG, "finish"); if (scanAlertDialog!=null && scanAlertDialog.isShowing()) { scanAlertDialog.dismiss(); } unregisterReceiver(scanReceiver); break; case DISMISS: Log.i(TAG, "dismiss"); if (scanAlertDialog!=null && scanAlertDialog.isShowing()) { scanAlertDialog.dismiss(); } default: break; }
对于其他类型的文件,只要com.android.providers中有这种文件信息数据库,扫描SD卡内所有这种类型文件也可以同样这么做。