继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

通过MediaStore获取Audio信息

一只斗牛犬
关注TA
已关注
手记 493
粉丝 49
获赞 300

音乐媒体信息的管理

  在开始构架程序之前,我们需要准备一下必须的基本知识。首先来了解一下在OPhone平台中应该如何获取音乐文件的信息以及如何管理这些信息。

  OPhone系统提供了 MediaScanner,MediaProvider,MediaStore等接口,并且提供了一套数据库表格,通过Content Provider的方式提供给用户。当手机开机或者有SD卡插拔等事件发生时,系统将会自动扫描SD卡和手机内存上的媒体文件,如 audio,video,图片等,将相应的信息放到定义好的数据库表格中。在这个程序中,我们不需要关心如何去扫描手机中的文件,只要了解如何查询和使用 这些信息就可以了。

  MediaStore中定义了一系列的数据表格,通过ContentResolver提供的查询接口,我们可以得到各种需要的信息。下面我们重点介绍如何管理SD卡上的音乐文件信息。

  先来了解一下ContentResolver的查询接口:

view plain copy to clipboard print ?

  1. Cursor  query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);  

        Uri:指明要查询的数据库名称加上表的名称,从MediaStore中我们可以找到相应信息的参数,具体请参考开发文档。 
        Projection: 指定查询数据库表中的哪几列,返回的游标中将包括相应的信息。Null则返回所有信息。
        selection: 指定查询条件
        selectionArgs:参数selection里有 ?这个符号是,这里可以以实际值代替这个问号。如果selection这个没有?的话,那么这个String数组可以为null。
        SortOrder:指定查询结果的排列顺序

  查询所有歌曲:

view plain copy to clipboard print ?

  1. Cursor cursor = query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,  null ,  

  2.                 null ,  null , MediaStore.Audio.Media.DEFAULT_SORT_ORDER);  

5b911f080001981d01050060.jpg

  该命令将返回所有在外部存储卡上的音乐文件的信息,其中常用的信息如下:

view plain copy to clipboard print ?

  1. MediaStore.Audio.Media._ID:歌曲ID  

  2. Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));  

  3.   

  4. MediaStore.Audio.Media.TITLE:歌曲的名称  

  5. String tilte = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));  

  6.   

  7. MediaStore.Audio.Media.ALBUM :歌曲的专辑名  

  8. String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));  

  9.   

  10.   

  11. MediaStore.Audio.Media.ARTIST:歌曲的歌手名  

  12. String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));  

  13.   

  14. MediaStore.Audio.Media.DATA:歌曲文件的路径  

  15. String url = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));  

  16.   

  17. MediaStore.Audio.Media.DURATION:歌曲的总播放时长  

  18. Int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));  

  19.   

  20. MediaStore.Audio.Media.SIZE: 歌曲文件的大小  

  21. Int size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));  

5b911f080001981d01050060.jpg


        查询歌手信息:

view plain copy to clipboard print ?

  1. Cursor cursor = query(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,  null ,  null ,  null ,  

  2.  MediaStore.Audio.Artists.DEFAULT_SORT_ORDER);  

5b911f080001981d01050060.jpg

  该命令将返回所有在外部存储卡上的歌手信息,其中常用的信息如下:

view plain copy to clipboard print ?

  1. MediaStore.Audio.Artists._ID:歌手id  

  2. Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists._ID));  

  3.   

  4. MediaStore.Audio.Artists.ARTIST :歌手姓名  

  5. String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST));  

  6.   

  7. MediaStore.Audio.Artists.NUMBER_OF_ALBUMS: 共有多少该歌手的专辑  

  8. Int numOfAlbum = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.NUMBER_OF_ALBUMS));  

  9.   

  10. MediaStore.Audio.Artists.NUMBER_OF_TRACKS: 共有多少该歌手的歌曲  

  11. Int numOfSong = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.NUMBER_OF_TRACKS));  

  查询专辑信息:

view plain copy to clipboard print ?

  1. Cursor cursor = query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,  null ,  null , null ,  

  2.  MediaStore.Audio.Albums.DEFAULT_SORT_ORDER);  

    该命令将返回所有在外部存储卡上的专辑信息,其中常用的信息如下:

