Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android開發獲得多媒體信息

Android開發獲得多媒體信息

編輯:Android開發實例

  通過調用Android的API,可以實現相冊,播放器,錄音和攝像等功能。這一章需要掌握如下功能:
多媒體的ContentProvider的調用
Camera
AudioRecord和AudioTrack
MediaPlayer

  1.1  獲取多媒體信息
多媒體信息?在pc中的音樂播放器總是很容易的顯示歌手名、歌曲名、專輯名、年代。在Android中應該如何獲取這些信息呢?

  1.1.1  查看多媒體ContentProvider
前面我們學習了ContentProvider來保存和檢索數據,Android為常用的數據類型(如:音視頻、圖片和聯系方式等)提供了大量的ContentProvider,它們被定義在android.provider包下。那麼我們如何獲取多媒體的ContentProvider呢。

  (1)在Eclipse中添加Android自帶的FileExplorer視圖:
菜單欄->window->show view->other->Android->FileExplorer
(2)開啟模擬器,在FileExplorer中查看data/data/com.android.providers.media/databases/

  (3)將external.db文件 pull到pc上,用sqlite工具(可以使用火狐插件SQliteManager)查看:

 

  (4)查看表結構:
audio_meta:管理sd卡中的音頻資源。

  video:管理sd卡中的視頻資源。

  images:管理sd卡中的圖片。

  可能大家看到這裡會不明白為什麼講多媒體先要介紹這些。筆者這裡給大家列舉一個音樂播放器的需求:
1)      獲得音樂文件列表及路徑
2)      獲得音樂文件屬性(歌曲名、歌手名、專輯、年代。。)
3)      手動刪除內存卡中音樂文件,如何能同步更新文件列表

  如果是沒有Android經驗,大家可能會這樣分析:
文件路徑嘛,我調用file.listFile()就可以得到音樂文件列表。如果內存卡裡有很多文件,那麼這個將會特別的耗時,如果讓用戶等上10秒去掃描存儲卡,用戶很有可能將你的應用卸載掉。
音樂文件屬性一般保存在音樂文件中,有的放在文件頭,有的放在文件尾,必須讀出該文件相關字節中的內容才可以獲取音樂文件信息。OK,有個開源的項目,可以解析MP3文件中的文件信息。但是它同樣也是耗時的操作。而且學會調用這個開源項目還需要一周的時間。
在文件管理器中手動刪除或添加一個音樂文件,這個時候如何把它更新到音樂列表中呢,當你選擇一首歌播放的時候,很有可能已經被刪掉了。總不能讓它時刻去調用file.listFile()去維護吧?

  那麼我們到底應該怎麼做呢?你要始終相信Android是強大的,它早已為我們提供了這些功能,我們只需要調用Android提供的API,就可以解決上述的需求。
現在我們先看個圖,圖1.6為模擬器開機時,在log中打印的日志。

 

 

  開機時的log

  大家會看到,系統會調用MediaScanner去掃描Internal和External Volume。原來,在開機時,系統會在後台掃描內存和外存設備,將多媒體數據更新到數據庫中。同時也會掃描文件信息,這樣,我們不費吹灰之力就解決了問題。
小插曲:之前由於筆者還不知道這個方法,在摸索中讓同事去研究解析MP3文件信息,花了他一個星期時間,當他做出來了,我花了十分鐘找到了這個方法。真是罪過罪過。

  那麼我們如何得到多媒體數據呢,請看下面的例子:

  /**
      * 讀取sd卡中的音樂文件
      * @return
      * @throws Exception
      */
     public static ArrayList<Song> readDataFromSD(Context context,int component){
//       Log.i(TAG, "scanFile");
         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);
         ArrayList<Song> songs = null;
         if (cursor.moveToFirst()) {
              songs = SongInfoUtil.getList(cursor, context, component);
         }
         return songs;
     }

  /**
 * @author stayzhang 封裝信息至Song
 */
public class SongInfoUtil {
//   private static final String TAG = "ListUtils";
     public static ArrayList<Song> getList(Cursor cursor, Context mContext, int component) {
         Song song = null;
         do {
//            Log.i(TAG, "getList");
              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 temp = cursor.getInt(8) / 1024f / 1024f;
                   String sizeStr = (temp + "").substring(0, 4);
                   song.setSize(sizeStr + "M");
              } else {
                   song.setSize("未知");
              }
              if (cursor.getString(9) != null) {//文件路徑
                   song.setFileUrl(cursor.getString(9));
              }
         } while (cursor.moveToNext());
         cursor.close();
         return dbService.query(component, null, null);
     }
}

 

 

  同理,圖片還有視頻文件也可以這樣獲得,不再贅述。
這樣第一個和第二個需求我們已經解決,那第三個需求呢。
當我們手動的刪除或添加多媒體文件到存儲卡中時,Android會自動掃描這些文件並將其更新到數據庫嗎?
答案是不會,那麼我們如何將數據實時更新到數據庫中呢。還記得logcat中打印出來的MediaScanner嗎?我們也可以調用MediaScanner這個類去掃描存儲卡。但是不能直接調用這個類,只能以廣播的形式通知系統,讓系統去掃描存儲卡指定的URI,掃描完後,再通過ContentProvider查詢數據庫。
方法如下:

  /**
          * 調用系統api掃描sd卡
          */
         private void scanSdCard() {
                   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://" + getExternalStorageDirectory().getAbsolutePath)));
         }
  
         /**
          * @author stayzhang 注冊掃描開始/完成的廣播
          */
         private class ScanSdFilesReceiver extends BroadcastReceiver {
                   public void onReceive(Context context, Intent intent) {
                            String action = intent.getAction();
                            if (Intent.ACTION_MEDIA_SCANNER_STARTED.equals(action)) {
//當系統開始掃描sd卡時,為了用戶體驗,可以加上一個等待框
                                     scanHandler.sendEmptyMessage(STARTED);
                            }
                            if (Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)) {
                            //當系統掃描完畢時,停止顯示等待框,並重新查詢ContentProvider
                                     scanHandler.sendEmptyMessage(FINISHED);
                            }
                   }
         }

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved