【Android開發經驗】如何擷取媒體庫中所有音頻檔案資訊,並在檔案增刪後及時更新媒體庫

來源:互聯網
上載者:User

標籤:

轉載請註明出處: http://blog.csdn.net/zhaokaiqiang1992

今天一開啟部落格,發現一位朋友給我發了一封私信,請教下面的問題,所以特寫此文章,為其解惑。

從這位朋友的提問中,我們需要瞭解下面的這些問題,才能給他很好的解答:

(1)如何擷取手機裡所有歌曲的資訊?

(2)在歌曲檔案發生改變,比如增刪操作之後,如何及時的更新媒體庫,從而擷取到最新的歌曲資訊?

(3)在4.4版本之後,掃描sd卡,更新媒體庫的操作發生變化了嗎?

下面,我將就以上三個問題,進行解答。

(1)如何擷取手機裡所有歌曲的資訊?

如果要解決這個問題,那麼我們首先要知道在Android系統中,是如何對歌曲資訊進行管理的。

在Android中,系統為多媒體類型的檔案(比片、音頻、視頻等)建立了資料庫(sqlite資料庫),從而完成多媒體資料的維護工作。我們當然可以不用這些系統的資料庫,比如說,如果我們想擷取所有歌曲,我們可以掃描sd上所有的檔案夾中的檔案,然後根據檔案的尾碼名,就可以取到我們想要的mp3、wma檔案等。但是,這樣的操作是非常效率低下的,所以是行不通的。

Android系統為我們建立起多媒體資料庫之後,便把多媒體常用的資訊,比如歌曲名、檔案大小、播放時間長度、專輯、歌手等常用資訊儲存在了資料庫裡,那我們可以直接用多媒體庫中的資料,完成這個需求。雖然我們需要用多媒體庫,但是我們不能直接操作。Android為這些常用的需要共用的資料(多媒體和連絡人等),建立了ContentProvider,因此,如果我們想擷取到這些資訊,我們就需要用ContentProvider。

在開始介紹之前,先給出需要用到的歌曲的實體類

/** *  * @ClassName: com.example.mediastore.Song * @Description: 歌曲實體類 * @author zhaokaiqiang * @date 2014-12-4 上午11:49:59 *  */public class Song {  private String fileName;  private String title;  private int duration;  private String singer;  private String album;  private String year;  private String type;  private String size;  private String fileUrl;  public String getFileName() {    return fileName;  }  public void setFileName(String fileName) {    this.fileName = fileName;  }  public String getTitle() {    return title;  }  public void setTitle(String title) {    this.title = title;  }  public int getDuration() {    return duration;  }  public void setDuration(int duration) {    this.duration = duration;  }  public String getSinger() {    return singer;  }  public void setSinger(String singer) {    this.singer = singer;  }  public String getAlbum() {    return album;  }  public void setAlbum(String album) {    this.album = album;  }  public String getYear() {    return year;  }  public void setYear(String year) {    this.year = year;  }  public String getType() {    return type;  }  public void setType(String type) {    this.type = type;  }  public String getSize() {    return size;  }  public void setSize(String size) {    this.size = size;  }  public String getFileUrl() {    return fileUrl;  }  public void setFileUrl(String fileUrl) {    this.fileUrl = fileUrl;  }  public Song() {    super();  }  public Song(String fileName, String title, int duration, String singer,      String album, String year, String type, String size, String fileUrl) {    super();    this.fileName = fileName;    this.title = title;    this.duration = duration;    this.singer = singer;    this.album = album;    this.year = year;    this.type = type;    this.size = size;    this.fileUrl = fileUrl;  }  @Override  public String toString() {    return "Song [fileName=" + fileName + ", title=" + title        + ", duration=" + duration + ", singer=" + singer + ", album="        + album + ", year=" + year + ", type=" + type + ", size="        + size + ", fileUrl=" + fileUrl + "]";  }}

有了上面的這些資訊,我們完全可以做一個播放器了!

有了實體類之後,我封裝了一個類,專門用來擷取歌曲資訊,下面是實現的代碼

/** *  * @ClassName: com.example.mediastore.AudioUtils * @Description: 音頻檔案協助類 * @author zhaokaiqiang * @date 2014-12-4 上午11:39:45 *  */public class AudioUtils {  /**   * 擷取sd卡所有的音樂檔案   *    * @return   * @throws Exception   */  public static ArrayList<Song> getAllSongs(Context context) {    ArrayList<Song> songs = null;    Cursor cursor = context.getContentResolver().query(        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,        new String[] { MediaStore.Audio.Media._ID,            MediaStore.Audio.Media.DISPLAY_NAME,            MediaStore.Audio.Media.TITLE,            MediaStore.Audio.Media.DURATION,            MediaStore.Audio.Media.ARTIST,            MediaStore.Audio.Media.ALBUM,            MediaStore.Audio.Media.YEAR,            MediaStore.Audio.Media.MIME_TYPE,            MediaStore.Audio.Media.SIZE,            MediaStore.Audio.Media.DATA },        MediaStore.Audio.Media.MIME_TYPE + "=? or "            + MediaStore.Audio.Media.MIME_TYPE + "=?",        new String[] { "audio/mpeg", "audio/x-ms-wma" }, null);    songs = new ArrayList<Song>();    if (cursor.moveToFirst()) {      Song song = null;      do {        song = new Song();        // 檔案名稱        song.setFileName(cursor.getString(1));        // 歌曲名        song.setTitle(cursor.getString(2));        // 時間長度        song.setDuration(cursor.getInt(3));        // 歌手名        song.setSinger(cursor.getString(4));        // 專輯名        song.setAlbum(cursor.getString(5));        // 年代        if (cursor.getString(6) != null) {          song.setYear(cursor.getString(6));        } else {          song.setYear("未知");        }        // 歌曲格式        if ("audio/mpeg".equals(cursor.getString(7).trim())) {          song.setType("mp3");        } else if ("audio/x-ms-wma".equals(cursor.getString(7).trim())) {          song.setType("wma");        }        // 檔案大小        if (cursor.getString(8) != null) {          float size = cursor.getInt(8) / 1024f / 1024f;          song.setSize((size + "").substring(0, 4) + "M");        } else {          song.setSize("未知");        }        // 檔案路徑        if (cursor.getString(9) != null) {          song.setFileUrl(cursor.getString(9));        }        songs.add(song);      } while (cursor.moveToNext());      cursor.close();    }    return songs;  }}

代碼的思路很簡單,我們需要根據ContentResover擷取到一個Cursor,然後根據這個遊標,遍曆所有的歌曲的資訊。在上面的代碼中,我們查詢出了包括歌名、路徑、檔案大小等在內的共10項資料,對於一般的應用這些足夠了。查詢出來之後,我們把資訊轉換成了實體類,這樣操作起來更加方便。

如果要使用這個工具類,記得添加許可權 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

 

(2)如何及時更新媒體庫

Android系統重新整理媒體庫的資料的時機,是在開機的時候,即手機一開機,系統便重新掃描一下sd卡,並將多媒體資料庫更新一下。如果使用者刪除了某一個音頻檔案,不重新開機的話,資料庫中的資料是不會更新的。那麼,如果我們想使用者一開啟軟體,就強制的更新多媒體資料庫,應該怎麼做呢?

在4.4版本之前,我們可以使用發送廣播的方式,強制重新整理多媒體庫

IntentFilter intentFilter = new IntentFilter(        Intent.ACTION_MEDIA_SCANNER_STARTED);    intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);    intentFilter.addDataScheme("file");    sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,        Uri.parse("file://"            + Environment.getExternalStorageDirectory()                .getAbsolutePath())));

發送廣播之後,還需要註冊一個廣播接受者,來接受並處理掃描開始和結束事件

private class ScanReceiver extends BroadcastReceiver {    public void onReceive(Context context, Intent intent) {      String action = intent.getAction();      // 當系統開始掃描sd卡時,為了使用者體驗,可以加上一個等待框      if (Intent.ACTION_MEDIA_SCANNER_STARTED.equals(action)) {      }      // 當系統掃描完畢時,停止顯示等待框,並重新查詢ContentProvider      if (Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)) {      }    }  }

通過這種方式,我們便可以強制更新媒體庫。

但是,在4.4之後,Android對一些操作的許可權提高,如果在4.4的系統上使用這種方式,便會出現下面的錯誤

Caused by: java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.MEDIA_MOUNTED from pid=22360, uid=10163

這是因為在4.4之後,這個廣播只有系統應用才能發出,因此,我們不能使用這種方式了,我們可以使用下面的代碼實現相同的功能:

MediaScannerConnection.scanFile(this, new String[] { Environment        .getExternalStorageDirectory().getAbsolutePath() }, null, null);
使用MediaScannerConnection的scanFile方法,就可以強制掃描我們需要更新的檔案路徑,之後媒體資料庫也會同步更新,這樣,就不會出現檔案刪除,在媒體庫中卻能搜尋到的情況了,也能解決這位朋友提出的新增加歌曲的資訊擷取問題了。

 

【Android開發經驗】如何擷取媒體庫中所有音頻檔案資訊,並在檔案增刪後及時更新媒體庫(轉)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.