与系统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完毕。

原创粉丝点击