OPhone程序開發入門之音樂播放器
OPhone平台提供了完整的多媒體解決方案。為開發者提供了統一的,簡單易用的開發接口。本文首先介紹了OPhone平台的多媒體框架,然後詳細介紹了 在OPhone平台上開發音樂播放程序所需的基本知識。通過一步一步構建一個簡單的音樂播放器示例程序,來幫助讀者了解具體的開發過程。該示例涵蓋了Application,Activity,Service,Intent,BroadCast Receiver等基本概念,使讀者對OPhone程序的開發有一個全麵的了解,進一步鞏固和熟悉這些基本概念。最後介紹了如何利用MAT工具分析OPhone 程序。本文適合OPhone平台開發的初學者閱讀。(作者:CMRI 孟釗)
OPhone平台的多媒體架構
在開始構建我們的示例程序前,先讓我們大概了解一下OPhone平台的多媒體框架。
圖 一
圖一是OPhone平台的整體框架結構,從圖上我們可以看出OPhone平台大致可以分成以下幾個層次:
- 最上層是Application層。它包含了主屏,電話,瀏覽器,地址本等核心的應用程序。我們將開發的音樂播放器也屬於這一層。
- 第二層是Application Framework層。這一層為開發者提供了完整的編程接口。多媒體部分提供了MediaPlayer, MediaRecorder等接口。同時MediaProvider,MediaScanner等係統服務也對媒體文件的管理提供了支持。本文將重點介紹 它們的使用。
- 第三層是Library層, 它由一係列的c/c++庫組成,這些庫的能力通過JNI封裝成java接口,由Application Framework層提供給開發者。多媒體係統庫OpenCore,它是OPhone多媒體的核心,來源於PacketVideo。它非常複雜,提供了完 整的多媒體解決方案。
- 最底層為Linux Kernel和驅動,負責與硬件的數據交互等。
圖二說明了在OPhone平台中播放音樂文件時的調用關係。
對於應用程序開發者來說,需要重點學習和關注的是如何使用Appliation Framework層提供給開發者的接口。
音樂媒體信息的管理
在開始構架程序之前,我們需要準備一下必須的基本知識。首先來了解一下在OPhone平台中應該如何獲取音樂文件的信息以及如何管理這些信息。
OPhone係統提供了MediaScanner,MediaProvider,MediaStore等接口,並且提供了一套數據庫表格,通過Content Provider的方式提供給用戶。當手機開機或者有SD卡插拔等事件發生時,係統將會自動掃描SD卡和手機內存上的媒體文件,如audio,video,圖片等,將相應的信息放到定義好的數據庫表格中。在這個程序中,我們不需要關心如何去掃描手機中的文件,隻要了解如何查詢和使用 這些信息就可以了。
MediaStore中定義了一係列的數據表格,通過ContentResolver提供的查詢接口,我們可以得到各種需要的信息。下麵我們重點介紹如何管理SD卡上的音樂文件信息。
先來了解一下ContentResolver的查詢接口:
- Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
- Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
Uri:指明要查詢的數據庫名稱加上表的名稱,從MediaStore中我們可以找到相應信息的參數,具體請參考開發文檔。
Projection: 指定查詢數據庫表中的哪幾列,返回的遊標中將包括相應的信息。Null則返回所有信息。
selection: 指定查詢條件
selectionArgs:參數selection裏有 ?這個符號是,這裏可以以實際值代替這個問號。如果selection這個沒有?的話,那麼這個String數組可以為null。
SortOrder:指定查詢結果的排列順序
查詢所有歌曲:
- Cursor cursor = query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,
- null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
- Cursor cursor = query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,
- null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
Cursor cursor = query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
該命令將返回所有在外部存儲卡上的音樂文件的信息,其中常用的信息如下:
- MediaStore.Audio.Media._ID:歌曲ID
- Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
- MediaStore.Audio.Media.TITLE:歌曲的名稱
- String tilte = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
- MediaStore.Audio.Media.ALBUM :歌曲的專輯名
- String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
- MediaStore.Audio.Media.ARTIST:歌曲的歌手名
- String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
- MediaStore.Audio.Media.DATA:歌曲文件的路徑
- String url = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
- MediaStore.Audio.Media.DURATION:歌曲的總播放時長
- Int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));
- MediaStore.Audio.Media.SIZE: 歌曲文件的大小
- Int size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));
- MediaStore.Audio.Media._ID:歌曲ID
- Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
- MediaStore.Audio.Media.TITLE:歌曲的名稱
- String tilte = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
- MediaStore.Audio.Media.ALBUM :歌曲的專輯名
- String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
- MediaStore.Audio.Media.ARTIST:歌曲的歌手名
- String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
- MediaStore.Audio.Media.DATA:歌曲文件的路徑
- String url = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
- MediaStore.Audio.Media.DURATION:歌曲的總播放時長
- Int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));
- MediaStore.Audio.Media.SIZE: 歌曲文件的大小
- Int size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));
MediaStore.Audio.Media._ID:歌曲ID Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)); MediaStore.Audio.Media.TITLE:歌曲的名稱 String tilte = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)); MediaStore.Audio.Media.ALBUM :歌曲的專輯名 String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM)); MediaStore.Audio.Media.ARTIST:歌曲的歌手名 String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST)); MediaStore.Audio.Media.DATA:歌曲文件的路徑 String url = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)); MediaStore.Audio.Media.DURATION:歌曲的總播放時長 Int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION)); MediaStore.Audio.Media.SIZE: 歌曲文件的大小 Int size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));
查詢歌手信息:
- Cursor cursor = query(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, null, null, null,
- MediaStore.Audio.Artists.DEFAULT_SORT_ORDER);
- Cursor cursor = query(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, null, null, null,
- MediaStore.Audio.Artists.DEFAULT_SORT_ORDER);
Cursor cursor = query(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Artists.DEFAULT_SORT_ORDER);
該命令將返回所有在外部存儲卡上的歌手信息,其中常用的信息如下:
- MediaStore.Audio.Artists._ID:歌手id
- Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists._ID));
- MediaStore.Audio.Artists.ARTIST :歌手姓名
- String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST));
- MediaStore.Audio.Artists.NUMBER_OF_ALBUMS: 共有多少該歌手的專輯
- Int numOfAlbum = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.NUMBER_OF_ALBUMS));
- MediaStore.Audio.Artists.NUMBER_OF_TRACKS: 共有多少該歌手的歌曲
- Int numOfSong = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.NUMBER_OF_TRACKS));
- MediaStore.Audio.Artists._ID:歌手id
- Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists._ID));
- MediaStore.Audio.Artists.ARTIST :歌手姓名
- String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST));
- MediaStore.Audio.Artists.NUMBER_OF_ALBUMS: 共有多少該歌手的專輯
- Int numOfAlbum = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.NUMBER_OF_ALBUMS));
- MediaStore.Audio.Artists.NUMBER_OF_TRACKS: 共有多少該歌手的歌曲
- Int numOfSong = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.NUMBER_OF_TRACKS));
MediaStore.Audio.Artists._ID:歌手id Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists._ID)); MediaStore.Audio.Artists.ARTIST :歌手姓名 String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST)); MediaStore.Audio.Artists.NUMBER_OF_ALBUMS: 共有多少該歌手的專輯 Int numOfAlbum = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.NUMBER_OF_ALBUMS)); MediaStore.Audio.Artists.NUMBER_OF_TRACKS: 共有多少該歌手的歌曲 Int numOfSong = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.NUMBER_OF_TRACKS));
查詢專輯信息:
- Cursor cursor = query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, null, null,null,
- MediaStore.Audio.Albums.DEFAULT_SORT_ORDER);
- Cursor cursor = query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, null, null,null,
- MediaStore.Audio.Albums.DEFAULT_SORT_ORDER);
Cursor cursor = query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, null, null,null, MediaStore.Audio.Albums.DEFAULT_SORT_ORDER);
該命令將返回所有在外部存儲卡上的專輯信息,其中常用的信息如下:
- MediaStore.Audio.Albums._ID :專輯id
- Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums._ID));
- MediaStore.Audio.Albums.ALBUM:專輯名稱
- String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM));
- MediaStore.Audio.Albums.NUMBER_OF_SONGS:共用多少歌曲屬於該專輯
- Int numOfSong = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.NUMBER_OF_SONGS));
- MediaStore.Audio.Albums._ID :專輯id
- Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums._ID));
- MediaStore.Audio.Albums.ALBUM:專輯名稱
- String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM));
- MediaStore.Audio.Albums.NUMBER_OF_SONGS:共用多少歌曲屬於該專輯
- Int numOfSong = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.NUMBER_OF_SONGS));
MediaStore.Audio.Albums._ID :專輯id Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums._ID)); MediaStore.Audio.Albums.ALBUM:專輯名稱 String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM)); MediaStore.Audio.Albums.NUMBER_OF_SONGS:共用多少歌曲屬於該專輯 Int numOfSong = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.NUMBER_OF_SONGS));
查詢播放列表
- Cursor cursor = query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, null, null, null,
- MediaStore.Audio.Playlists.DATE_ADDED + " asc");
- Cursor cursor = query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, null, null, null,
- MediaStore.Audio.Playlists.DATE_ADDED + " asc");
Cursor cursor = query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Playlists.DATE_ADDED + " asc");
該命令將返回所有在外部存儲卡上的專輯信息,其中常用的信息如下:
- MediaStore.Audio.Playlists._ID :播放列表id
- Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists._ID));
- MediaStore.Audio.Playlists.NAME:播放列表名稱
- String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.NAME));
- MediaStore.Audio.Playlists.DATE_ADDED :添加時間
- long dateAdded = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.DATE_ADDED));
- MediaStore.Audio.Playlists.DATE_MODIFIED :修改時間
- long dateModified = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.DATE_MODIFIED));
- MediaStore.Audio.Playlists._ID :播放列表id
- Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists._ID));
- MediaStore.Audio.Playlists.NAME:播放列表名稱
- String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.NAME));
- MediaStore.Audio.Playlists.DATE_ADDED :添加時間
- long dateAdded = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.DATE_ADDED));
- MediaStore.Audio.Playlists.DATE_MODIFIED :修改時間
- long dateModified = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.DATE_MODIFIED));
MediaStore.Audio.Playlists._ID :播放列表id Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists._ID)); MediaStore.Audio.Playlists.NAME:播放列表名稱 String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.NAME)); MediaStore.Audio.Playlists.DATE_ADDED :添加時間 long dateAdded = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.DATE_ADDED)); MediaStore.Audio.Playlists.DATE_MODIFIED :修改時間 long dateModified = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.DATE_MODIFIED));
通過組合這些查詢結果,指定查詢條件,用戶可以很方便的查詢指定的媒體信息,比如:查詢屬於指定歌手(歌手id 為 aid)的歌曲:
- query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,
- MediaStore.Audio.Media.ARTIST_ID + "=" + aid, null,
- MediaStore.Audio.Media.TITLE);
- query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,
- MediaStore.Audio.Media.ARTIST_ID + "=" + aid, null,
- MediaStore.Audio.Media.TITLE);
query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Audio.Media.ARTIST_ID + "=" + aid, null, MediaStore.Audio.Media.TITLE);
查詢屬於指定專輯(專輯id 為 aid)的歌曲:
- return query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,
- MediaStore.Audio.Media.ALBUM_ID + "=" + aid, null,
- MediaStore.Audio.Media.TITLE);
- return query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,
- MediaStore.Audio.Media.ALBUM_ID + "=" + aid, null,
- MediaStore.Audio.Media.TITLE);
return query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Audio.Media.ALBUM_ID + "=" + aid, null, MediaStore.Audio.Media.TITLE);
以上我們重點介紹了音樂媒體信息的查詢方法,對於媒體信息的增刪改等操作主要集中在對播放列表的管理上,也是通過Content Resolver的insert,update,delete等接口來實現的。隻要搞清楚了各個參數的含義,相應URI以及各個字段的義,很容易實現。由 於篇幅原因,我們不再詳細介紹,有興趣的朋友可以查看OPhone開發文檔。
音樂播放
音樂文件的播放功能是由MediaPlayer類實現的,MediaPlayer提供了常用的接口,比如播放,暫停,停止,快速定位等。
播放音樂文件的基本調用流程:
- 生成MediaPlayer實例。
- 設置播放源(文件)
- 準備播放
- 開始播放
- MediaPlayer mp = new MediaPlayer();
- mp.setDataSource(file_to_play);
- mp.prepare();
- mp.start();
- MediaPlayer mp = new MediaPlayer();
- mp.setDataSource(file_to_play);
- mp.prepare();
- mp.start();
MediaPlayer mp = new MediaPlayer(); mp.setDataSource(file_to_play); mp.prepare(); mp.start();
以上代碼即可以完成最簡單的音樂播放功能。
除了MediaPlayer類,我們還需要注意幾個播放器件Listener的使用,它們提供了播放器的更多的狀態信息。
1.MediaPlayer.OnBufferingUpdateListener
當播放網絡上的媒體文件或者流媒體時 MediaPlayer.OnBufferingUpdateListener 的onBufferingUpdate(MediaPlayer mp, int percent)接口函數會被回調,通知當前的緩衝進度信息。
通過setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener) 函數來注冊該Listener
2.MediaPlayer.OnCompletionListener
當前歌曲播放結束後,MediaPlayer.OnCompletionListener的 onCompletion(MediaPlayer mp) 接口會被回調,通知歌曲結束事件。
通過setOnCompletionListener(MediaPlayer.OnCompletionListener listener) 函數來注冊該監聽器
3.MediaPlayer.OnErrorListener
當由於某種原因,MediaPlayer進入錯誤狀態時,MediaPlayer.OnBufferingUpdateListener的onError(MediaPlayer mp, int what, int extra)接口會被回調,通知錯誤信息。此時MediaPlayer 應該調用reset()函數,將MediaPlayer重新置於idle狀態。如果發生無法回複的錯誤,需要重新獲取MediaPlayer的實例。
4.MediaPlayer.OnPreparedListener
當播放網絡媒體文件或流媒體時,播放器的準備時間較長,播放器準備完畢可以開始播放時,MediaPlayer.OnPreparedListener的onPrepared(MediaPlayer mp)接口會被回調,通知該信息。
當播放器需要支持播放流媒體或者網絡媒體文件時,建議使用prepareAsync()接口調用來準備播放器,同時通過MediaPlayer.OnPreparedListener來監聽prepared信息。這樣可以避免因為網絡等因素造成的MediaPlayer準 備時間過長進而導致程序長時間無響應。
構建音樂播放器程序
在學習了媒體信息管理和媒體播放的基本內容後,我們現在可以開始動手構建我們的簡單播放器示例程序了。
一.創建工程
在Eclipse開發環境中創建一個新的Android Project.
File > New > Android Project.
設置工程名為MusicPlayerDemo, 設置packages名為 com.ophone
二.指定程序的Application,添加MusicPlayerDemoApp
添加MusicPlayerDemoApp類,它繼承自 android.app.Application。
Application類用來存儲程序的狀態,它存在於整個程序的生命周期之中。
修改AndroidManifest.xml如下,指定MusicPlayerDemoApp為示例程序的Application.
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="https://schemas.android.com/apk/res/android"
- package="com.ophone"
- android:versionCode="1"
- android:versionName="1.0">
- <application android:name="MusicPlayerDemoApp"
- android:icon="@drawable/icon"
- android:label="@string/app_name">
- </application>
- </manifest>
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="https://schemas.android.com/apk/res/android"
- package="com.ophone"
- android:versionCode="1"
- android:versionName="1.0">
- <application android:name="MusicPlayerDemoApp"
- android:icon="@drawable/icon"
- android:label="@string/app_name">
- </application>
- </manifest>
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:andro package="com.ophone" android:versionCode="1" android:versionName="1.0"> <application android:name="MusicPlayerDemoApp" android:icon="@drawable/icon" android:label="@string/app_name"> </application> </manifest>
我們需要注意Application的兩個函數: onCreate() 和 onTerminate(). 當程序開始運行時,onCreate()函數會首先被調用,此時沒有任何其他的對象在運行,在這裏我們可以進行一些初始化的工作。當程序結束時, onTerminate()函數會被調用,程序進程將會退出,我們可以在此做一些最終的清理工作。需要注意的是,當因為係統資源緊張等問題,程序被係統kill的時候,onTerminate()不會被調用到,程序將直接退出。
稍後我們再來修改MusicPlayerDemoApp,先往下繼續。
三.管理音樂信息的類MusicDBController
為了使接口整潔,便於管理和使用,我們將在第三章介紹的 查詢管理音樂信息的方法統一封裝在MusicDBController類中。
- public static MusicDBController getInstance(MusicPlayerDemoApp app) {
- if(sInstance == null) {
- sInstance = new MusicDBController(app);
- }
- return sInstance;
- }
- private MusicDBController(MusicPlayerDemoApp app) {
- mApp = app;
- }
- private Cursor query(Uri _uri, String[] prjs, String selections,
- String[] selectArgs, String order) {
- ContentResolver resolver = mApp.getContentResolver();
- if (resolver == null) {
- return null;
- }
- return resolver.query(_uri, prjs, selections, selectArgs,
- order);
- public static MusicDBController getInstance(MusicPlayerDemoApp app) {
- if(sInstance == null) {
- sInstance = new MusicDBController(app);
- }
- return sInstance;
- }
- private MusicDBController(MusicPlayerDemoApp app) {
- mApp = app;
- }
- private Cursor query(Uri _uri, String[] prjs, String selections,
- String[] selectArgs, String order) {
- ContentResolver resolver = mApp.getContentResolver();
- if (resolver == null) {
- return null;
- }
- return resolver.query(_uri, prjs, selections, selectArgs,
- order);
public static MusicDBController getInstance(MusicPlayerDemoApp app) { if(sInstance == null) { sInstance = new MusicDBController(app); } return sInstance; } private MusicDBController(MusicPlayerDemoApp app) { mApp = app; } private Cursor query(Uri _uri, String[] prjs, String selections, String[] selectArgs, String order) { ContentResolver resolver = mApp.getContentResolver(); if (resolver == null) { return null; } return resolver.query(_uri, prjs, selections, selectArgs, order);
MusicDBController采用單例模式,使程序中隻有唯一的實例。我們傳入MusicPlayerDemoApp 作為Context生成Content Resolver,用來查詢媒體庫。
現在,我們修改MusicPlayerDemoApp,添加一個MusicDBController的成員,並在onCreate()中初始化它。
- private MusicDBController mDBContorller = null;
- public void onCreate() {
- // TODO Auto-generated method stub
- super.onCreate();
- // init MusicDBController
- mDBContorller = MusicDBController.getInstance(this);
- }
- 並且提供一個獲取MusicDBController的接口:
- public MusicDBController getMusicDBController(){
- return mDBContorller;
- private MusicDBController mDBContorller = null;
- public void onCreate() {
- // TODO Auto-generated method stub
- super.onCreate();
- // init MusicDBController
- mDBContorller = MusicDBController.getInstance(this);
- }
- 並且提供一個獲取MusicDBController的接口:
- public MusicDBController getMusicDBController(){
- return mDBContorller;
private MusicDBController mDBContorller = null; public void onCreate() { // TODO Auto-generated method stub super.onCreate(); // init MusicDBController mDBContorller = MusicDBController.getInstance(this); } 並且提供一個獲取MusicDBController的接口: public MusicDBController getMusicDBController(){ return mDBContorller;
這樣程序中的任何Activity和Serivce都可以通過getApplicatio()函數得到MusicPlayerDemoApp, 再通過getMusicDBController()接口獲取MusicDBController,進而獲取所需要的媒體信息。
四.展示媒體庫-MusicListActivity 和 MusicListAdapter。
首先添加MusicListAdapter,它繼承自SimpleCursorAdapter。通過重載bindView()函數, 把媒體庫信息綁定到指定的ListView上。
我們使用android.R.layout.cmcc_list_5作為ListView的layout,它的布局定義如下:
android.R.layout.cmcc_list_5:
android.R.id.listicon1 圖片
android.R.id.text1 左上文字
android.R.id.text2 左下文字
android.R.id.text3 右下文字
- public void bindView(View view, Context context, Cursor cursor) {
- super.bindView(view, context, cursor);
- TextView titleView = (TextView) view.findViewById(android.R.id.text1);
- TextView artistView = (TextView) view.findViewById(android.R.id.text2);
- TextView durationView = (TextView) view.findViewById(android.R.id.text3);
- ImageView imageView = (ImageView) view.findViewById(android.R.id.listicon1);
- // Set icon
- imageView.setImageResource(R.drawable.cmcc_list_music);
- // Set track name
- titleView.setText(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)));
- // Set artist name
- artistView.setText(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST)));
- // Set duration
- int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));
- durationView.setText(makeTimeString(duration));
- }
- public void bindView(View view, Context context, Cursor cursor) {
- super.bindView(view, context, cursor);
- TextView titleView = (TextView) view.findViewById(android.R.id.text1);
- TextView artistView = (TextView) view.findViewById(android.R.id.text2);
- TextView durationView = (TextView) view.findViewById(android.R.id.text3);
- ImageView imageView = (ImageView) view.findViewById(android.R.id.listicon1);
- // Set icon
- imageView.setImageResource(R.drawable.cmcc_list_music);
- // Set track name
- titleView.setText(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)));
- // Set artist name
- artistView.setText(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST)));
- // Set duration
- int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));
- durationView.setText(makeTimeString(duration));
- }
public void bindView(View view, Context context, Cursor cursor) { super.bindView(view, context, cursor); TextView titleView = (TextView) view.findViewById(android.R.id.text1); TextView artistView = (TextView) view.findViewById(android.R.id.text2); TextView durationView = (TextView) view.findViewById(android.R.id.text3); ImageView imageView = (ImageView) view.findViewById(android.R.id.listicon1); // Set icon imageView.setImageResource(R.drawable.cmcc_list_music); // Set track name titleView.setText(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE))); // Set artist name artistView.setText(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST))); // Set duration int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION)); durationView.setText(makeTimeString(duration)); }
注意,上麵這段代碼中的android.R.id.text1,android.R.id.text2,android.R.id.text3 和 android.R.id.listicon1是在我們傳入中的ListView(android.R.layout.cmcc_list_5)的layout中定義的。如果你使用了自己定義的layout,請把它們替換成你自己定義的widget id。
現在可以來添加我們的第一個Activity -MusicListActivity,它以List的形式展示了所有歌曲。MusicListActivity繼承自ListActivity。
在onCreate()中獲取MusicDBController的實例,為獲取歌曲信息做準備。
- private MusicDBController mDBController = null;
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mDBController = ((MusicPlayerDemoApp)getApplication()).getMusicDBController();
- }
- 通過MusicListAdapter,我們將從MusicDBController中拿到的媒體庫信息,綁定到ListView,我們在onResume()完成這個工作。
- protected void onResume() {
- super.onResume();
- mCursor = mDBController.getAllSongs();
- MusicListAdapter adapter = new MusicListAdapter(this, android.R.layout.cmcc_list_5, mCursor, new String[]{}, new int[]{});
- setListAdapter(adapter);
- }
- 將MusicListActivity添加到AndroidManifest.xml中
- <activity android:name=".MusicListActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- private MusicDBController mDBController = null;
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mDBController = ((MusicPlayerDemoApp)getApplication()).getMusicDBController();
- }
- 通過MusicListAdapter,我們將從MusicDBController中拿到的媒體庫信息,綁定到ListView,我們在onResume()完成這個工作。
- protected void onResume() {
- super.onResume();
- mCursor = mDBController.getAllSongs();
- MusicListAdapter adapter = new MusicListAdapter(this, android.R.layout.cmcc_list_5, mCursor, new String[]{}, new int[]{});
- setListAdapter(adapter);
- }
- 將MusicListActivity添加到AndroidManifest.xml中
- <activity android:name=".MusicListActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
private MusicDBController mDBController = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mDBController = ((MusicPlayerDemoApp)getApplication()).getMusicDBController(); } 通過MusicListAdapter,我們將從MusicDBController中拿到的媒體庫信息,綁定到ListView,我們在onResume()完成這個工作。 protected void onResume() { super.onResume(); mCursor = mDBController.getAllSongs(); MusicListAdapter adapter = new MusicListAdapter(this, android.R.layout.cmcc_list_5, mCursor, new String[]{}, new int[]{}); setListAdapter(adapter); } 將MusicListActivity添加到AndroidManifest.xml中 <activity android:name=".MusicListActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
現在運行一下我們的程序,它已經可以展現給你媒體庫的音樂列表了。
同樣的,仿照上麵的過程,我們還可以添加展示專輯列表,藝術家列表等等Activity,我們就不再一一介紹了。
五.後台播放-使用Service
現在我們需要考慮如何來播放這些媒體庫中的文件了。我們希望當用戶退出這個程序界麵後,我們的程序仍然能夠繼續播放歌曲,比如用戶在讀郵件時,可以聽聽音 樂。為了達到後台播放的效果,需要使用Service。當程序的所有Activity都退出後,Service仍然可以在後台運行。在這個示例中我們使用Local Service,它與應用程序運行在同一個進程中。(我們甚至可以不使用bind service就直接獲得它的句柄,調用它所提供的函數。)
首先,創建一個MusicPlaybackService類,它繼承自android.app.Service,重載onBind方法,返回自 定義的LocalBinder,通過LocalBinder的getService()方法就可以獲得MusicPlaybackService的句柄 了。
- private final IBinder mBinder = new LocalBinder();
- public class LocalBinder extends Binder {
- public MusicPlaybackService getService() {
- return MusicPlaybackService.this;
- }
- }
- @Override
- public IBinder onBind(Intent intent) {
- // TODO Auto-generated method stub
- return mBinder;
- }
- private final IBinder mBinder = new LocalBinder();
- public class LocalBinder extends Binder {
- public MusicPlaybackService getService() {
- return MusicPlaybackService.this;
- }
- }
- @Override
- public IBinder onBind(Intent intent) {
- // TODO Auto-generated method stub
- return mBinder;
- }
private final IBinder mBinder = new LocalBinder(); public class LocalBinder extends Binder { public MusicPlaybackService getService() { return MusicPlaybackService.this; } } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return mBinder; }
我們繼續完成MusicPlaybackService的基本構架,添加一個MediaPlayer成員,並在onCreate()函數中對其進行初始化,它將負責音樂播放的主要功能。
- private MediaPlayer mMediaPlayer = null;
- public void onCreate() {
- super.onCreate();
- mMediaPlayer = new MediaPlayer();
- }
- private MediaPlayer mMediaPlayer = null;
- public void onCreate() {
- super.onCreate();
- mMediaPlayer = new MediaPlayer();
- }
private MediaPlayer mMediaPlayer = null; public void onCreate() { super.onCreate(); mMediaPlayer = new MediaPlayer(); }
構架完成MusicPlaybackService的基本架構後,我們要定義一些常用的控製接口了,其他模塊通過這些接口,可以控製音樂的播放,暫停,停止等功能。
- public<
最後更新:2017-04-02 06:52:25
上一篇:
J2EE空鏈接a標簽的處理方法
下一篇:
linq to xml之增改刪查