【android】音乐播放器之设计思路
学习Android有一个多月,看完了《第一行代码》以及mars老师的第一期视频通过音乐播放器小项目加深对知识点的理解。从本文开始,将详细的介绍简单仿多米音乐播放器的实现,以及网络解析数据获取百度音乐最新排行音乐以及下载功能。
功能介绍如下:
1、获取本地歌曲列表,实现歌曲播放功能。
2、利用jsoup解析网页数据,从网络获取歌曲列表,同时实现歌曲和歌词下载到手机本地的功能。
3、通知栏提醒,实现仿QQ音乐播放器的通知栏功能.
涉及的技术有:
1、jsoup解析网络网页,从而获取需要的数据
2、android中访问网络,获取文件到本地的网络请求技术,以及下载文件到本地实现断点下载
3、线程池
4、图片缓存
5、service一直在后台运行
6、Activity与Fragment间的切换以及通信
7、notification通知栏设计
8、自定义广播
9、android系统文件管
该播放器详细设计参考下面博文:
UI设计部分见: 【android】音乐播放器之UI设计的点点滴滴
Service服务设i:【android】音乐播放器之service服务设计
数据存储技术的运用见: 【android】音乐播放器之数据存储总结
下面是最终结果展示:
图一主界面以及本地音乐列表
图二: 在本地列表中长按菜单键可以弹出功能选择键,短按listview中的歌曲列表跳转到播放列表,长按listview中的个人去items可以歌曲的删除。
上面两幅图都关于网络列表:按listview中的歌曲items可以实现下载功能
播放界面了~!~我还是比较喜欢这个播放界面的,仿QQ音乐播放界面风格。通过左右滑动可以实现播放歌曲当前的的图片到播放歌曲歌词显示的切换
上面这两幅图分别为下载时和播放歌曲时候通知栏的显示,其余的小功能就不一一展示。如果感兴趣可以下载代码编也好改也好随你便吧,~!~hahahha!!!
这边文章主要讲讲大致的设计思路~~~~~~。
还是先谈谈service服务吧,音乐播放器用到了两个service服务:PlayService和DownLoadService。PlayService主要负责的是播放音乐的功能,当然,在启动的时候到sdcard中读取数据、动态跟新通知栏以及歌词等这些也都是在PlayService中完成的;而DownLoadService主要结合DownLoad类实现歌曲下载的功能。也是必须要考虑到服务必须要在后台长期运行的缘故,因此,这边的处理是在应用启动时候,通过application类调用它的startService方法启动service。详细情况可以参考我的博文【android】音乐播放器之service服务设计~!~哈哈哈哈哈哈,application类已经在前面提到的博文中已经贴出来这边就不再贴出相关的代码。
有了application类后可以着手去设计Activity类,很自然想到实现一个父类,把子类中复用的代码都放在BaseActivity。然后在子类中覆盖或者重写父类中的相关代码 ,代码如下:
public abstract class BaseActivity extends FragmentActivity {protected PlayService mPlayService;protected DownloadService mDownloadService;private final String TAG = BaseActivity.class.getSimpleName();private ServiceConnection mPlayServiceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName arg0, IBinder service) {// TODO Auto-generated method stubmPlayService = ((PlayService.PlayBinder) service).getService();mPlayService.setOnMusicEventListener(mMusicEventListener);onChange(mPlayService.getPlayingPosition());}@Overridepublic void onServiceDisconnected(ComponentName arg0) {mPlayService = null;}};private ServiceConnection mDownloadServiceConnection = new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {L.l(TAG, "download--->onServiceDisconnected");mDownloadService = null;}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mDownloadService = ((DownloadService.DownloadBinder) service).getService();}};/** 音乐播放服务回调接口的实现类*/private PlayService.OnMusicEventListener mMusicEventListener = new PlayService.OnMusicEventListener() {@Overridepublic void onPublish(int progress) {BaseActivity.this.onPublish(progress);}@Overridepublic void onChange(int position) {BaseActivity.this.onChange(position);}};/*** Fragment的view加载完成后回调*/public void allowBindService() {bindService(new Intent(this, PlayService.class), mPlayServiceConnection,Context.BIND_AUTO_CREATE);}/*** fragment的view消失后回调*/public void allowUnbindService() {unbindService(mPlayServiceConnection);}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);bindService(new Intent(this, DownloadService.class), mDownloadServiceConnection,Context.BIND_AUTO_CREATE);}@Overrideprotected void onDestroy() {unbindService(mDownloadServiceConnection);super.onDestroy();}public DownloadService getDownloadService() {return mDownloadService;}/*** 更新进度* @param progress 进度*/public abstract void onPublish(int progress);/*** 切换歌曲* @param position 歌曲在list中的位置*/public abstract void onChange(int position);
}
有了BaseActivity,可以设计子类部分。在一个准备类启动加载一个布局全屏显示一张启动封面延时两秒钟进入主界面。主界面设计仿多米音乐风格,在MainActivity中添加5个Fragment(详细的UI设计见:【android】音乐播放器之UI设计的点点滴滴),同时监听按钮实现Fragment的切换:
@Overridepublic void onClick(View v){resetImgs();switch (v.getId()){case R.id.id_tab_user:setSelect(TAB_USER);break;case R.id.id_tab_cd:setSelect(TAB_CD);break;case R.id.id_tab_search:setSelect(TAB_SEARCH);break;case R.id.id_tab_compass:setSelect(TAB_COMPASS);break;case R.id.id_tab_topjump:startActivity(new Intent(this, PlayActivity.class));break;case R.id.tv_pop_exit:stopService(new Intent(this, PlayService.class));//stopService(new Intent(this, DownloadService.class));case R.id.tv_pop_shutdown:finish();case R.id.tv_pop_cancel:if(mPopupWindow != null && mPopupWindow.isShowing()) mPopupWindow.dismiss();onPopupWindowDismiss();break;default:break;}}
其中,1、需要注意的是本地音乐列表LocalFragment的监听事件是通过在UserFragment中监听获得并调用主活动的的select方法跳转到本地音乐列表。当然,此时本地音乐列表已经初始化过~~~初始化过程主要在PlayService中启动过程完成(这个在上面提到的相关博文有详细的说明);2、在LocalFragment启动过程通过bingservice()绑定服务,这样就可以实现当点击本地音乐列表时候播放按钮同时跳转到PlayActivity播放界面。代码如下:
@Overridepublic void onStart() {super.onStart();mActivity.allowBindService();}@Overridepublic void onStop() {super.onStop();mActivity.allowUnbindService();}
@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {Intent intent = new Intent(mActivity, PlayActivity.class);intent.putExtra("pos", position);startActivity(intent);play(position);}
private void play(int position) {int pos = mActivity.getPlayService().play(position);onPlay(pos);}
同时,当长按本地音乐播放列表可以实现删除本地音乐的功能,通过listView的setOnItemLongClickListener方法监听,获取事件时调用MusicUtils的remove方法删除本地音乐,并启动扫描sdcard通过广播通知列表变化更新本地列表:
private OnItemLongClickListener mItemLongClickListener = new OnItemLongClickListener() {@Overridepublic boolean onItemLongClick(AdapterView<?> parent, View view,int position, long id) {final int pos = position;AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);builder.setTitle("删除该条目");builder.setMessage("确认要删除该条目吗?");builder.setPositiveButton("删除",new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {Music music = MusicUtils.sMusicList.remove(pos);mMusicListAdapter.notifyDataSetChanged();if (new File(music.getUri()).delete()) {scanSDCard();}}});builder.setNegativeButton("取消", null);builder.create().show();return true;}};
private void scanSDCard() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {// 判断SDK版本是不是4.4或者高于4.4String[] paths = new String[]{Environment.getExternalStorageDirectory().toString()};MediaScannerConnection.scanFile(mActivity, paths, null, null);} else {Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED);intent.setClassName("com.android.providers.media","com.android.providers.media.MediaScannerReceiver");intent.setData(Uri.parse("file://"+ MusicUtils.getMusicDir()));mActivity.sendBroadcast(intent);}}
跳转到PlayActivity后实现和在LocalFragment实现十分相同,绑定Playservice服务,初始化监听事件,获取事件调用服务中的方法播放音乐,具体的Ui设计部分见【android】音乐播放器之UI设计的点点滴滴。另外,注意一点是:在布局文件中介个监听听按钮设置了onclick属性:
<ImageButtonandroid:id="@+id/ib_play_pre"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@android:color/transparent"android:contentDescription="@string/app_name"android:onClick="pre"android:src="@drawable/player_btn_pre_normal" /><ImageButtonandroid:id="@+id/ib_play_start"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="20dp"android:layout_marginRight="20dp"android:background="@android:color/transparent"android:contentDescription="@string/app_name"android:onClick="play"android:src="@drawable/player_btn_play_normal" /><ImageButtonandroid:id="@+id/ib_play_next"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@android:color/transparent"android:contentDescription="@string/app_name"android:onClick="next"android:src="@drawable/player_btn_next_normal" />
当在MainActivity中捕获到网络按钮时,跳转到SearchFragment网络列表,因为在BaseActivity的Oncreate方法直接绑定DownLoadService,所以在该Fragment中就没必要再去绑定服务。在 SearchFragment创建后调用setUserVisibleHint方法实现Fragment实现懒加载,结合SongsRecommendation类解析百度音乐中页面获取音乐数据,显示在SearchFragment布局中,网页解析获取歌曲列表主要通过JSOUP解析技术实现(可以参考:jsoup下载地址 以及jsoup中文开发指南)。代码如下:
@Overridepublic void onResume() {super.onResume();if(getUserVisibleHint()){Boolean isVisibleToUser = getUserVisibleHint();setUserVisibleHint(isVisibleToUser);}}/*** 该方法实现的功能是: 当该Fragment不可见时,isVisibleToUser=false* 当该Fragment可见时,isVisibleToUser=true* 该方法由系统调用,重写该方法实现用户可见当前Fragment时再进行数据的加载*/@Overridepublic void setUserVisibleHint(boolean isVisibleToUser) {super.setUserVisibleHint(isVisibleToUser);// 当Fragment可见且是第一次加载时if (isVisibleToUser && isFirstShown) {mSearchProgressBar.setVisibility(View.VISIBLE);mSearchResultListView.setVisibility(View.GONE);SongsRecommendation.getInstance().setListener(new SongsRecommendation.OnRecommendationListener() {@Overridepublic void onRecommend(ArrayList<SearchResult> results) {if (results == null || results.isEmpty())return;mSearchProgressBar.setVisibility(View.GONE);mSearchResultListView.setVisibility(View.VISIBLE);mResultData.clear();mResultData.addAll(results);mSearchResultAdapter.notifyDataSetChanged();}}).get();isFirstShown = false;}}
/*** 真正执行网页解析的方法* 线程池中开启新的线程执行解析,解析完成之后发送消息* 将结果传递到主线程中*/public void get() {mThreadPool.execute(new Runnable() {@Overridepublic void run() {ArrayList<SearchResult> result = getMusicList();if (result == null) {mHandler.sendEmptyMessage(Constants.FAILED);return;}mHandler.obtainMessage(Constants.SUCCESS, result).sendToTarget();}});}private ArrayList<SearchResult> getMusicList() {try {/*** 一下方法调用请参考官网* 说明:timeout设置请求时间,不宜过短。* 时间过短导致异常,无法获取。*/Document doc = Jsoup.connect(URL).userAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64)" +" AppleWebKit/537.36"+ " (KHTML, like Gecko)" +" Chrome/42.0.2311.22 Safari/537.36").timeout(60 * 1000).get();//select为选择器,请参考官网说明Elements songTitles = doc.select("span.song-title");Elements artists = doc.select("span.author_list");ArrayList<SearchResult> searchResults = new ArrayList<SearchResult>();for (int i = 0; i < songTitles.size(); i++) {SearchResult searchResult = new SearchResult();Elements urls = songTitles.get(i).getElementsByTag("a");searchResult.setUrl(urls.get(0).attr("href"));searchResult.setMusicName(urls.get(0).text());Elements artistElements = artists.get(i).getElementsByTag("a");searchResult.setArtist(artistElements.get(0).text());searchResult.setAlbum("最新推荐");searchResults.add(searchResult);}return searchResults;} catch (IOException e) {e.printStackTrace();}return null;}
具体监听点击事件开始下载功能的实现见其他几篇小博文。这边就不一一介绍了,如果感兴趣还是建议看下源码。
源码地址:音乐播放器源码
git 源码地址(免积分):音乐播放器源码
理
【android】音乐播放器之设计思路相关推荐
- android音乐播放器ppt,基于Android音乐播放器设计与开发.ppt
基于Android音乐播放器设计与开发 毕业设计 基于Android的音乐播放器 设计与开发 设计概述 研究背景 研究意义 研究目标 系统演示 研究背景 随着Android智能手机的普及,用户越来越能 ...
- android音乐播放器之歌词下载、处理、开始、同步
android音乐播放器之歌词下载.处理.开始.同步 ** 程序源代码在底部 ** 先来看看效果 下载 /*** 自定义下载方法,调用系统DownloadManager下载* * @param myU ...
- android音乐播放器之----天天动听
下载手机软件的时候,随意的下了个天天动听,觉得喜欢,就仿照着他的UI做了个简单的音乐播放器,还不完善,只是在工作之余随便做做,贴图: 本文来自CSDN丹丹博库,转载请必须注明出处: http://bl ...
- android 音乐播放器设计,基于Android音乐播放器设计的实现毕业论文.pdf
摘要 随着手机的智能化以及网络的普及和应用,人类将进入移动互联 网的新时代.在国内,随着4G牌照的下发,三大运行商也在加紧抢 占移动互联网领域的制高点.在此过程中,人们对新一代移动互联终 端设备的功能 ...
- android音乐播放器之在线播放功能的实现
转发请注明出处:http://blog.csdn.net/qq_28055429/article/details/51327171 前言:由于最近在做一个音乐播放器,需实现在线播放功能的实现,故而找了 ...
- 【android】音乐播放器之service服务设计
学习Android有一个多月,看完了<第一行代码>以及mars老师的第一期视频通过音乐播放器小项目加深对知识点的理解.从本文开始,将详细的介绍简单仿多米音乐播放器的实现,以及网络解析数据获 ...
- 【android】音乐播放器之UI设计的点点滴滴
学习Android有一个多月,看完了<第一行代码>以及mars老师的第一期视频通过音乐播放器小项目加深对知识点的理解.从本文开始,将详细的介绍简单仿多米音乐播放器的实现,以及网络解析数据获 ...
- 【android】音乐播放器之数据存储总结
学习Android有一个多月,看完了<第一行代码>以及mars老师的第一期视频通过音乐播放器小项目加深对知识点的理解.从本文开始,将详细的介绍简单仿多米音乐播放器的实现,以及网络解析数据获 ...
- 基于android音乐播放器的设计
本科毕业论文(设计)诚信声明 本人郑重声明:所呈交的毕业论文(设计),题目<---基于android音乐播放器的设计----------->是本人在指导教师的指导下,进行研究工作所取得的成 ...
最新文章
- android Spinner 例子
- centos6.9安装Tomcat8.0.36
- Navicat是如何连接到服务器的呢
- html5媒体对象居中,媒体对象 - Media Objects
- django1.5 连接mysql_django1.5.5使用mysql
- java并发(二):初探syncronized
- mysql 按月建表_MySQL之存储过程按月创建表
- Python使用傅里叶变换调整音频文件音量
- 怎么能让宝贝快点入睡?
- docker 实战---使用oracle xe作为开发数据库(六)
- 互联网寒冬资讯分析报告!如何在“大裁员”下逆势而为?
- spring mvc请求的时候是如何找到正确的Controller
- SlickEdit 之Ubuntu 版本安装
- 4k颜色测试软件,BMPC 4K 使用达芬奇LUT 调色测试
- pytorch修改图片尺寸大小
- android dex2oat 编译,dex2oat代码阅读笔记
- 如何成为一名合格的算法工程师?我们做了一次技能拆分…
- win11电脑开机密码忘记了怎么办?
- 计算机二级c语言选择题资料,计算机二级C语言重点选择题笔试复习资料
- php数据库无法插入数据,php无法插入数据怎么办