view plain copy to clipboard print ?

  1. MediaStore.Audio.Albums._ID :专辑id  

  2. Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums._ID));  

  3.   

  4. MediaStore.Audio.Albums.ALBUM:专辑名称  

  5. String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM));  

  6.   

  7. MediaStore.Audio.Albums.NUMBER_OF_SONGS:共用多少歌曲属于该专辑  

  8. Int numOfSong = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.NUMBER_OF_SONGS));  

5b911f080001981d01050060.jpg

  查询播放列表

view plain copy to clipboard print ?

  1. Cursor cursor = query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,  null ,  null ,  null ,  

  2.  MediaStore.Audio.Playlists.DATE_ADDED + " asc" );  

      该命令将返回所有在外部存储卡上的专辑信息,其中常用的信息如下:

view plain copy to clipboard print ?

  1. MediaStore.Audio.Playlists._ID :播放列表id  

  2. Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists._ID));  

  3.   

  4. MediaStore.Audio.Playlists.NAME:播放列表名称  

  5. String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.NAME));  

  6.   

  7. MediaStore.Audio.Playlists.DATE_ADDED :添加时间  

  8. long  dateAdded = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.DATE_ADDED));  

  9.   

  10. MediaStore.Audio.Playlists.DATE_MODIFIED :修改时间  

  11. long  dateModified = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.DATE_MODIFIED));  

5b911f080001981d01050060.jpg

      通过组合这些查询结果,指定查询条件,用户可以很方便的查询指定的媒体信息,比如:查询属于指定歌手(歌手id 为 aid)的歌曲:

view plain copy to clipboard print ?

  1. query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,  null ,  

  2.                 MediaStore.Audio.Media.ARTIST_ID + "="  + aid,  null ,  

  3.                 MediaStore.Audio.Media.TITLE);  

5b911f080001981d01050060.jpg


      查询属于指定专辑(专辑id 为 aid)的歌曲:

view plain copy to clipboard print ?

  1. return  query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,  null ,  

  2.                 MediaStore.Audio.Media.ALBUM_ID + "="  + aid,  null ,  

  3.                 MediaStore.Audio.Media.TITLE);  


      以上我们重点介绍了音乐媒体信息的查询方法,对于媒体信息的增删改等操作主要集中在对播放列表的管理上,也是通过Content Resolver的insert,update,delete等接口来实现的。只要搞清楚了各个参数的含义,相应URI以及各个字段的义,很容易实现。由 于篇幅原因,我们不再详细介绍,有兴趣的朋友可以查看OPhone开发文档。

音乐播放

  音乐文件的播放功能是由MediaPlayer类实现的,MediaPlayer提供了常用的接口,比如播放,暂停,停止,快速定位等。

       播放音乐文件的基本调用流程:

  1. 生成MediaPlayer实例。

  2. 设置播放源(文件)

  3. 准备播放

  4. 开始播放  

view plain copy to clipboard print ?

  1. MediaPlayer mp =  new  MediaPlayer();    

  2. mp.setDataSource(file_to_play);    

  3. mp.prepare();    

  4. mp.start();    

5b911f080001981d01050060.jpg

       以上代码即可以完成最简单的音乐播放功能。

       除了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.

view plain copy to clipboard print ?

  1. <?xml version= "1.0"  encoding= "utf-8" ?>  

  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"   

  3.       package = "com.ophone"   

  4.       android:versionCode="1"   

  5.       android:versionName="1.0" >  

  6.     <application android:name="MusicPlayerDemoApp"   

  7.      android:icon="@drawable/icon"    

  8.      android:label="@string/app_name" >  

  9.     </application>  

  10. </manifest>  

     我们需要注意Application的两个函数: onCreate() 和 onTerminate(). 当程序开始运行时,onCreate()函数会首先被调用,此时没有任何其他的对象在运行,在这里我们可以进行一些初始化的工作。当程序结束时, onTerminate()函数会被调用,程序进程将会退出,我们可以在此做一些最终的清理工作。需要注意的是,当因为系统资源紧张等问题,程序被系统 kill的时候,onTerminate()不会被调用到,程序将直接退出。
  稍后我们再来修改MusicPlayerDemoApp,先往下继续。

三.管理音乐信息的类MusicDBController
  为了使接口整洁,便于管理和使用,我们将在第三章介绍的         查询管理音乐信息的方法统一封装在MusicDBController类中。

