上篇文章中主要分析了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。
下面回到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文件就分析完了,后面会继续分析主控制界面中的四个选项卡控制界面的源码。