我们用了6篇文章的篇幅做了铺垫,终于到了真正的应用程序了。这部分还是一如既往的简单。

有关应用的类有两个,一个是LiryicMain,一个是SelectFileActivity。都是差不多最低限度的内容,没有任何华丽的内容。

先看看这两个类在整个软件中的位置。从图中可以看出LyricMain是软件全体的控制者。SelectFileActivity也为LyricMain提供服务。

SelectFileActivity太过简单,本文中就不再说明了。我们集中篇幅说明一下LyricMain。

首先是数据成员。一个是LyricPlayerServiceProxy,歌词播放服务的代理,一个是用来保存歌词结束位置的List。

  1. private LyricPlayerServiceProxy mProxy = new LyricPlayerServiceProxy(this);
  2. private ArrayList<Integer> mLyricEndList = new ArrayList<Integer>();

LyricPlayerServiceProxy是前面已经介绍过的内容,在这里就不在重复了。mLyricEndList需要说明一下。在这个软件中我们将所有歌词都表示在一个TextEditView中,为了能够表示当前播放中的歌词,我们将每一句歌词的位置保存在mLyricEndList中,这样当播放中的歌词发生变化时,只要将这句歌词设为选中状态就可以了。

接下来是LyricMediaInfoProvider的最简单实现,提供了固定的歌名和歌曲文件的位置信息。如果需要切换歌曲,需要再复杂一些。

  1. private class LyricMediaInfoProvider implements MediaPlayerService.MediaInfoProvider{
  2. String mUrl;
  3. String mTitle;
  4. LyricMediaInfoProvider(String url, String title){
  5. mUrl = url;
  6. mTitle = title;
  7. }
  8. @Override
  9. public boolean moveToPrev() {
  10. // TODO Auto-generated method stub
  11. return false;
  12. }
  13. @Override
  14. public boolean moveToNext() {
  15. // TODO Auto-generated method stub
  16. return false;
  17. }
  18. @Override
  19. public String getUrl() {
  20. return mUrl;
  21. }
  22. @Override
  23. public String getTitle() {
  24. // TODO Auto-generated method stub
  25. return mTitle;
  26. }
  27. }

接下来是onCreate方法。主要做了几件事

1.建立和LyricPlayerServiceProxy之间的联系。

2.提供了的实现NotificationProvider(详细信息请参照: Android歌词秀设计思路(4)通用的音乐播放服务(下) )

3.设置ImageButton的尺寸。

  1. /** Called when the activity is first created. */
  2. @Override
  3. public void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.main);
  6. mLyricEdit = (EditText)this.findViewById(R.id.editLyric);
  7. mProxy.setConnectionListener(this);
  8. mProxy.setLyricPlayerListener(this);
  9. mProxy.setNotificationProvider(new MediaPlayerService.NotificationProvider(){
  10. @Override
  11. public Notification createNotification(Context context) {
  12. Notification notification = new Notification(R.drawable.button_blue_play, mProxy.getTitle(), System.currentTimeMillis());
  13. // The PendingIntent to launch our activity if the user selects this notification
  14. PendingIntent contentIntent = PendingIntent.getActivity(context, 0, new Intent(context, LyricMain.class), 0);
  15. // Set the info for the views that show in the notification panel.
  16. notification.setLatestEventInfo(context, getText(R.string.media_player_label), mProxy.getTitle(), contentIntent);
  17. return notification;
  18. }
  19. });
  20. mProxy.startAndBindService();
  21. mLyricEndList.clear();
  22. DisplayMetrics metrics = new DisplayMetrics();
  23. getWindowManager().getDefaultDisplay().getMetrics(metrics);
  24. int btnId[] = {R.id.buttonPrev, R.id.buttonStop, R.id.buttonPlay, R.id.buttonPause, R.id.buttonNext};
  25. int btnSize = Math.min(metrics.widthPixels, metrics.heightPixels) / (btnId.length + 1);
  26. //调整按键尺寸。
  27. for(int i = 0; i < btnId.length; ++i){
  28. ImageButton ib = (ImageButton)this.findViewById(btnId[i]);
  29. ib.setAdjustViewBounds(true);
  30. ib.setMaxHeight(btnSize);
  31. ib.setMaxWidth(btnSize);
  32. }
  33. ImageButton selectFile = (ImageButton)this.findViewById(R.id.buttonSelectFile);
  34. selectFile.setAdjustViewBounds(true);
  35. selectFile.setMaxHeight(btnSize*2/3);
  36. selectFile.setMaxWidth(btnSize*2/3);
  37. updateButtonState();
  38. }

