第四部分 音乐播放器
该播放器实现了界面布局、MediaPlayer的使用、Service的使用、媒体信息的管理MediaStore等操作
1、UI设计。通过xml文件对其进行设计
res.layout.list_layout.xml
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
android:id="@+id/widget1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android=" http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="@drawable/bg"
>
<RelativeLayout
android:id="@+id/control_panel"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<TextView
android:id="@+id/show_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:text="@string/click_to_play"/>
<Button
android:id="@+id/play_pause_btn"
android:layout_width="100px"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:visibility="invisible"
android:text="@string/play"/>
<Button
android:id="@+id/stop_btn"
android:layout_width="100px"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:visibility="invisible"
android:text="@string/stop"/>
</RelativeLayout>
<ListView
android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:cacheColorHint="#00000000"/>
<TextView
android:id="@id/android:empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:textSize="20sp"
android:text="@string/no_music"/>
</LinearLayout>

2、多媒体信息的管理
为了实现在启动播放器的同时自动获取手机和SD卡上的音频文件,并显示到ListView视图中。Android系统提供了MediaScanner、MediaProvider、MediaStore等接口,及一套数据
库,可通过ContentProvider方式提供给用户。当手机开机或有SD卡插入等事件发生时,系统将会自动扫描SD卡和手机内存上的媒体文件,如音频、视频、图片等。将相应的信息
放到定义好的数据库表中。MediaStore中定义了一系列的数据表,通过ContentResolver提供的查询接口,可以得到各种需要的信息。如何获得这些信息及使用方法:
ContentResolver提供了如下查询接口;
//参数uri指明要查询的数据库名称加上表的名称;projection指定查询数据库表中的哪几列,返回的游标中将包括相应的信息,null则返回为空;
//参数selection 指定查询条件; 参数selectionArgs 如果selection中有"?"这个符号,这里可以以实际值代替这个问号,如果没有则String数组可以为null;
//参数sortOrder 指定查询结果的排列顺序
Cursor query(Uri uri, String[] projection, String selection, String [] selectionArgs, String sorttOrder);
例:
Cursor cursor =query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,null,null,MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
该方法将返回所以外部存储卡上的音乐文件的信息,可以通过一些常量来获得歌曲的具体信息如下:
多媒体常用信息
MediaStore.Audio.Media._ID歌曲ID
MediaStore.Audio.Media.TITLE歌曲名称
MediaStore.Audio.Media.ALBUM歌曲的专辑名
MediaStore.Audio.Media.ARTIST歌曲歌手名
MediaStore.Audio.Media.DATA歌曲文件的路径
MediaStore.Audio.Media.DURATION歌曲的总播放时长
MediaStore.Audio.Media.SIZE歌曲文件的大小
MediaStore.Audio.Playlists.DATE_MODIFIED 修改时间
MediaStore.Audio.Playlists.DATE_ADDED添加时间
MediaStore.Audio.Playlists.NAME播放列表名称
MediaStore.Audio.Playlists._ID播放列表ID
MediaStore.Audio.Albums.NUMBER_OF_SONGS该专辑共有多少歌曲
MediaStore.Audio.Albums.ALBUM专辑名称
MediaStore.Audio.Albums._ID专辑ID
MediaStore.Audio.Artists.NUMBER_OF_TRACKS共有多少该歌手的歌曲
MediaStore.Audio.Artists.NUMBER_OF_ALBUMS共有多少该歌手的专辑
MediaStore.Audio.Artists.ARTIST歌手姓名
MediaStore.Audio.Artists._ID歌手ID
我们可以通过相应的cursor.get方法来获取这些信息。如下:
int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
String tilte = cursor.getString(cursor.getColumIndexOrThrow(MediaStore.Audio.Media.TITLE));
String album = cursor.getString(cursor.getColumIndexOrThrow(MediaStore.Audio.Media.ALBUM));
String artist = cursor.getString(cursor.getColumIndexOrThrow(MediaStore.Audio.Media.ARTIST));
int size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));
int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));

Cursor cursor =query(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, null,null,null,MediaStore.Audio.Artists.DEFAULT_SORT_ORDER);//查询歌手信息,返回所有外部存储卡上的歌手信息
Cursor cursor =query(MeidaStore.Audio.Albums.EXTERNAL_CONTENT_URI, null,null,null,MediaStore.Audio.Albums.DEFAULT_SORT_ORDER);//查询专辑,返回所有外部存储卡上的专辑信息
Cursor cursor =query(MeidaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,null,null,null,MeidaStore.Audio.Playlists.DEFAULT_SORT_ORDER);//查询播放列表,返回所有外部存储卡上的专辑信息
通过这些查询结果,指定查询条件,用户可以很方便的查询指定的媒体信息,如:
query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, MediaStroe.Audio.Media.ARTIST_ID+"="+aid, null, MediaStore.Audio.Media.TITLE);//查询属于指定歌手(歌手ID为"aid")的歌曲
query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,MediaStore.Audio.Media.ALBUM_ID+"="+ aid, null,MediaStore.Audio.Media.TITLE);//查询属于指定专辑(歌手ID为"aid")的歌曲

