前言:最近在开发android8.1的原生音乐播放器,代码路径是vendor\\mediatek\\proprietary\\packages\\apps\\Music;音乐播放器的逻辑比较清晰明了,分析起来也比较简单;

 本节分析是Music的主界面

废话不多说,直接上源码:

MusicBrowserActivity是音乐播放器的主界面,我们来分析一下它的流程:

1.先从onCreate方法开始,进行初始化:

代码1:

public void onCreate(Bundle savedInstanceState) {

//保存savedInstanceState的原因是:当权限请求成功之后,继续进行初始化工作时需要savedInstanceState

mSavedInstanceState = savedInstanceState;

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

//请求权限,权限请求成功之后才会进行初始化工作,权限请求的结果在onRequestPermissionsResult方法中

if (getApplicationContext()

.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)

!= PackageManager.PERMISSION_GRANTED) {

requestMusicPermissions();

mPermissionReqProcessed = false;

} else {

mPermissionReqProcessed = true;

onCreateContinue(mSavedInstanceState);

}

 

//创建通知管理,发送通知需要指定一个管道channel

NotificationManager mgr = (NotificationManager)this.

getSystemService(Context.NOTIFICATION_SERVICE);

mgr.createNotificationChannel(new NotificationChannel(

MUSIC_NOTIFICATION_CHANNEL, \"MUSIC\", NotificationManager.IMPORTANCE_LOW));

}

点评:onCreate的主要工作是请求权限,权限的请求的结果在onRequestPermissionsResult方法中,看这个方法:

代码2:

public void onRequestPermissionsResult(int requestCode,

String permissions[], int[] grantResults) {

if (requestCode == REQUEST_EXTERNAL_STORAGE) {

// If request is cancelled, the result arrays are empty.

if (grantResults.length > 0

&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {

 

mPermissionReqProcessed = true;

//权限请求成功之后,使用mSavedInstanceState继续执行初始化工作

onCreateContinue(mSavedInstanceState);

onResumeContinue();

} else {

//权限请求失败,便直接finish,并toast权限被拒绝

finish();

Toast.makeText(this, R.string.music_storage_permission_deny

, Toast.LENGTH_SHORT).show();

}

}

}

点评:当权限请求成功之后,继续执行初始化操作onCreateContinue();

 

2.继续执行初始化

代码3:

public void onCreateContinue(Bundle savedInstanceState) {

//设置音频流类型

setVolumeControlStream(AudioManager.STREAM_MUSIC);

 

//绑定MediaPlaybackService服务,返回一个ServiceToken对象,Activity通过该ServiceToken与Service进行通信

mToken = MusicUtils.bindToService(this, this);

 

/*判断手机是否存在物理的menu键;

在前面我们看到标签栏里面有5个标签,其中最后一个标签是模拟出来的虚拟的menu键,如果手机存在物理menu键的话,这个虚拟标签就是多于的,需要删掉*/

mHasMenukey = ViewConfiguration.get(this).hasPermanentMenuKey();

 

//LocalActivityManager是把activity转换成view对象的一个api,通过startActivity().getDecorView()方法获取Activity当前Window窗口下的view对象

mActivityManager = new LocalActivityManager(this, false);

mActivityManager.dispatchCreate(savedInstanceState);

 

mTabHost = getTabHost();

 

//初始化标签栏

initTab();

 

//上次退出音乐播放器时的当前标签

mCurrentTab = MusicUtils.getIntPref(this, SAVE_TAB, ARTIST_INDEX);

 

if ((mCurrentTab < 0) || (mCurrentTab >= mTabCount)) {

mCurrentTab = ARTIST_INDEX;

}

//给mTabHost设置默认标签

if (mCurrentTab == ARTIST_INDEX) {

mTabHost.setCurrentTab(ALBUM_INDEX);

}

//设置标签栏中标签变化时的监听,activity重写了onTabChanged方法

mTabHost.setOnTabChangedListener(this);

 

//将音乐,专辑,歌曲,播放列表这四个view添加进mPagers集合

initPager();

 

mViewPager = (ViewPager) findViewById(R.id.viewpage);

//将mPagers中view与mViewPager进行绑定

mViewPager.setAdapter(new MusicPagerAdapter());

//设置mViewPager页面变化的监听,activity重写了onPageSelected方法

mViewPager.setOnPageChangeListener(this);

//mViewPager.setOffscreenPageLimit(VIEW_PAGER_OFFSCREEN_PAGE_NUM);

 

//监听SD卡状态变化的广播,音乐播放器中的音频来源主要是SD卡

IntentFilter f = new IntentFilter();

f.addAction(MusicUtils.SDCARD_STATUS_UPDATE);

registerReceiver(mSdcardstatustListener, f);

 

//当不存在物理menu键时,需要创建假的menu键,本机就需要一个假的menu键

createFakeMenu();

//初始化搜索按钮并设置了搜索按钮的点击事件,该搜索按钮是存在于nowplaying布局当中的

initSearchButton();

}

点评:onCreateContinue()方法主要进行了这些操作:初始化标签栏,初始化ViewPager,初始化虚拟menu键,初始化搜索按钮,接下来详细分析这些初始化操作:

①初始化标签栏,也就是initTab()方法:

代码4:

private void initTab() {

//mPermissionReqProcessed表示权限申请成功

if (mPermissionReqProcessed == true) {

/**标签栏的布局;注意:buttonbar中有6个view,也就是说标签栏中本应该有6个标签,

* 但是由于项目需要,将最后一个标签即虚拟标签给gone掉了,

* 所以我们看到的最多只有5个;它们分别是:音乐,专辑,歌曲,播放列表,正在播放*/

final TabWidget tabWidget =

(TabWidget) getLayoutInflater().inflate(R.layout.buttonbar, null);

//当前屏幕方向

mOrientaiton = getResources().getConfiguration().orientation;

//标签个数,默认是6个

mTabCount = tabWidget.getChildCount();

View tabView;

/**如果存在menu键的话,就将假的menu键去掉;

* 例如本机就没有menu键,它就需要一个虚拟标签,所以标签栏中应有6个标签,前面说了,由于最后一个虚拟标签不可见,其实也就5个*/

if (mHasMenukey) {

mTabCount--;

}

//将标签转换成view,依次将每个view添加进TabHost当中

for (int i = 0; i < mTabCount; i++) {

tabView = tabWidget.getChildAt(0);

if (tabView != null) {

tabWidget.removeView(tabView);

}

//将view添加进TabHost当中

mTabHost.addTab(mTabHost.newTabSpec

(getStringId(i)).setIndicator(tabView).setContent(android.R.id.tabcontent));

}

 

/**如果当前是竖屏的话,由于屏幕限制,需要将第5个标签以及第5个以后的标签都不可见,即竖屏下只能看到4个标签,

* 横屏下可以看到4个以上,看不到的标签就是模拟虚拟按键的那个标签*/

if (mOrientaiton == Configuration.ORIENTATION_PORTRAIT) {

TabWidget tabWidgetTemp = mTabHost.getTabWidget();

for (int i = PLAYBACK_INDEX; i < mTabCount; i++) {

tabView = tabWidgetTemp.getChildTabViewAt(i);

if (tabView != null) {

tabView.setVisibility(View.GONE);

}

}

}

}

点评:在初始化标签栏的时候,要注意竖屏时屏幕宽度的限制以及手机是否有物理menu菜单;

 

②初始化ViewPager:

初始化ViewPager需要分两步,第一步是收集页面,initPager();

代码5:

private void initPager() {

mPagers.clear();

View view = null;

/*getView(i)方法就是前面所说的利用mActivityManager获取Activity当前Window窗口下的view对象,然后将这些view对象添加进mPagers集合;

* 这里是将音乐,专辑,歌曲,播放列表这四个view添加进了集合,正在播放和虚拟菜单的view并没有加进去*/

for (int i = 0; i <= PLAYLIST_INDEX; i++) {

view = (i == mCurrentTab) ? getView(i) : null;

mPagers.add(view);

}

}

我们来看下这个getView(i) :

代码6:

private View getView(int index) {

View view = null;

Intent intent = new Intent(Intent.ACTION_PICK);

switch (index) {

case ARTIST_INDEX:

intent.setDataAndType(Uri.EMPTY, \"vnd.android.cursor.dir/artistalbum\");

break;

case ALBUM_INDEX:

intent.setDataAndType(Uri.EMPTY, \"vnd.android.cursor.dir/album\");

break;

case SONG_INDEX:

intent.setDataAndType(Uri.EMPTY, \"vnd.android.cursor.dir/track\");

break;

case PLAYLIST_INDEX:

intent.setDataAndType(Uri.EMPTY, MediaStore.Audio.Playlists.CONTENT_TYPE);

break;

default:

MusicLogUtils.v(TAG, \"default\");

return null;

}

intent.putExtra(\"withtabs\", true);

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

//获取当前Activity的view

view = mActivityManager.startActivity(getStringId(index), intent).getDecorView();

return view;

}

点评:页面view收集结束了,就需要进行绑定了,也就是调用mViewPager.setAdapter(new MusicPagerAdapter())方法,具体的代码就不展示了,就是将mPagers中view与mViewPager进行绑定;

 

③初始化虚拟menu键,createFakeMenu();

代码7:

private void createFakeMenu() {

if (mPermissionReqProcessed == true) {

//当不存在物理menu键时,才会创建假的menu键

if (mHasMenukey) {

return;

}

 

/*横屏的时候,menu键存在于布局buttonbar中,也就是mOverflowMenuButton在标签栏中;

* 竖屏的时候,menu键存在于布局nowplaying中,布局nowplaying是一个正在播放音乐的view,它在手机屏幕正下方的,类似于一个悬浮框*/

if (mOrientaiton == Configuration.ORIENTATION_LANDSCAPE) {

mOverflowMenuButtonId = R.id.overflow_menu;

mOverflowMenuButton = findViewById(R.id.overflow_menu);

} else {

mOverflowMenuButtonId = R.id.overflow_menu_nowplaying;

mOverflowMenuButton = findViewById(R.id.overflow_menu_nowplaying);

View parent = (View) mOverflowMenuButton.getParent();

if (parent != null) {

parent.setVisibility(View.VISIBLE);

}

}

//mOverflowMenuButton就表示menu键

if(mOverflowMenuButton != null){

mOverflowMenuButton.setVisibility(View.VISIBLE);

//menu键的点击事件

mOverflowMenuButton.set Listener(new View. Listener() {

public void (View v) {

if (v.getId() == mOverflowMenuButtonId) {

//点击menu键,弹出一个PopupMenu的悬浮框

final PopupMenu popupMenu = new PopupMenu(MusicBrowserActivity.this,

mOverflowMenuButton);

mPopupMenu = popupMenu;

final Menu menu = popupMenu.getMenu();

/*给悬浮框PopupMenu设置内容,其实就是添加了4个item和1个搜索按钮,4个item是以文字形式出现,分别是:全部播放,派对随机播放,全部随机播放和音效;

*搜索按钮是一个图标,后面会详细分析*/

onCreateOptionsMenu(menu);

//悬浮框PopupMenu中item的点击事件

popupMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {

public boolean onMenuItemClick(MenuItem item) {

return onOptionsItemSelected(item);

}

});

//悬浮框PopupMenu消失时的监听

popupMenu.setOnDismissListener(new OnDismissListener() {

public void onDismiss(PopupMenu menu) {

mPopupMenuShowing = false;

return;

}

});

//悬浮框PopupMenu显示前的准备工作,也就是设置一些item以及搜索图标在某些特定的情况下可见或者不可见等

onPrepareOptionsMenu(menu);

mPopupMenuShowing = true;

if (popupMenu != null) {

//悬浮框PopupMenu显示

popupMenu.show();

}

}

}

});

}

}

点评:这段代码,主要是给虚拟菜单按键设置点击事件以及添加item内容;我们来看下PopupMenu中item的添加,即onCreateOptionsMenu方法;

代码8:

public boolean onCreateOptionsMenu(Menu menu) {

super.onCreateOptionsMenu(menu);

 

if (mPermissionReqProcessed == true) {

//PLAY_ALL,PARTY_SHUFFLE等字段,是在MusicUtils中定义的静态变量

menu.add(0, PLAY_ALL, 0, R.string.play_all);

menu.add(0, PARTY_SHUFFLE, 0, R.string.party_shuffle);

menu.add(0, SHUFFLE_ALL, 0, R.string.shuffle_all);

menu.add(0, EFFECTS_PANEL, 0, R.string.effects_list_ );

//给menu菜单添加一个搜索图标,mQueryTextListener是搜索框中文字变化时的监听

mSearchItem = MusicUtils.addSearchView(this, menu, mQueryTextListener, null);

}

return true;

}

其中:mQueryTextListener是搜索框中文字变化时的监听,看下它的监听内容是什么?

代码9:

SearchView.OnQueryTextListener mQueryTextListener = new SearchView.OnQueryTextListener() {

public boolean onQueryTextSubmit(String query) {

//当系统搜索框中的文字改变的时候,会跳转到QueryBrowserActivity进行相应的搜索动作

Intent intent = new Intent();

intent.setClass(MusicBrowserActivity.this, QueryBrowserActivity.class);

intent.putExtra(SearchManager.QUERY, query);

startActivity(intent);

return true;

}

 

public boolean onQueryTextChange(String newText) {

return false;

}

};

给虚拟菜单设置内容的时候,还见到onOptionsItemSelected()和onPrepareOptionsMenu(),它们分别是菜单中item选项的点击操作以及菜单显示前的准备工作,看下代码:

代码10:

public boolean onOptionsItemSelected(MenuItem item) {

Cursor cursor;

Intent intent;

//点击菜单按钮中的item

switch (item.getItemId()) {

//全部播放

case PLAY_ALL:

cursor = MusicUtils.query(this,

MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,

new String[] { MediaStore.Audio.Media._ID },

MediaStore.Audio.Media.IS_MUSIC + \"=1\",

null,

/// M: add for chinese sorting

MediaStore.Audio.Media.DEFAULT_SORT_ORDER);

if (cursor != null) {

MusicUtils.playAll(this, cursor);

cursor.close();

}

 

//派对随机播放

case PARTY_SHUFFLE:

MusicUtils.togglePartyShuffle();

return true;

 

//全部随机播放

case SHUFFLE_ALL:

cursor = MusicUtils.query(this,

MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,

new String[] { MediaStore.Audio.Media._ID },

MediaStore.Audio.Media.IS_MUSIC + \"=1\",

null,

/// M: add for chinese sorting

MediaStore.Audio.Media.DEFAULT_SORT_ORDER);

if (cursor != null) {

MusicUtils.shuffleAll(this, cursor);

cursor.close();

}

return true;

 

//音效

case EFFECTS_PANEL:

return MusicUtils.startEffectPanel(this);

 

//搜索按钮

case R.id.search:

onSearchRequested();

mSearchViewShowing = true;

return true;

 

default:

break;

}

return super.onOptionsItemSelected(item);

}

 

代码11:

public boolean onPrepareOptionsMenu(Menu menu) {

MusicUtils.setPartyShuffleMenuIcon(menu);

super.onPrepareOptionsMenu(menu);

if (mPermissionReqProcessed == true) {

//没有安装SD卡

if (!mIsSdcardMounted) {

return false;

}

//\"全部播放\"item只能在\"歌曲\"界面显示

menu.findItem(PLAY_ALL).setVisible(mCurrentTab == SONG_INDEX);

//\"全部随机播放\"item不能在\"播放列表界面\"显示

menu.findItem(SHUFFLE_ALL).setVisible(mCurrentTab != PLAYLIST_INDEX);

//\"音效\"item只能在音效功能有用的时候才会显示

MusicUtils.setEffectPanelMenu(getApplicationContext(), menu);

//搜索按钮只在横屏状态下才显示

mSearchItem.setVisible(mOrientaiton == Configuration.ORIENTATION_LANDSCAPE);

}

return true;

}

 

④初始化搜索按钮, initSearchButton();

代码12:

private void initSearchButton() {

mSearchButton = (ImageButton) findViewById(R.id.search_menu_nowplaying);

//blankView是搜索按钮和菜单按钮之间的空格部分

final View blankView = this.findViewById(R.id.blank_between_search_and_overflow);

final View nowPlayingView = this.findViewById(R.id.nowplaying);

if (mSearchButton != null) {

//搜索按钮的点击事件

mSearchButton.set Listener(new View. Listener() {

@Override

public void (View v) {

if (mOverflowMenuButton != null) {

mOverflowMenuButton.setEnabled(false);

}

//一旦点击了搜索按钮,搜索按钮就需要被隐藏,因为此时会调用系统的搜索框

mSearchButton.setVisibility(View.GONE);

//调用Activity的onSearchRequested方法,该方法会弹出系统的搜索框

onSearchRequested();

if (blankView.getVisibility() == View.VISIBLE) {

blankView.setVisibility(View.GONE);

}

//mSearchViewShowing表示系统搜索框的显示与否

mSearchViewShowing = true;

}

});

 

//系统搜索运用了SearchManager中的逻辑

SearchManager searchManager = (SearchManager) this

.getSystemService(Context.SEARCH_SERVICE);

//系统搜索框消失时的监听

searchManager.setOnDismissListener(new SearchManager.OnDismissListener() {

@Override

public void onDismiss() {

if (mOverflowMenuButton != null) {

mOverflowMenuButton.setEnabled(true);

}

//系统搜索框消失时,搜索按钮由隐藏状态转变为可见状态

mSearchButton.setVisibility(View.VISIBLE);

if (nowPlayingView.getVisibility() != View.VISIBLE && !mHasMenukey) {

blankView.setVisibility(View.VISIBLE);

}

mSearchViewShowing = false;

 

InputMethodManager imm = (InputMethodManager)

getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);

if (imm != null) {

MusicLogUtils.v(TAG, \"IIME getService failed\");

}

MusicLogUtils.v(TAG, \"IME getService success\");

//隐藏输入法

if (imm != null) {

MusicLogUtils.v(TAG, \"Search Dialog hiding the IME\");

imm.hideSoftInputFromWindow(mSearchButton.getWindowToken(), 0);

}

}

});

}

}

}

点评:分析完了onCreate中的初始化动作,MusicBrowserActivity的核心代码也差不多分析完了,再看一下其他的也是比较重要的代码;

 

3.activity的生命周期;

刚才已经分析完了activity的oncrate周期,接着看一下其他的生命周期;

代码13:

public void onResume() {

super.onResume();

if (mPermissionReqProcessed == true) {

onResumeContinue();

}

}

 

public void onResumeContinue() {

IntentFilter f = new IntentFilter();

//监听音乐播放状态的广播

f.addAction(MediaPlaybackService. _CHANGED);

registerReceiver(mTrackListListener, f);

mTabHost.setCurrentTab(mCurrentTab);

mActivityManager.dispatchResume();

}

 

private BroadcastReceiver mTrackListListener = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

if (mService != null) {

//监听音乐播放状态的广播,当音乐状态改变时,改变nowPlaying的布局的可见性以及\"正在播放\"标签,当没有正在播放的音乐时,正在播放\"标签不可点击

MusicUtils.updateNowPlaying(MusicBrowserActivity.this, mOrientaiton);

updatePlaybackTab();

}

}

};

 

 

public void onPause() {

super.onPause();

if (mPermissionReqProcessed == true) {

unregisterReceiver(mTrackListListener);

mActivityManager.dispatchPause(false);

//activity不可见时,保存当前的标签,供下次activity显示时使用

MusicUtils.setIntPref(this, SAVE_TAB, mCurrentTab);

}

 

public void () {

if (mPermissionReqProcessed == true) {

//activity后台不可见时,悬浮框mPopupMenu也会消失

if (mPopupMenu != null) {

mPopupMenu.dismiss();

mPopupMenuShowing = false;

}

mActivityManager.dispatchStop();

}

super. ();

}

 

public void onDestroy() {

if (mPermissionReqProcessed == true) {

if (mToken != null) {

//activity销毁时与服务解绑

MusicUtils.unbindFromService(mToken);

mService = null;

}

unregisterReceiver(mSdcardstatustListener);

mActivityManager.dispatchDestroy(false);

}

super.onDestroy();

}

 

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

if (mPermissionReqProcessed == true) {

int startActivityTab = mCurrentTab;

if (data != null) {

startActivityTab = data.getIntExtra(MusicUtils.START_ACTIVITY_TAB_ID, mCurrentTab);

}

Activity startActivity = mActivityManager.getActivity(getStringId(startActivityTab));

if (startActivity == null) {

return;

}

//activity的跳转结果会派发给相应的页面activity去执行

switch (startActivityTab) {

case ARTIST_INDEX:

((ArtistAlbumBrowserActivity) startActivity).onActivityResult(requestCode,

resultCode,

data);

break;

 

case ALBUM_INDEX:

((AlbumBrowserActivity) startActivity).onActivityResult(requestCode,

resultCode,

data);

break;

 

case SONG_INDEX:

((TrackBrowserActivity) startActivity).onActivityResult(requestCode,

resultCode,

data);

break;

 

case PLAYLIST_INDEX:

((PlaylistBrowserActivity) startActivity).onActivityResult(requestCode,

resultCode,

data);

break;

 

default:

break;

}

}

}

 

public void onConfigurati d(Configuration newConfig) {

super.onConfigurati d(newConfig);

//当系统配置改变的时候,需要进行一些处理,比如横竖屏

if (mPermissionReqProcessed == true) {

TabWidget tabWidgetTemp = mTabHost.getTabWidget();

View tabView;

Activity activity;

int viewStatusForTab = View.GONE;

 

//此时是横屏

if (mOrientaiton == Configuration.ORIENTATION_LANDSCAPE) {

viewStatusForTab = View.VISIBLE;

}

//标签栏中的\"正在播放\"以及\"虚拟menu\"标签由不可见变为可见状态

for (int i = PLAYBACK_INDEX; i < mTabCount; i++) {

tabView = tabWidgetTemp.getChildTabViewAt(i);

if (tabView != null) {

tabView.setVisibility(viewStatusForTab);

}

}

 

for (int i = 0; i < PLAYBACK_INDEX; i++) {

activity = mActivityManager.getActivity(getStringId(i));

if (activity != null) {

//通知\"正在播放\"以及\"虚拟menu\"页面系统配置已经发生了改变

activity.onConfigurati d(newConfig);

}

}

if (!mHasMenukey) {

boolean popupMenuShowing = mPopupMenuShowing;

/*如果此时悬浮框popupMenu是正在显示的状态,需要先将popupMenu隐藏*/

if (popupMenuShowing && mPopupMenu != null) {

mPopupMenu.dismiss();

}

//重新加载虚拟menu键

createFakeMenu();

if (!mSearchViewShowing && mOverflowMenuButton != null) {

mOverflowMenuButton.setEnabled(true);

}

 

/*在横竖屏状态改变之前,如果悬浮框popupMenu已经显示出来了,那么在横竖屏状态改变之后,悬浮框popupMenu还需要继续显示;

* 这里是模拟了菜单按键的点击事件达到了悬浮框popupMenu继续显示的效果*/

if (popupMenuShowing && mOverflowMenuButton != null) {

mOverflowMenuButton.setSoundEffectsEnabled(false);

mOverflowMenuButton.performClick();

mOverflowMenuButton.setSoundEffectsEnabled(true);

}

}

if (mService != null) {

//根据系统显示框的显示与否来更新搜索按钮的状态

if (mSearchViewShowing) {

mSearchButton.setVisibility(View.GONE);

} else {

mSearchButton.setVisibility(View.VISIBLE);

}

//更新屏幕正下方的nowplaying布局的可见性

MusicUtils.updateNowPlaying(MusicBrowserActivity.this, mOrientaiton);

//更新标签栏中\"正在播放\"标签的图标,以及当没有正在播放的音乐时,正在播放\"标签不可点击

updatePlaybackTab();

}

 

//重新设置标签栏和viewpager

mTabHost.setCurrentTab(mCurrentTab);

mViewPager.setAdapter(new MusicPagerAdapter());

onTabChanged(getStringId(mCurrentTab));

}

}

 

4.接下来是三个监听;

①绑定服务成功的监听

public void onServiceConnected(ComponentName className, IBinder service) {

if (mPermissionReqProcessed == true) {

//与MediaPlaybackService进行绑定

mService = IMediaPlaybackService.Stub.asInterface(service);

String shuf = getIntent().getStringExtra(\"autoshuffle\");

if (mService != null) {

if (Boolean.valueOf(shuf).booleanValue()) {

try {

//设置音乐播放的音效,默认是自动

mService.setShuffleMode(MediaPlaybackService.SHUFFLE_AUTO);

}

catch (RemoteException ex) {

}

}

//更新nowPlaying布局,没有正在播放的音乐时nowPlaying会不可见,playbackTab会不可点击

MusicUtils.updateNowPlaying(MusicBrowserActivity.this, mOrientaiton);

updatePlaybackTab();

}

}

}

 

public void onServiceDisconnected(ComponentName className) {

if (mPermissionReqProcessed == true) {

mService = null;

finish();

}

}

 

②标签栏中的标签发生了点击变化后的监听

public void onTabChanged(String tabId) {

//当标签栏中的标签发生了点击变化后,会通知ViewPager发生改变,由ViewPager去处理;除了\"正在播放\"和\"菜单\"标签;

// \"正在播放\"标签会直接跳转至MediaPlaybackActivity,而\"菜单\"标签在这里不做处理*/

int tabIndex = TAB_MAP.get(tabId);

if ((tabIndex >= ARTIST_INDEX) && (tabIndex <= PLAYLIST_INDEX)) {

//ARTIST_INDEX <= tabIndex <= PLAYLIST_INDEX,也就是只处理前4个标签

mViewPager.setCurrentItem(tabIndex);

mCurrentTab = tabIndex;

//\"正在播放\"标签

Intent intent = new Intent(this, MediaPlaybackActivity.class);

startActivity(intent);

}

}

 

③iewpager发生改变后的监听

public void onPageSelected(int position) {

MusicLogUtils.v(TAG, \"onPageSelected-position:\" + position);

//viewpager发生改变时通知标签栏

mTabHost.setCurrentTab(position);

}

 

 

收藏 打印