我们用了6篇文章的篇幅做了铺垫,终于到了真正的应用程序了。这部分还是一如既往的简单。
有关应用的类有两个,一个是LiryicMain,一个是SelectFileActivity。都是差不多最低限度的内容,没有任何华丽的内容。
先看看这两个类在整个软件中的位置。从图中可以看出LyricMain是软件全体的控制者。SelectFileActivity也为LyricMain提供服务。
SelectFileActivity太过简单,本文中就不再说明了。我们集中篇幅说明一下LyricMain。
首先是数据成员。一个是LyricPlayerServiceProxy,歌词播放服务的代理,一个是用来保存歌词结束位置的List。
- private LyricPlayerServiceProxy mProxy = new LyricPlayerServiceProxy(this);
- private ArrayList<Integer> mLyricEndList = new ArrayList<Integer>();
LyricPlayerServiceProxy是前面已经介绍过的内容,在这里就不在重复了。mLyricEndList需要说明一下。在这个软件中我们将所有歌词都表示在一个TextEditView中,为了能够表示当前播放中的歌词,我们将每一句歌词的位置保存在mLyricEndList中,这样当播放中的歌词发生变化时,只要将这句歌词设为选中状态就可以了。
接下来是LyricMediaInfoProvider的最简单实现,提供了固定的歌名和歌曲文件的位置信息。如果需要切换歌曲,需要再复杂一些。
- private class LyricMediaInfoProvider implements MediaPlayerService.MediaInfoProvider{
- String mUrl;
- String mTitle;
- LyricMediaInfoProvider(String url, String title){
- mUrl = url;
- mTitle = title;
- }
- @Override
- public boolean moveToPrev() {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean moveToNext() {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public String getUrl() {
- return mUrl;
- }
- @Override
- public String getTitle() {
- // TODO Auto-generated method stub
- return mTitle;
- }
- }
接下来是onCreate方法。主要做了几件事
1.建立和LyricPlayerServiceProxy之间的联系。
2.提供了的实现NotificationProvider(详细信息请参照:
)3.设置ImageButton的尺寸。
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mLyricEdit = (EditText)this.findViewById(R.id.editLyric);
- mProxy.setConnectionListener(this);
- mProxy.setLyricPlayerListener(this);
- mProxy.setNotificationProvider(new MediaPlayerService.NotificationProvider(){
- @Override
- public Notification createNotification(Context context) {
- Notification notification = new Notification(R.drawable.button_blue_play, mProxy.getTitle(), System.currentTimeMillis());
- // The PendingIntent to launch our activity if the user selects this notification
- PendingIntent contentIntent = PendingIntent.getActivity(context, 0, new Intent(context, LyricMain.class), 0);
- // Set the info for the views that show in the notification panel.
- notification.setLatestEventInfo(context, getText(R.string.media_player_label), mProxy.getTitle(), contentIntent);
- return notification;
- }
- });
- mProxy.startAndBindService();
- mLyricEndList.clear();
- DisplayMetrics metrics = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(metrics);
- int btnId[] = {R.id.buttonPrev, R.id.buttonStop, R.id.buttonPlay, R.id.buttonPause, R.id.buttonNext};
- int btnSize = Math.min(metrics.widthPixels, metrics.heightPixels) / (btnId.length + 1);
- //调整按键尺寸。
- for(int i = 0; i < btnId.length; ++i){
- ImageButton ib = (ImageButton)this.findViewById(btnId[i]);
- ib.setAdjustViewBounds(true);
- ib.setMaxHeight(btnSize);
- ib.setMaxWidth(btnSize);
- }
- ImageButton selectFile = (ImageButton)this.findViewById(R.id.buttonSelectFile);
- selectFile.setAdjustViewBounds(true);
- selectFile.setMaxHeight(btnSize*2/3);
- selectFile.setMaxWidth(btnSize*2/3);
- updateButtonState();
- }
再下来是onDestroy方法,如果音乐在播放中,就接触和播放服务之间的关系,退出程序,这是歌曲播放会继续。如果播放出于停止或暂停状态,就连同播放服务一起关闭,完全退出程序。
- @Override
- protected void onDestroy() {
- super.onDestroy();
- mProxy.setConnectionListener(null);
- mProxy.setLyricPlayerListener(null);
- if(!mProxy.isPlaying()){
- mProxy.stopService();
- }
- }
启动选择文件的SelectFileActivity
- public void OnSelectFile(View v){
- Intent i = new Intent(this, SelectFileActivity.class);
- startActivityForResult(i, 0);
- }
SelectFileActivity关闭,取得选中的媒体文件的信息并通知的LyricPlayerServiceProxy
接下来是按键处理
- public void OnOperationButtonClick(View v){
- switch(v.getId()){
- case R.id.buttonPrev:
- mProxy.seekToPrevLyric();
- break;
- case R.id.buttonStop:
- if(mProxy.isPlaying() || mProxy.isPausing()){
- mProxy.stop();
- }
- break;
- case R.id.buttonPlay:
- if(!mProxy.isPlaying()){
- mProxy.start();
- }
- break;
- case R.id.buttonPause:
- if(mProxy.isPlaying()){
- mProxy.pause();
- }
- break;
- case R.id.buttonNext:
- mProxy.seekToNextLyric();
- break;
- }
- }
根据播放状态更新各个按键的状态。
- protected void updateButtonState(){
- ((ImageButton)this.findViewById(R.id.buttonPrev)).setEnabled(mProxy.isPlaying() || mProxy.isPausing());
- ((ImageButton)this.findViewById(R.id.buttonStop)).setEnabled(mProxy.isPlaying() || mProxy.isPausing());
- ((ImageButton)this.findViewById(R.id.buttonPlay)).setEnabled(mProxy.getDataSource()!= null && (!mProxy.isPlaying() || mProxy.isPausing()));
- ((ImageButton)this.findViewById(R.id.buttonPause)).setEnabled(mProxy.isPlaying());
- ((ImageButton)this.findViewById(R.id.buttonNext)).setEnabled(mProxy.isPlaying() || mProxy.isPausing());
- }
如果是程序启动时已经有歌曲在播放,就更新一下文件标题和按钮状态。
- //implement of LyricPlayerServiceProxy.ServiceConnectionListener
- public void onServiceConnected(){
- String title = mProxy.getTitle();
- if(title != null){
- TextView tv = (TextView)this.findViewById(R.id.fileTitle);
- tv.setText(title);
- }
- updateButtonState();
- }
- public void onServiceDisconnected(){
- }
实现LyricPlayerListener的代码,负责处理歌词播放服务的各种通知。
- //implement of LyricPlayerService.LyricPlayerListener
- public void onLyricLoaded(){
- mLyricEndList.clear();
- String lyric = new String();
- for(int i = 0; i < mProxy.getLyricCount(); ++i){
- lyric += mProxy.getLyric(i);
- lyric += "\r\n";
- mLyricEndList.add(new Integer(lyric.length()));
- }
- mLyricEdit.setText(lyric);
- }
- public void onStateChanged(){
- updateButtonState();
- }
- public void onPositionChanged(long position){
- }
- public void onLyricChanged(int lyric_index){
- int lyricStart = 0;
- if(lyric_index > 0){
- lyricStart = mLyricEndList.get(lyric_index - 1);
- }
- int lyricEnd = mLyricEndList.get(lyric_index);
- mLyricEdit.setSelection(lyricStart, lyricEnd);
- mLyricEdit.invalidate();
- Log.i(TAG, String.format("lyric= %d, setSelection(%d, %d)", lyric_index, lyricStart, lyricEnd));
- }
在歌词读入时,将所有歌词练成一个长字符串,并记住每一句歌词在字符串中的位置。
在播放服务的状态发生变化时,更新按钮的状态。
在当前歌词发生变化时,根据前面保存的位置信息将当前歌词设置成高亮。
最后是跳到选定歌词的代码,还是一样的简单。
- public void OnLyricClick(View v){
- EditText et = (EditText)v;
- int sel_start = et.getSelectionStart();
- for(int i = 0; i < mLyricEndList.size(); ++i){
- if(sel_start < mLyricEndList.get(i))
- {
- mProxy.seekToLyric(i);
- break;
- }
- }
- }
结合选中的位置,和保存的歌词位置信息,找到歌词的序号,让播放服务跳到那句就行了