public class MusicInfoController{//定义一个用来管理音乐信息的类
private static MusicInfoControllermInstance= null;
private MusicPlayerApppApp= null;
public static MusicInfoController getInstance(MusicPlayerApp app){
if (mInstance == null){
mInstance = new MusicInfoController(app);
}
return mInstance;
}
private MusicInfoController(MusicPlayerApp app){
pApp = app;
}
public MusicPlayerApp getMusicPlayer(){
return pApp;
}
private Cursor query(Uri uri, String[] prjs, String selections, String[] selectArgs, String order){//查询指定信息
ContentResolver resolver = pApp.getContentResolver();
if (resolver == null){
return null;
}
return resolver.query(uri, prjs, selections, selectArgs, order);
}
public Cursor getAllSongs(){//查询所有歌曲信息
return query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
}
}

3、播放音乐
public class MusicPlayerService extends Service{//我们希望当退出程序界面后,音乐仍然继续播放这就需要Service,本例采用了Local Service它与程序运行在同一个进程中。
private final IBinder mBinder = new LocalBinder();
private MediaPlayer mMediaPlayer = null; //音乐文件的播放是由MediaPlayer类实现的,如常用接口播放、暂停、停止、快速定位等
public static final String PLAYER_PREPARE_END = "com.yarin.musicplayerservice.prepared";
public static final String PLAY_COMPLETED = "com.yarin.musicplayerservice.playcompleted";

MediaPlayer.OnCompletionListener mCompleteListener = new MediaPlayer.OnCompletionListener() {//给MediaPlay添加MediaPlayer.OnPreparedListener和
MediaPlay.OnCompletionListener监听准备完毕和播放结束的消息
public void onCompletion(MediaPlayer mp) {
broadcastEvent(PLAY_COMPLETED);
}
};
MediaPlayer.OnPreparedListener mPrepareListener = new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
broadcastEvent(PLAYER_PREPARE_END);
}
};
private void broadcastEvent(String what){//在我们没有播放歌曲时,播放,暂停等按钮处于不可见状态,当选择其中一首时,
要显示这些按钮,当这个状态改变时,通过Intent的形式,将准备完毕或播放等消息广播(BroadCastReceiver)出去。
Intent i = new Intent(what);
sendBroadcast(i);
}
public void onCreate(){
super.onCreate();
mMediaPlayer = new MediaPlayer();//对MediaPlayer用来播放音乐,在此处初始化
mMediaPlayer.setOnPreparedListener(mPrepareListener);
mMediaPlayer.setOnCompletionListener(mCompleteListener);
}
public class LocalBinder extends Binder{
public MusicPlayerService getService(){//通过LocalBinder的getService方法得当MusicPlayerService的实例
return MusicPlayerService.this;
}
}
public IBinder onBind(Intent intent){//重置 onBind 方法,返回自定义的 LocalBinder
return mBinder;
}
public void setDataSource(String path){
try{
mMediaPlayer.reset();
mMediaPlayer.setDataSource(path);
mMediaPlayer.prepare();
}catch (IOException e){
return;
}catch (IllegalArgumentException e){
return;
}
}
public void start(){//播放
mMediaPlayer.start();
}
public void stop(){//停止
mMediaPlayer.stop();
}
public void pause(){//暂停
mMediaPlayer.pause();
}
public boolean isPlaying(){
return mMediaPlayer.isPlaying();
}
public int getDuration(){
return mMediaPlayer.getDuration();
}
public int getPosition(){
return mMediaPlayer.getCurrentPosition();
}
public long seek(long whereto){
mMediaPlayer.seekTo((int) whereto);
return whereto;
}
}

public class MusicList extends ListActivity{//通过MusicList来显示播放列表开启服务Service,在后台播放音乐.
private MusicPlayerService mMusicPlayerService = null;
private MusicInfoController mMusicInfoController = null;
private Cursor mCursor = null;
private TextView mTextView = null;
private Button mPlayPauseButton = null;
private Button mStopButton = null;
private ServiceConnection mPlaybackConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mMusicPlayerService = ((MusicPlayerService.LocalBinder)service).getService();
}
public void onServiceDisconnected(ComponentName className) {
mMusicPlayerService = null;
}
};
protected BroadcastReceiver mPlayerEvtReceiver = new BroadcastReceiver() {//对接收到广播进行处理
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(MusicPlayerService.PLAYER_PREPARE_END)) {
// will begin to play
mTextView.setVisibility(View.INVISIBLE);
mPlayPauseButton.setVisibility(View.VISIBLE);
mStopButton.setVisibility(View.VISIBLE);
mPlayPauseButton.setText(R.string.pause);
} else if(action.equals(MusicPlayerService.PLAY_COMPLETED)) {
mPlayPauseButton.setText(R.string.play);
}
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_layout);

