Android 原生音乐播放器Music源码分析之二

上篇文章中主要分析了Music的Android.mk文件以及根据AndroidManifest.xml文件介绍了Music涉及到的大部分组件框架。本文开始重点分析java源码。

从Music的应用入口MusicBrowserActivity.java文件开始分析,源代码文件位于packages/apps/Music/src/com/android/music/目录下。

首先看一下它的onCreate()函数,看看都做了些什么。

37    /**
38     * Called when the activity is first created.
39     */
40    @Override
41    public void onCreate(Bundle icicle) {
42        super.onCreate(icicle);
43        int activeTab = MusicUtils.getIntPref(this, "activetab", R.id.artisttab);
44        if (activeTab != R.id.artisttab
45                && activeTab != R.id.albumtab
46                && activeTab != R.id.songtab
47                && activeTab != R.id.playlisttab) {
48            activeTab = R.id.artisttab; /*第一次进入该应用时,默认打开的选项卡界面为artist选项卡界面*/
49        }
50        MusicUtils.activateTab(this, activeTab);
51
52        String shuf = getIntent().getStringExtra("autoshuffle");
53        if ("true".equals(shuf)) {
54            mToken = MusicUtils.bindToService(this, autoshuffle);
55        }
56    }
在onCreate()方法中首先通过MusicUtils的getIntPref函数从com.android.music.xml(该文件是上次最后一次打开音乐管理器时,通过sharedPreferences存储的)获取需要打开的选项卡界面对应的id,关于MusicUtils的getIntPref函数逻辑,这里不再贴出代码,感兴趣的读者可以自己去查看。

1205    static void activateTab(Activity a, int id) {
1206        Intent intent = new Intent(Intent.ACTION_PICK);
1207        switch (id) {
1208            case R.id.artisttab:
1209                intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/artistalbum");
1210                break;
1211            case R.id.albumtab:
1212                intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/album");
1213                break;
1214            case R.id.songtab:
1215                intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
1216                break;
1217            case R.id.playlisttab:
1218                intent.setDataAndType(Uri.EMPTY, MediaStore.Audio.Playlists.CONTENT_TYPE);
1219                break;
1220            case R.id.nowplayingtab:
1221                intent = new Intent(a, MediaPlaybackActivity.class);
1222                a.startActivity(intent);/*该activity是一个全屏activity,不需要结束掉当前的activity,也不用设计切换动画,所以直接return*/
1223                // fall through and return
1224            default:
1225                return;
1226        }
1227        intent.putExtra("withtabs", true);
1228        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1229        a.startActivity(intent);/*启动相应activity*/
1230        a.finish(); /*结束掉当前activity*/
1231        a.overridePendingTransition(0, 0);/*activity的切换动画*/
1232    }
获取所需打开选项卡界面对应的id后,接着调用MusicUtils类的activateTab方法去激活相应的activity来呈现给用户相应的界面,代码位于 packages/apps/Music/src/com/android/music/MusicUtils.java

根据id找到相应的字符串,启动intent,如:

          case R.id.albumtab:
               intent.setDataAndType(Uri.EMPTY,"vnd.android.cursor.dir/album");
               break;


系统会自动根据字符串“vnd.android.cursor.dir/album”去AndroidManifest.xml中寻找匹配的activity,专辑的activity为AlbumBrowserActivity.java。
启动相应activity后结束掉当前activity 即MusicBrowserActivity。

下面回到MusicBrowserActivity的onCreate()函数,接下来读取所获得的intent的key “autoshuffle”所传过来的字符串,

52        String shuf = getIntent().getStringExtra("autoshuffle");
53        if ("true".equals(shuf)) {
54            mToken = MusicUtils.bindToService(this, autoshuffle);
55        }
如果该字符串为"true",就调用MusicUtils的bindToService方法去绑定服务。autoshuffle 是用来回调的ServiceConnection,定义如下

66    private ServiceConnection autoshuffle = new ServiceConnection() {
67        public void onServiceConnected(ComponentName classname, IBinder obj) {
68            // we need to be able to bind again, so unbind
69            try {
70                unbindService(this);
71            } catch (IllegalArgumentException e) {
72            }
73            IMediaPlaybackService serv = IMediaPlaybackService.Stub.asInterface(obj);/*获取播放服务MediaPlaybackService接口对象*/
74            if (serv != null) {
75                try {
76                    serv.setShuffleMode(MediaPlaybackService.SHUFFLE_AUTO);/*设置播放服务的模式为自动*/
77                } catch (RemoteException ex) {
78                }
79            }
80        }
81
82        public void onServiceDisconnected(ComponentName classname) {
83        }
84    };
接下来分析MusicUtils的bindToService方法

167    public static ServiceToken bindToService(Activity context, ServiceConnection callback) {
168        Activity realActivity = context.getParent();
169        if (realActivity == null) {
170            realActivity = context;
171        }
172        ContextWrapper cw = new ContextWrapper(realActivity);
173        cw.startService(new Intent(cw, MediaPlaybackService.class)); /*启动MediaPlaybackService服务*/
174        ServiceBinder sb = new ServiceBinder(callback);/*创建一个serviceBinder对象实例*/
175        if (cw.bindService((new Intent()).setClass(cw, MediaPlaybackService.class), sb, 0)) { /*bind MediaPlayBackService*/
176            sConnectionMap.put(cw, sb);
177            return new ServiceToken(cw);
178        }
179        Log.e("Music", "Failed to bind to service");
180        return null;
181    }
在bindToService方法中会启动播放服务MediaPlaybackService,然后根据autoshuffle这个回调serviceConnection创建一个ServiceBinder实例,ServiceBinder类也实现了serviceConnection接口,在后面与MediaPlaybackService绑定的过程中会回调其onServiceConnection方法。

如果当前activity即MusicBrowserActivity与MediaPlaybackService成功绑定,则将刚才创建的ServiceBinder实例放到serviceConnectionMap(存放当前activity成功绑定的服务),然后返回一个ServiceToken对象。

至此,MediaPlaybackService 已经起来,MusicBrowserActivity与 MediaPlaybackService也已绑定,后面就可以调用MediaPlaybackService的各种方法了。在Activity 消失时可以解除与MediaPlaybackService的绑定。

58    @Override
59    public void onDestroy() {
60        if (mToken != null) {
61            MusicUtils.unbindFromService(mToken);/*解除与MediaPlaybackService的绑定*/
62        }
63        super.onDestroy();
64    }
在MusicBrowserActivity的onDestroy方法中根据刚才返回的serviceToken对象,解除与MediaPlaybackService的绑定。

这样整个MusicBrowserActivit.java文件就分析完了,后面会继续分析主控制界面中的四个选项卡控制界面的源码。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值