再下来是onDestroy方法,如果音乐在播放中,就接触和播放服务之间的关系,退出程序,这是歌曲播放会继续。如果播放出于停止或暂停状态,就连同播放服务一起关闭,完全退出程序。

  1. @Override
  2. protected void onDestroy() {
  3. super.onDestroy();
  4. mProxy.setConnectionListener(null);
  5. mProxy.setLyricPlayerListener(null);
  6. if(!mProxy.isPlaying()){
  7. mProxy.stopService();
  8. }
  9. }

启动选择文件的SelectFileActivity

  1. public void OnSelectFile(View v){
  2. Intent i = new Intent(this, SelectFileActivity.class);
  3. startActivityForResult(i, 0);
  4. }

SelectFileActivity关闭,取得选中的媒体文件的信息并通知的LyricPlayerServiceProxy

接下来是按键处理

  1. public void OnOperationButtonClick(View v){
  2. switch(v.getId()){
  3. case R.id.buttonPrev:
  4. mProxy.seekToPrevLyric();
  5. break;
  6. case R.id.buttonStop:
  7. if(mProxy.isPlaying() || mProxy.isPausing()){
  8. mProxy.stop();
  9. }
  10. break;
  11. case R.id.buttonPlay:
  12. if(!mProxy.isPlaying()){
  13. mProxy.start();
  14. }
  15. break;
  16. case R.id.buttonPause:
  17. if(mProxy.isPlaying()){
  18. mProxy.pause();
  19. }
  20. break;
  21. case R.id.buttonNext:
  22. mProxy.seekToNextLyric();
  23. break;
  24. }
  25. }

根据播放状态更新各个按键的状态。

  1. protected void updateButtonState(){
  2. ((ImageButton)this.findViewById(R.id.buttonPrev)).setEnabled(mProxy.isPlaying() || mProxy.isPausing());
  3. ((ImageButton)this.findViewById(R.id.buttonStop)).setEnabled(mProxy.isPlaying() || mProxy.isPausing());
  4. ((ImageButton)this.findViewById(R.id.buttonPlay)).setEnabled(mProxy.getDataSource()!= null && (!mProxy.isPlaying() || mProxy.isPausing()));
  5. ((ImageButton)this.findViewById(R.id.buttonPause)).setEnabled(mProxy.isPlaying());
  6. ((ImageButton)this.findViewById(R.id.buttonNext)).setEnabled(mProxy.isPlaying() || mProxy.isPausing());
  7. }

如果是程序启动时已经有歌曲在播放,就更新一下文件标题和按钮状态。

  1. //implement of LyricPlayerServiceProxy.ServiceConnectionListener
  2. public void onServiceConnected(){
  3. String title = mProxy.getTitle();
  4. if(title != null){
  5. TextView tv = (TextView)this.findViewById(R.id.fileTitle);
  6. tv.setText(title);
  7. }
  8. updateButtonState();
  9. }
  10. public void onServiceDisconnected(){
  11. }

实现LyricPlayerListener的代码,负责处理歌词播放服务的各种通知。

  1. //implement of LyricPlayerService.LyricPlayerListener
  2. public void onLyricLoaded(){
  3. mLyricEndList.clear();
  4. String lyric = new String();
  5. for(int i = 0; i < mProxy.getLyricCount(); ++i){
  6. lyric += mProxy.getLyric(i);
  7. lyric += "\r\n";
  8. mLyricEndList.add(new Integer(lyric.length()));
  9. }
  10. mLyricEdit.setText(lyric);
  11. }
  12. public void onStateChanged(){
  13. updateButtonState();
  14. }
  15. public void onPositionChanged(long position){
  16. }
  17. public void onLyricChanged(int lyric_index){
  18. int lyricStart = 0;
  19. if(lyric_index > 0){
  20. lyricStart = mLyricEndList.get(lyric_index - 1);
  21. }
  22. int lyricEnd = mLyricEndList.get(lyric_index);
  23. mLyricEdit.setSelection(lyricStart, lyricEnd);
  24. mLyricEdit.invalidate();
  25. Log.i(TAG, String.format("lyric= %d, setSelection(%d, %d)", lyric_index, lyricStart, lyricEnd));
  26. }

在歌词读入时,将所有歌词练成一个长字符串,并记住每一句歌词在字符串中的位置。

在播放服务的状态发生变化时,更新按钮的状态。

在当前歌词发生变化时,根据前面保存的位置信息将当前歌词设置成高亮。

最后是跳到选定歌词的代码,还是一样的简单。

  1. public void OnLyricClick(View v){
  2. EditText et = (EditText)v;
  3. int sel_start = et.getSelectionStart();
  4. for(int i = 0; i < mLyricEndList.size(); ++i){
  5. if(sel_start < mLyricEndList.get(i))
  6. {
  7. mProxy.seekToLyric(i);
  8. break;
  9. }
  10. }
  11. }

结合选中的位置,和保存的歌词位置信息,找到歌词的序号,让播放服务跳到那句就行了。

转载于:https://blog.51cto.com/craftsman1970/667904