view plain copy to clipboard print ?

  1. public   static  MusicDBController getInstance(MusicPlayerDemoApp app) {  

  2.         if (sInstance ==  null ) {  

  3.             sInstance = new  MusicDBController(app);  

  4.         }  

  5.         return  sInstance;  

  6.     }  

  7.       

  8.     private  MusicDBController(MusicPlayerDemoApp app) {  

  9.         mApp = app;  

  10.   }  

  11.   

  12. private  Cursor query(Uri _uri, String[] prjs, String selections,  

  13.             String[] selectArgs, String order) {  

  14.         ContentResolver resolver = mApp.getContentResolver();  

  15.         if  (resolver ==  null ) {  

  16.             return   null ;  

  17.         }  

  18.           

  19.         return  resolver.query(_uri, prjs, selections, selectArgs,  

  20.                 order);  

  MusicDBController采用单例模式,使程序中只有唯一的实例。我们传入MusicPlayerDemoApp 作为Context生成Content Resolver,用来查询媒体库。

  现在,我们修改MusicPlayerDemoApp,添加一个MusicDBController的成员,并在onCreate()中初始化它。

view plain copy to clipboard print ?

  1. private  MusicDBController mDBContorller =  null ;      

  2.     public   void  onCreate() {  

  3.         // TODO Auto-generated method stub   

  4.         super .onCreate();  

  5.           

  6.         // init MusicDBController   

  7.         mDBContorller = MusicDBController.getInstance(this );  

  8.   }  

  9.     并且提供一个获取MusicDBController的接口:  

  10.       

  11. public  MusicDBController getMusicDBController(){  

  12.         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 右下文字

 

view plain copy to clipboard print ?

  1. public   void  bindView(View view, Context context, Cursor cursor) {     

  2.           

  3.     super .bindView(view, context, cursor);  

  4.           

  5.     TextView titleView = (TextView) view.findViewById(android.R.id.text1);  

  6.         TextView artistView = (TextView) view.findViewById(android.R.id.text2);  

  7.         TextView durationView = (TextView) view.findViewById(android.R.id.text3);  

  8.         ImageView imageView = (ImageView) view.findViewById(android.R.id.listicon1);  

  9.           

  10.         // Set icon   

  11.         imageView.setImageResource(R.drawable.cmcc_list_music);  

  12.           

  13.         // Set track name   

  14.         titleView.setText(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)));  

  15.           

  16.         // Set artist name   

  17.         artistView.setText(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST)));  

  18.           

  19.         // Set duration   

  20.         int  duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));  

  21.         durationView.setText(makeTimeString(duration));  

  22.           

  23.     }  

 注意,上面这段代码中的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的实例,为获取歌曲信息做准备。 

view plain copy to clipboard print ?

  1. private  MusicDBController mDBController =  null ;  

  2.       

  3.     /** Called when the activity is first created. */   

  4.     @Override   

  5.     public   void  onCreate(Bundle savedInstanceState) {  

  6.         super .onCreate(savedInstanceState);  

  7.         setContentView(R.layout.main);  

  8.           

  9.         mDBController = ((MusicPlayerDemoApp)getApplication()).getMusicDBController();  

  10.     }  

  11. 通过MusicListAdapter,我们将从MusicDBController中拿到的媒体库信息,绑定到ListView,我们在onResume()完成这个工作。  

  12. protected   void  onResume() {  

  13.         super .onResume();  

  14.         mCursor = mDBController.getAllSongs();  

  15.         MusicListAdapter adapter = new  MusicListAdapter( this , android.R.layout.cmcc_list_5, mCursor,  new  String[]{},  new   int []{});  

  16.         setListAdapter(adapter);  

  17.  }  

  18. 将MusicListActivity添加到AndroidManifest.xml中  

  19.   

  20. <activity android:name=".MusicListActivity" >  

  21.             <intent-filter>  

  22.                 <action android:name="android.intent.action.MAIN"  />  

  23.                 <category android:name="android.intent.category.LAUNCHER"  />  

  24.             </intent-filter>  

  25.         </activity>  

  现在运行一下我们的程序,它已经可以展现给你媒体库的音乐列表了。

  同样的,仿照上面的过程,我们还可以添加展示专辑列表,艺术家列表等等Activity,我们就不再一一介绍了。

