与系统music同步播放器Demo
来源:互联网 发布:伦拜亚斯体测数据 编辑:程序博客网 时间:2024/05/18 20:07
看很多网友对music源码比较感兴趣,自己琢磨了一下,正好有时间,写了个小Demo,结合Demo我把自己学到东西跟大家分享下。
首先讲下Demo实现的功能,很简单,就是实现和music同步播放,并把歌名,演唱者,专辑封面显示给用户,之前学到widget,此次就用widget实现吧,正好也是个知识的巩固吧。没有用到activity。
Demo名MyMusic
1、在laytou下创建widget布局文件,mymusic_widget_laytou
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="match_parent" android:background="@color/light_blue" > <ImageView android:id="@+id/img_album" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="centerCrop" /> <LinearLayout android:id="@+id/widget" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" android:orientation="vertical" > <RelativeLayout android:id="@+id/album_cover" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="4" android:gravity="center_horizontal" android:orientation="vertical" > <TextView android:id="@+id/tv_songname" android:layout_width="fill_parent" android:layout_height="40dip" android:layout_above="@+id/tv_artist" android:gravity="center" android:text="@string/songname" android:textColor="@color/white" /> <TextView android:id="@+id/tv_artist" android:layout_width="fill_parent" android:layout_height="40dip" android:layout_alignParentBottom="true" android:gravity="center" android:text="@string/artist" android:textColor="@color/white" /> </RelativeLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1" android:gravity="center_vertical" > <ProgressBar android:id="@+id/probar_song" style="?android:attr/progressBarStyleHorizontal" android:layout_width="fill_parent" android:layout_height="20dip" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="0dip" android:layout_gravity="center" android:layout_weight="1" android:orientation="horizontal" > <ImageView android:id="@+id/img_rewind" android:layout_width="40dip" android:layout_height="fill_parent" android:clickable="true" android:focusable="true" android:src="@drawable/rewind_bg" /> <ImageView android:id="@+id/img_play" android:layout_width="40dip" android:layout_height="fill_parent" android:layout_marginLeft="40dip" android:clickable="true" android:focusable="true" android:src="@drawable/play_bg" /> <ImageView android:id="@+id/img_next" android:layout_width="40dip" android:layout_height="fill_parent" android:layout_marginLeft="40dip" android:clickable="true" android:focusable="true" android:src="@drawable/forward_bg" /> </LinearLayout> </LinearLayout></FrameLayout>
2、在res下新建xml文件夹,在该文件夹下新建mymusic_widget.xml
<?xml version="1.0" encoding="utf-8"?><appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="160dip" android:minHeight="80dip" android:resizeMode="horizontal|vertical" android:updatePeriodMillis="0" android:initialLayout="@layout/mymusic_widget_layout" android:previewImage="@drawable/mymusicpre" ></appwidget-provider>
3、新建java文件,MymusicProvider,该类继承自AppWidgetProvider
package com.example.mymusic;import java.io.FileDescriptor;import android.app.PendingIntent;import android.appwidget.AppWidgetManager;import android.appwidget.AppWidgetProvider;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.net.Uri;import android.os.ParcelFileDescriptor;import android.util.Log;import android.widget.RemoteViews;public class MyMusicProvider extends AppWidgetProvider { public static final String TOGGLEPAUSE_ACTION = "com.android.music.musicservicecommand.togglepause"; public static final String PAUSE_ACTION = "com.android.music.musicservicecommand.pause"; public static final String PREVIOUS_ACTION = "com.android.music.musicservicecommand.previous"; public static final String NEXT_ACTION = "com.android.music.musicservicecommand.next"; public static final String PLAYSTATE_CHANGED = "com.android.music.playstatechanged"; public static final String META_CHANGED = "com.android.music.metachanged"; public static final String MUSIC_SERVICE = "com.example.mymusic.MUSIC_SERVICE"; // public static RemoteViews musicRemoteViews; // public static Context mContext; @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds); RemoteViews musicRemoteViews = new RemoteViews( context.getPackageName(), R.layout.mymusic_widget_layout); initView(context, musicRemoteViews); musicRemoteViews.setProgressBar(R.id.probar_song, 100, 0, false); appWidgetManager.updateAppWidget(appWidgetIds, musicRemoteViews); Intent musicIntent = new Intent(MUSIC_SERVICE); context.startService(musicIntent); } @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); Log.v("receive", intent.getAction()); AppWidgetManager appWidgetManager = AppWidgetManager .getInstance(context); ComponentName provider = new ComponentName(context, MyMusicProvider.class); int[] appWidgetIds = appWidgetManager.getAppWidgetIds(provider); RemoteViews musicRemoteViews = new RemoteViews( context.getPackageName(), R.layout.mymusic_widget_layout); String actionString = intent.getAction(); if (actionString.equals(PLAYSTATE_CHANGED) || actionString.equals(META_CHANGED)) { linkButtons(context, musicRemoteViews); getSongInfo(intent, musicRemoteViews); changePlayState(context, intent, musicRemoteViews); musicRemoteViews.setImageViewBitmap(R.id.img_album, getArtwork(context, intent)); musicRemoteViews.setProgressBar(R.id.probar_song, 100, MyService.mProgress, false); } appWidgetManager.updateAppWidget(appWidgetIds, musicRemoteViews); } /**更新进度条,在Service里调用*/ public static void updateProgress(Context context, int progress) { AppWidgetManager appWidgetManager = AppWidgetManager .getInstance(context); ComponentName provider = new ComponentName(context, MyMusicProvider.class); int[] appWidgetIds = appWidgetManager.getAppWidgetIds(provider); RemoteViews musicRemoteViews = new RemoteViews( context.getPackageName(), R.layout.mymusic_widget_layout); musicRemoteViews.setProgressBar(R.id.probar_song, 100, progress, false); appWidgetManager.updateAppWidget(appWidgetIds, musicRemoteViews); } /**获取歌曲名和演唱者*/ private static void getSongInfo(Intent intent, RemoteViews remoteViews) { String songString = intent.getStringExtra("track"); String artiString = intent.getStringExtra("artist"); remoteViews.setTextViewText(R.id.tv_songname, songString); remoteViews.setTextViewText(R.id.tv_artist, artiString); } /**监听播放/暂停按钮状态切换背景图片*/ private void changePlayState(Context context, Intent intent, RemoteViews remoteViews) { boolean isPlaying = intent.getBooleanExtra("playing", false); Log.e("111", intent.getAction() + " " + isPlaying); if (isPlaying) { remoteViews .setImageViewResource(R.id.img_play, R.drawable.pause_bg); } else { remoteViews.setImageViewResource(R.id.img_play, R.drawable.play_bg); } } /**获取专辑封面,没有的话显示默认*/ private Bitmap getArtwork(Context context, Intent intent) { String str = "content://media/external/audio/media/" + intent.getLongExtra("id", -1L) + "/albumart"; Uri uri = Uri.parse(str); ParcelFileDescriptor pfd = null; try { pfd = context.getContentResolver().openFileDescriptor(uri, "r"); } catch (Exception e) { e.printStackTrace(); } if (pfd != null) { Bitmap bm = null; FileDescriptor fd = pfd.getFileDescriptor(); bm = BitmapFactory.decodeFileDescriptor(fd); return bm; } return null; } /**为按钮设置背景图片,并且绑定时间*/ private void linkButtons(Context context, RemoteViews remoteViews) { Intent intent; PendingIntent pendingIntent; remoteViews.setImageViewResource(R.id.img_rewind, R.drawable.rewind_bg); remoteViews.setImageViewResource(R.id.img_play, R.drawable.play_bg); remoteViews.setImageViewResource(R.id.img_next, R.drawable.forward_bg); intent = new Intent("com.android.music.PLAYBACK_VIEWER"); pendingIntent = PendingIntent.getActivity(context, 0, intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0); remoteViews.setOnClickPendingIntent(R.id.album_cover, pendingIntent); intent = new Intent(TOGGLEPAUSE_ACTION); pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0); remoteViews.setOnClickPendingIntent(R.id.img_play, pendingIntent); intent = new Intent(NEXT_ACTION); pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0); remoteViews.setOnClickPendingIntent(R.id.img_next, pendingIntent); intent = new Intent(PREVIOUS_ACTION); pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0); remoteViews.setOnClickPendingIntent(R.id.img_rewind, pendingIntent); } /**初次运行初始化界面*/ private void initView(Context context, RemoteViews remoteViews) { Intent intent; PendingIntent pendingIntent; intent = new Intent("com.android.music.PLAYBACK_VIEWER"); pendingIntent = PendingIntent.getActivity(context, 0, intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0); remoteViews.setOnClickPendingIntent(R.id.album_cover, pendingIntent); remoteViews.setImageViewResource(R.id.img_rewind, R.drawable.button_rewind_gray); remoteViews.setImageViewResource(R.id.img_play, R.drawable.button_play_gray); remoteViews.setImageViewResource(R.id.img_next, R.drawable.button_forward_gray); }}
4、自定义一个Service,在Service里面更新播放进度条
package com.example.mymusic;import com.android.music.IMediaPlaybackService;import android.app.Service;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.util.Log;public class MyService extends Service {private static IMediaPlaybackService mService;public static long mPosition;public static long mDuration;public static int mProgress;public static Handler mHandler;public static final int UPDATE_PROGRESS = 1;public boolean miStart = false;@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// TODO Auto-generated method stubIntent i = new Intent();i.setClassName("com.android.music","com.android.music.MediaPlaybackService");ServiceConnection conn = new MediaPlayerServiceConnection();boolean isBinded = this.bindService(i, conn, 0);Log.v("isbinded", "isBinded : " + isBinded);if(!miStart && mHandler!= null){mHandler.sendEmptyMessage(UPDATE_PROGRESS);miStart = true;}return 1;}@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsuper.handleMessage(msg);try {mPosition = mService.position();mDuration = mService.duration();mProgress = (int) (100 * mPosition/mDuration);MyMusicProvider.updateProgress(MyService.this, mProgress);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}mHandler.sendEmptyMessageDelayed(UPDATE_PROGRESS, 1000);}};}class MediaPlayerServiceConnection implements ServiceConnection {public void onServiceConnected(ComponentName name, IBinder boundService) {Log.i("MediaPlayerServiceConnection","Connected! Name: " + name.getClassName());// This is the important linemService = IMediaPlaybackService.Stub.asInterface(boundService);// If all went well, now we can use the interface}public void onServiceDisconnected(ComponentName name) {mService = null;Log.i("MediaPlayerServiceConnection", "Disconnected!");}}}
5、这里Service用到aidl(android内部进程通信接口的描述语言)系统自带的IMediaPlaybackService.aidl,里面涵盖了很多种方法可以留给用户调用,包括上面的Provider里面,其实都可已用该aidl来获取到专辑,歌曲,作者信息等等,而不用自己另外写功能去实现;本实例中只用到aidl里面的position()和duration方法,分别时当前进度和总进度;
在src下新建包com.android.music,将music源码里的IMediaPlaybackService.aidl拷贝到该包名下,或者自己新建 名字一样,代码如下:
/* //device/samples/SampleCode/src/com/android/samples/app/RemoteServiceInterface.java**** Copyright 2007, The Android Open Source Project**** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at **** http://www.apache.org/licenses/LICENSE-2.0 **** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License.*/package com.android.music;import android.graphics.Bitmap;interface IMediaPlaybackService{ void openFile(String path); void open(in long [] list, int position); int getQueuePosition(); boolean isPlaying(); void stop(); void pause(); void play(); void prev(); void next(); long duration(); long position(); long seek(long pos); String getTrackName(); String getAlbumName(); long getAlbumId(); String getArtistName(); long getArtistId(); void enqueue(in long [] list, int action); long [] getQueue(); void moveQueueItem(int from, int to); void setQueuePosition(int index); String getPath(); long getAudioId(); void setShuffleMode(int shufflemode); int getShuffleMode(); int removeTracks(int first, int last); int removeTrack(long id); void setRepeatMode(int repeatmode); int getRepeatMode(); int getMediaMountedCount(); int getAudioSessionId();}从代码里不难看出IMediaPlaybackService.aidl相当于一个接口,里面封装好了各种函数可直接调用。
6、对MyMusicProvider当中出现的Broadcast都需要在AndroidManifest.xml当中注册生效:
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.mymusic" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/music_ico" android:label="@string/app_name" android:theme="@style/AppTheme" > <receiver android:name=".MyMusicProvider" > <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE_VIEW" /> <action android:name="com.android.music.playstatechanged" /> <action android:name="com.android.music.metachanged"/> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/mymusic_widget" /> </receiver> <!-- <activity android:name="com.example.mymusic.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> --> </application></manifest>
至此,整个Demo完毕。
- 与系统music同步播放器Demo
- 创建Music播放器demo
- 我的个人Music播放器
- html5写的music播放器
- android源码解析------Music 音乐播放器
- 源码 Music音乐播放器代码结构
- 后台播放music示例
- Android中music播放器源码要点详解【安卓music源码进化一】
- Android中music播放器源码要点详解【安卓music源码进化一】
- RTSP 播放器 demo
- 剖析Android自带Widget-Music播放器
- Android实战 - 音心播放器 (Music Service 实现)
- 享听音乐播放器(Enjoy listening to music player)
- 基于service服务后台运行的music播放器
- asf与vga同步播放
- vga 与 asf 同步播放
- 播放音乐:pygame.mixer.music
- 本地MediaPlayer音乐播放器与歌词同步的实现
- HDU-3191 How Many Paths Are There 次最短路
- C++ new/delete 重载
- Timer
- springMVC中在过滤器中使用spring bean
- Codeforces Round #203 (Div. 2)A
- 与系统music同步播放器Demo
- set -o vi
- win7 隐藏驱动编译于安装
- HDU1853 Cyclic Tour KM算法 模版题
- 利用alias,简化grunt配置文件
- 专业学习小成果
- 近期C程序小结
- android四大组件之 ContentProvider
- 如何做科研