Android 扫描SD卡内所有MP3(音频)文件

    这段时间一个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);  
                }  
            }  
        }  
    }  
      
}
View Code

但是这样做,我们先扫描所有文件或目录,然后将其加入到我们自己的数据库里。由于遍历全部文件或目录效率很低,所以这种方法不可取,这里只是顺带提及一下这个可行的方法。

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;
    }
View Code

 

如果是获取音频文件其他属性也可类似用此方法。

 

好了,最后一个问题<当你往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; 
            } 
View Code

对于其他类型的文件,只要com.android.providers中有这种文件信息数据库,扫描SD卡内所有这种类型文件也可以同样这么做。

posted @ 2015-04-23 10:23  逍遥剑臣  阅读(3310)  评论(0编辑  收藏  举报