五.后台播放-使用Service

      现在我们需要考虑如何来播放这些媒体库中的文件了。我们希望当用户退出这个程序界面后,我们的程序仍然能够继续播放歌曲,比如用户在读邮件时,可以听听音 乐。为了达到后台播放的效果,需要使用Service。当程序的所有Activity都退出后,Service仍然可以在后台运行。在这个示例中我们使用 Local Service,它与应用程序运行在同一个进程中。(我们甚至可以不使用bind service就直接获得它的句柄,调用它所提供的函数。)

  首先,创建一个MusicPlaybackService类,它继承自android.app.Service,重载onBind方法,返回自 定义的LocalBinder,通过LocalBinder的getService()方法就可以获得MusicPlaybackService的句柄 了。 

view plain copy to clipboard print ?

  1. private   final  IBinder mBinder =  new  LocalBinder();  

  2.       

  3.     public   class  LocalBinder  extends  Binder {  

  4.         public  MusicPlaybackService getService() {  

  5.             return  MusicPlaybackService. this ;  

  6.         }  

  7.     }  

  8.       

  9.     @Override   

  10.     public  IBinder onBind(Intent intent) {  

  11.         // TODO Auto-generated method stub   

  12.         return  mBinder;  

  我们继续完成MusicPlaybackService的基本构架,添加一个MediaPlayer成员,并在onCreate()函数中对其进行初始化,它将负责音乐播放的主要功能。

view plain copy to clipboard print ?

  1. private  MediaPlayer mMediaPlayer =  null ;  

  2.           

  3.     public   void  onCreate() {  

  4.         super .onCreate();  

  5. mMediaPlayer = new  MediaPlayer();  

  6. }  

  构架完成MusicPlaybackService的基本架构后,我们要定义一些常用的控制接口了,其他模块通过这些接口,可以控制音乐的播放,暂停,停止等功能。

view plain copy to clipboard print ?

  1. public   void  setDataSource(String path) {  

  2.         try  {  

  3.             mMediaPlayer.reset();  

  4.             mMediaPlayer.setDataSource(path);  

  5.             mMediaPlayer.prepare();  

  6.         } catch  (IOException e) {  

  7.             return ;  

  8.         } catch  (IllegalArgumentException e) {  

  9.             return ;  

  10.         }  

  11.     }  

  12.       

  13.     public   void  start() {  

  14.         mMediaPlayer.start();  

  15.     }  

  16.       

  17.     public   void  stop() {  

  18.         mMediaPlayer.stop();  

  19.     }  

  20.   

  21.     public   void  pause() {  

  22.         mMediaPlayer.pause();  

  23.     }  

  24.   

  25.     public   boolean  isPlaying() {  

  26.         return  mMediaPlayer.isPlaying();  

  27.     }  

  28.       

  29.     public   int  getDuration() {  

  30.         return  mMediaPlayer.getDuration();  

  31.     }  

  32.   

  33.     public   int  getPosition() {  

  34.         return  mMediaPlayer.getCurrentPosition();  

  35.     }  

  36.   

  37.     public   long  seek( long  whereto) {  

  38.         mMediaPlayer.seekTo((int ) whereto);  

  39.         return  whereto;  

  40. }  

  最后,修改AndroidManifest.xml,添加MusicPlaybackService的定义。

view plain copy to clipboard print ?

  1. <service android:name= ".MusicPlaybackService"  android:exported= "true"  >  

  2.             <intent-filter>  

  3.                  <action android:name="com.ophone.musicplaybackservice"  />  

  4.             </intent-filter>      

  5. </service>  

 六.开始播放歌曲

      MusicPlaybackService准备就绪,我们可以利用它来播放歌曲了。修改MusicListActivity,在 onCreate() 中通过startService()函数启动MusicPlaybackService,并通过bindService()函数与之绑定。当绑定完成 时,ServiceConnection的 onServiceConnected()接口将被调用。

view plain copy to clipboard print ?

  1. private  MusicPlaybackService mPlaybackService =  null ;      

  2.       

  3.    private  ServiceConnection mPlaybackConnection =  new  ServiceConnection() {  

  4.         public   void  onServiceConnected(ComponentName className, IBinder service) {    

  5.             mPlaybackService = ((MusicPlaybackService.LocalBinder)service).getService();  

  6.         }  

  7.   

  8.         public   void  onServiceDisconnected(ComponentName className) {  

  9.             mPlaybackService = null ;  

  10.         }  

  11. };  

  12.   

  13. public   void  onCreate(Bundle savedInstanceState) {  

  14.         super .onCreate(savedInstanceState);  

  15.         setContentView(R.layout.list_layout);  

  16.           

  17.         mDBController = ((MusicPlayerDemoApp)getApplication()).getMusicDBController();  

  18.           

  19.         // bind playback service   

  20.         startService(new  Intent( this ,MusicPlaybackService. class ));          

  21.         bindService(new  Intent( this ,MusicPlaybackService. class ), mPlaybackConnection, Context.BIND_AUTO_CREATE);  

      为MusicListActivity添加点击事件处理,当用户点击一个音乐item时,会开始自动播放该歌曲,当用户点击一个item时,onListItemClick()函数会被调用。

view plain copy to clipboard print ?

  1. protected   void  onListItemClick(ListView l, View v,  int  position,  long  id) {  

  2.         // TODO Auto-generated method stub   

  3.         super .onListItemClick(l, v, position, id);  

  4.           

  5.         if  (mCursor ==  null  ||mCursor.getCount() ==  0 ) {  

  6.             return ;  

  7.         }  

  8.         mCursor.moveToPosition(position);  

  9.         String url = mCursor  

  10.                        .getString(mCursor  

  11.                             .getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));  

  12.         mPlaybackService.setDataSource(url);  

  13.         mPlaybackService.start();  

  14.     }  

      现在赶紧运行一下程序吧,看看是不是已经可以播放音乐了呢。

七. 播放控制-使用Intent和Broadcast Receiver

      目前我们只能播放音乐,还无法控制音乐的播放,暂停,停止,等等,让我们进一步来完善这个播放程序,给它添加两个控制按钮。
修改MusicListActivity的layout文件list_layout.xml如下:

view plain copy to clipboard print ?

  1. <?xml version= "1.0"  encoding= "UTF-8" ?>  

  2. <LinearLayout  

  3. android:id="@+id/widget1"   

  4. android:layout_width="fill_parent"   

  5. android:layout_height="fill_parent"   

  6. xmlns:android="http://schemas.android.com/apk/res/android"   

  7. android:orientation="vertical"   

  8. >  

  9. <RelativeLayout android:id="@+id/control_panel"   

  10.         android:orientation="horizontal"    

  11.         android:layout_width="fill_parent"   

  12.         android:layout_height="wrap_content"   

  13.         >  

  14.           

  15. <TextView android:id="@+id/show_text"   

  16.         android:layout_width="fill_parent"   

  17.         android:layout_height="wrap_content"   

  18.         android:textSize="20sp"   

  19.         android:text="@string/click_to_play" />  

  20.   

  21. <Button android:id="@+id/play_pause_btn"   

  22.     android:layout_width="100px"   

  23.     android:layout_height="wrap_content"    

  24.     android:layout_alignParentLeft="true"   

  25.     android:visibility="invisible"   

  26.     android:text="@string/play" />      

  27.         

  28. <Button android:id="@+id/stop_btn"   

  29.     android:layout_width="100px"   

  30.     android:layout_height="wrap_content"    

  31.     android:layout_alignParentRight="true"   

  32.     android:visibility="invisible"   

  33.     android:text="@string/stop" />              

  34. </RelativeLayout>  

  35.   

  36.   

  37. <ListView android:id="@id/android:list"   

  38.         android:layout_width="fill_parent"   

  39.         android:layout_height="fill_parent"   

  40.         android:cacheColorHint="#00000000" />  

  41.           

  42. <TextView android:id="@id/android:empty"   

  43.         android:layout_width="fill_parent"   

  44.         android:layout_height="fill_parent"   

  45.         android:textSize="20sp"   

  46.         android:text="@string/no_music" />  

  47. </LinearLayout>  

       在MusicListActivity中,添加两个按钮点击事件的处理程序,通过Button的setOnClickListener()函数,为 button添加一个Button.OnClickListener,当有点击事件发生时,Button.OnClickListener的 onClick()接口将被调用。

view plain copy to clipboard print ?

  1. private  TextView mTextView =  null ;  

  2. private  Button mPlayPauseButton =  null ;  

  3. private  Button mStopButton =  null ;  

5b911f080001981d01050060.jpg

       在onCreate函数中,增加如下的代码: 

view plain copy to clipboard print ?

  1. mTextView = (TextView)findViewById(R.id.show_text);  

  2.         mPlayPauseButton = (Button) findViewById(R.id.play_pause_btn);  

  3.         mStopButton = (Button) findViewById(R.id.stop_btn);  

  4.           

  5.         mPlayPauseButton.setOnClickListener(new  Button.OnClickListener() {  

  6.             public   void  onClick(View v) {  

  7.                 // Perform action on click   

  8.                 if  (mPlaybackService !=  null  && mPlaybackService.isPlaying()) {  

  9.                     mPlaybackService.pause();  

  10.                     mPlayPauseButton.setText(R.string.play);  

  11.                 } else   if  (mPlaybackService !=  null ){  

  12.                     mPlaybackService.start();  

  13.                     mPlayPauseButton.setText(R.string.pause);  

  14.                 }  

  15.             }  

  16.         });  

  17.           

  18.         mStopButton.setOnClickListener(new  Button.OnClickListener() {  

  19.             public   void  onClick(View v) {  

  20.                 // Perform action on click   

  21.                 if  (mPlaybackService !=  null  ) {  

  22.                     mTextView.setVisibility(View.VISIBLE);  

  23.                     mPlayPauseButton.setVisibility(View.INVISIBLE);  

  24.                     mStopButton.setVisibility(View.INVISIBLE);  

  25.                     mPlaybackService.stop();  

  26.                 }  

  27.             }  

  28.         });  

       现在运行程序,我们还看不到这两个控制按钮,默认状态下他们是不可见状态。程序刚启动时,默认显示提示信息。当播放器状态发生改变,有歌曲进行播放时,我 们显示控制按钮,隐藏提示信息。我们使用Intent和BroadCast Receiver来实现这个功能。

      定义准备完毕和播放完毕的Action String 

view plain copy to clipboard print ?

  1. public   static   final  String PLAYER_PREPARE_END =  "com.ophone.musicplaybackservice.prepared" ;  

  2.     public   static   final  String PLAY_COMPLETED =  "com.ophone.musicplaybackservice.playcompleted" ;  

      播放器状态发生改变的时候,通过Intent的形式,将消息广播出去,给mediaplayer添加 MediaPlayer.OnPreparedListener和MediaPlayer.OnCompletionListener,监听准备完毕和播 放结束的消息。

view plain copy to clipboard print ?

  1. MediaPlayer.OnCompletionListener mCompleteListener =  new  MediaPlayer.OnCompletionListener() {  

  2.         public   void  onCompletion(MediaPlayer mp) {  

  3.             broadcastEvent(PLAY_COMPLETED);  

  4.         }  

  5.     };  

  6.       

  7.     MediaPlayer.OnPreparedListener mPrepareListener = new  MediaPlayer.OnPreparedListener() {  

  8.         public   void  onPrepared(MediaPlayer mp) {     

  9.             broadcastEvent(PLAYER_PREPARE_END);  

  10.         }  

  11.     };  

  12.       

  13.     private   void  broadcastEvent(String what) {  

  14.         Intent i = new  Intent(what);  

  15.         sendBroadcast(i);  

  16. }  

  17.   

  18. 修改MusicPlaybackService,在mediaplayer中注册这个两个Listener:  

  19.   

  20. public   void  onCreate() {  

  21.         super .onCreate();  

  22.           

  23.         mMediaPlayer = new  MediaPlayer();  

  24.         mMediaPlayer.setOnPreparedListener(mPrepareListener);  

  25.         mMediaPlayer.setOnCompletionListener(mCompleteListener);  

       在MusicListActivity中,我们定义一个BroadcastReceiver来处理这两个消息:

view plain copy to clipboard print ?

  1. protected  BroadcastReceiver mPlayerEvtReceiver =  new  BroadcastReceiver() {  

  2.         @Override   

  3.         public   void  onReceive(Context context, Intent intent) {  

  4.             String action = intent.getAction();  

  5.             if  (action.equals(MusicPlaybackService.PLAYER_PREPARE_END)) {  

  6.                 // will begin to play   

  7.                 mTextView.setVisibility(View.INVISIBLE);  

  8.                 mPlayPauseButton.setVisibility(View.VISIBLE);  

  9.                 mStopButton.setVisibility(View.VISIBLE);  

  10.                   

  11.                 mPlayPauseButton.setText(R.string.pause);  

  12.             } else   if (action.equals(MusicPlaybackService.PLAY_COMPLETED)) {  

  13.                 mPlayPauseButton.setText(R.string.play);  

  14.             }  

  15.         }  

  16.     };  

  17.   

  18. 在onCreate()函数中,注册这个BroadcastReceiver来监听PLAYER_PREPARE_END 和PLAY_COMPLETED 这两个信息 ,在onCreate函数中添加下面的代码:  

  19. IntentFilter filter = new  IntentFilter();  

  20.         filter.addAction(MusicPlaybackService.PLAYER_PREPARE_END);  

  21.         filter.addAction(MusicPlaybackService.PLAY_COMPLETED);  

  22.     registerReceiver(mPlayerEvtReceiver, filter);  

      OK,现在我们的音乐播放器已经成型了,马上运行一下吧。

给程序加点新功能

  下面介绍的功能,在我们的示例代码中并没有实现,如果您感兴趣的话,可以按照下文介绍的大概步骤,添加到程序中,他们其实都很简单。

1.利用Alarm service实现简单的闹铃功能。
  Alarm Service是OPhone平台提供的一个系统服务。程序可以向Alarm Service注册一个PendingIntent,当到达注册时间的时候,Alarm Service会发出这个事先注册的intent,程序监听这个intent就可以达到定时的效果。

 1)添加一个BroadcastReceiver

view plain copy to clipboard print ?

  1. public   class  StartAlarm  extends  BroadcastReceiver {  

  2.         public   void  onReceive(Context context, Intent intent) {  

  3.             // 添加处理程序,启动播放。   

  4.         }  

  5. }  

5b911f080001981d01050060.jpg

  在AndroidManifest.xml中添加定义:

view plain copy to clipboard print ?

  1. <receiver android:name= ".StartAlarm"  />  

5b911f080001981d01050060.jpg

  2)注册Alarm Service