MusicPlayerApp musicPlayerApp=(MusicPlayerApp)getApplication();
mMusicInfoController = (musicPlayerApp).getMusicInfoController();
startService(new Intent(this,MusicPlayerService.class));// bind playback service
bindService(new Intent(this,MusicPlayerService.class), mPlaybackConnection, Context.BIND_AUTO_CREATE);

mTextView = (TextView)findViewById(R.id.show_text);
mPlayPauseButton = (Button) findViewById(R.id.play_pause_btn);
mStopButton = (Button) findViewById(R.id.stop_btn);

mPlayPauseButton.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
if (mMusicPlayerService != null && mMusicPlayerService.isPlaying()) {// Perform action on click
mMusicPlayerService.pause();
mPlayPauseButton.setText(R.string.play);
} else if (mMusicPlayerService != null){
mMusicPlayerService.start();
mPlayPauseButton.setText(R.string.pause);
}
}
});
mStopButton.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
if (mMusicPlayerService != null ) { // Perform action on click
mTextView.setVisibility(View.VISIBLE);
mPlayPauseButton.setVisibility(View.INVISIBLE);
mStopButton.setVisibility(View.INVISIBLE);
mMusicPlayerService.stop();
}
}
});
IntentFilter filter = new IntentFilter();
filter.addAction(MusicPlayerService.PLAYER_PREPARE_END);
filter.addAction(MusicPlayerService.PLAY_COMPLETED);
registerReceiver(mPlayerEvtReceiver, filter);
}
protected void onResume() {
super.onResume();
mCursor = mMusicInfoController.getAllSongs();
ListAdapter adapter = new MusicListAdapter(this, android.R.layout.simple_expandable_list_item_2, mCursor, new String[]{}, new int[]{});
setListAdapter(adapter);
}
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
if (mCursor == null ||mCursor.getCount() == 0) {
return;
}
mCursor.moveToPosition(position);
String url = mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
mMusicPlayerService.setDataSource(url);
mMusicPlayerService.start();
}
}

class MusicListAdapter extends SimpleCursorAdapter {
public MusicListAdapter(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
}
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);
titleView.setText(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)));
artistView.setText(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST)));
//int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));
}
public static String makeTimeString(long milliSecs) {
StringBuffer sb = new StringBuffer();
long m = milliSecs / (60 * 1000);
sb.append(m < 10 ? "0" + m : m);
sb.append(":");
long s = (milliSecs % (60 * 1000)) / 1000;
sb.append(s < 10 ? "0" + s : s);
return sb.toString();
}
}

public class MusicPlayerApp extends Application{
private MusicInfoControllermMusicInfoController= null;
public void onCreate(){
super.onCreate();
mMusicInfoController = MusicInfoController.getInstance(this);
}
public MusicInfoController getMusicInfoController(){
return mMusicInfoController;
}
}

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yarin.android.MusicPlayer"
android:versionCode="1"
android:versionName="1.0">
<application
android:name="MusicPlayerApp"
android:icon="@drawable/icon"
android:label="@string/app_name">
<activity
android:name=".MusicList">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service //用于使用了Service来播放音乐,所有需要注册权限,另外程序中MusicInfoController采用单例模式,使程序只要唯一的实例,我们传入的MusicPlayerApp
作为Context生成ContentResolver,用来查询媒体库。
android:name=".MusicPlayerService"
android:exported="true" >
</service>
</application>
<uses-sdk android:minSdkVersion="5" />
</manifest>

更多相关文章

  1. adb 获取平台号
  2. Android开发之获取常用android设备参数信息
  3. Android(安卓)之Notification 用法
  4. MobSF安装使用及过程中遇到的错误
  5. 定制自己的 Android(安卓)Dialog 信息提示对话框
  6. 使用maven构建android 的apk包并自动签名
  7. Android(安卓)安全机制概述
  8. Android(安卓)自动检测版本并升级
  9. android中的Handler(1)

随机推荐

  1. 阅读《Android 从入门到精通》(29)——四大
  2. 安卓页面技巧片段 - 1
  3. android 改变 listView gridView的默认点
  4. Android——ViewPager+Fragment+ListView
  5. Android自动化测试之MonkeyRunner-startA
  6. Android7.0中文文档(API)-- LinearLayout.L
  7. Android:如何设计一个完全不可见的Activi
  8. android 微信 listview 气泡
  9. 坑爹啊 横向滑动多屏竟然官方就有
  10. Android 获取唯一硬件编号