Android歌词秀设计思路(7)水到渠成相关推荐

  1. Android歌词秀设计思路(8)后记

    写下这篇博文的时候,访问量的总数刚好过2000次,先自己庆祝一下. 做程序已经十八九年,但是写文章介绍自己的程序还是第一次.是实话这件事的难度超出了我的预想. 一个是篇幅长,原先以为很简单的一个程序, ...

  2. Android歌词秀设计思路(2)歌词处理

    这次的内容是歌词处理模块LyricAdapter类.这个类的主要功能有 1.歌词文件的解析 2.对外提供歌词访问服务(歌词数取得,歌词内容,时间的取得等) 3.根据播放位置检索对应的歌词. 4.在歌词 ...

  3. Android歌词秀设计思路(6)运用Proxy设计模式简化歌词播放服务的使用

    开始开发歌词秀的时候还是夏天,没有想到写这篇文章的时候大连已经迎来的今年的第一次大规模降温.多少有点冬天的感觉了. 上一篇文章我们已经介绍了,带有歌词播放功能的服务,按说接下来就该是利用歌词播放服务的 ...

  4. android 歌词点击播放,Android歌词秀设计思路(5)歌词播放服务

    接下来说明一下,提供歌词播放器服务的LyricPlayerService.这个类在整个播放过程中的作用是 1.负责管理LyricAdapter的生命周期. 2.控制音乐播放,歌词解析,并且协调音乐与歌 ...

  5. android 歌词解析时间,Android歌词秀设计思路(1)SafetyTimer

    Android中使用Timer时需要同时访问TimerTask,Handle等类,手续繁杂而且是真正想做的事淹没在手续化的代码中.本文介绍了的SafetyTimer类隐藏了TimerTask,Hand ...

  6. Android歌词秀设计思路(3)通用的音乐播放服务(上)

    MediaPlayerService作为通用的音乐播放Service类,它的功能有: 控制音乐播放,停止,暂停,前/后歌曲切换. Audio Focus相关处理(对应应用程序切换). Intent处理 ...

  7. Android歌词秀设计思路歌词播放服务

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://craftsman1970.blog.51cto.com/3522772/6627 ...

  8. Andorid歌词秀设计思路(1)SafetyTimer

    在Android中实现多媒体播放功能主要是通过MediaPlayer实现的.为了方便用户检测MediaPlayer的动作状态,Andorid为我们提供了一下接口 Nested Classes inte ...

  9. Android歌词秀1.5版

    功能简介: 0.本软件可以在Android2.1以上(2.1,2.2,2.3测试通过)执行. 1.自动读取与音乐相同位置的歌词文件. 2.根据播放进度,表示当前的歌词 3.按歌词语句快进,快退. 5. ...

最新文章

  1. Java虚拟机的研究与实现
  2. Codechef SEAARC Sereja and Arcs (分块、组合计数)
  3. 插入排序法算长度为10的数组
  4. html怎么改变一块区域颜色,更改HTML中所选区域的背景颜色/不透明度
  5. (五十九)iOS网络基础之UIWebView简易浏览器实现
  6. saas是什么意思_为什么越来越多的人选择SaaS模式的crm客户管理系统?
  7. 我对计算机感兴趣作文300字,我想对电脑游戏说作文300字
  8. mysql rs.next_JDBC结果集rs.next()注意事项
  9. 我在售的12部图书简介及网上链接
  10. 多个物体轮廓c语言提取算法,C++ opencv-3.4.1 提取不规则物体的轮廓
  11. linux 添加软连接、查看软连接、增加文件的执行权限
  12. 新手菜鸟防***必备知识
  13. 网页自动填表html,风越网页表单批量自动填写工具
  14. 达梦数据库DM8同步到KAFKA的部署方法
  15. target is not existed: .page-component__scroll .el-scrollbar__wrap
  16. 集成支付宝支付(AliPay)详解,防跳坑
  17. 打开FTP服务器上的文件夹时发生错误。请检查是否有权限访问该文件夹
  18. 基于JavaWeb三层架构的OA管理系统
  19. 工欲善其事必先利其器——Elasticsearch安装
  20. 串口服务器 文档,MOXA串口服务器产品配置说明.pdf

热门文章

  1. 管理系统中计算机应用试题及答案,自考管理系统中计算机应用试题及答案
  2. strace命令工具安装
  3. SPL - QQ空间日志查看工具 v1.1.0.441
  4. springboot+vue实现分页操作
  5. 马斯克OpenAI实验室的17岁高中生
  6. 如何拍背景虚化的照片_如何拍摄背景虚化照片?
  7. 实例:函数定义来计算面积,体积
  8. POJ简单题3094 Quicksum
  9. Paper Reading||PROFIT: A Novel Training Method for sub-4-bit MobileNet Models
  10. 磁盘分区软件排名:来自各软件下载平台的数据