view plain copy to clipboard print ?

  1. Intent startIntent =  new  Intent(Context, StartAlarm. class );  

  2.   

  3. PendingIntent startSender = PendingIntent.getBroadcast(  

  4.                 Context, 0 , startIntent,  0 );  

  5.   

  6. // Schedule the alarm!  startTimeMillis 是定时时间   

  7.         AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);  

  8.         am.setRepeating(AlarmManager.RTC_WAKEUP, startTimeMillis,  

  9.                 24  *  60  *  60  *  1000 , startSender);  

       OK,我们就完成了定时注册,当注册时间到达时,即使程序没有运行,也会被唤醒,StartAlarm的onReceive()函数被调用,开始播放音乐。一个简单的闹钟功能就实现了。感兴趣的朋友可以马上动手试验试验。  

  2.设置振铃
  当我们发现了一首非常好听的歌曲,想把它设置成来电振铃,    如何实现呢?很简单,只需要如下两个步骤。

  第一步,更新歌曲在media provider数据库中的信息,
将 MediaStore.Audio.Media.IS_RINGTONE,
MediaStore.Audio.Media.IS_ALARM,
MediaStore.Audio.Media.IS_NOTIFICATION都置成 1。

  假设歌曲的id为 songId:

view plain copy to clipboard print ?

  1. ContentResolver resolver = ctx.getContentResolver();  

  2.         // Set the flag in the database to mark this as a ringtone   

  3.         Uri ringUri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songId);     

  4.        

  5.         try  {                         

  6.             ContentValues values = new  ContentValues( 2 );  

  7.             values.put(MediaStore.Audio.Media.IS_RINGTONE, "1" );  

  8.             values.put(MediaStore.Audio.Media.IS_ALARM, "1" );  

  9.             values.put(MediaStore.Audio.Media.IS_NOTIFICATION, "1" );              

  10.             resolver.update(ringUri, values, null ,  null );              

  11.               

  12.         } catch  (UnsupportedOperationException ex) {  

  13.             return ;  

  14.     }  

  第二步,通过android.provider.Settings.Profile的setRingTone接口,设置歌曲为振铃:

view plain copy to clipboard print ?

  1. Settings.Profile.setRingTone(resolver, ringUri);  

  现在给自己打个电话试试看,是不是振铃已经起作用了

原文链接:http://www.apkbus.com/blog-822415-72735.html

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP