热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

扣丁音乐(六)——PlayUIActivity(播放页面)

本文出自:http:blog.csdn.netdt235201314articledetails51360013代码上传到github,欢迎start:https:github.com

本文出自:http://blog.csdn.net/dt235201314/article/details/51360013

代码上传到github,欢迎start:https://github.com/JinBoy23520/TingTingMusic

一丶音乐播放页实现功能

1.音乐格信息显示,大图显示

2.播放功能,上一曲,下一曲,暂停

3.音乐进度显示

4.切换播放模式

二丶显示效果


三丶原理及代码实现

1.自定义接口回调的方法实现UI状态切换(进度位置,播放那一首歌)

2.seekbar实现歌曲进度同步及监听

3.service统一实现Activity,Fragment的播放功能及UI图片统一

4.BaseActivity基类统一实现服务绑定,音乐播放状态,直接调用MusicPlayService

代码实现

activity_play_ui.xml

xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_match_parent"
android:layout_match_parent"
android:background="@drawable/skin2">

android:layout_match_parent"
android:layout_wrap_content"
android:id="@+id/relativeLayout">

android:layout_centerVertical="true"
android:id="@+id/iv_pull_down"
android:layout_wrap_content"
android:layout_20dp"
android:src="@drawable/backtrack"
android:layout_marginLeft="10dp"/>

android:id="@+id/ll_play_ui_top"
android:gravity="center"
android:layout_match_parent"
android:layout_wrap_content"
android:orientation="vertical"
android:layout_marginTop="5dp"
android:layout_toRightOf="@+id/iv_pull_down"
android:layout_toLeftOf="@+id/iv_share">

android:id="@+id/tv_play_ui_song"
android:layout_wrap_content"
android:layout_wrap_content"
android:text="听妈妈的话"
android:textColor="@color/white"
android:textSize="18sp"/>

android:id="@+id/tv_play_ui_artist"
android:layout_wrap_content"
android:layout_wrap_content"
android:textColor="#c1c1c1"
android:paddingTop="5dp"
android:text="周杰伦"/>



android:id="@+id/iv_share"
android:layout_wrap_content"
android:layout_25dp"
android:src="@drawable/share"
android:layout_marginRight="10dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"/>


android:layout_alignParentBottom="true"
android:layout_match_parent"
android:layout_wrap_content"
android:orientation="vertical"
android:id="@+id/linearLayout">

android:layout_match_parent"
android:layout_wrap_content">

android:id="@+id/tv_play_ui_play_time"
android:layout_wrap_content"
android:layout_wrap_content"
android:text="00:00"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:textColor="@color/white"/>

android:id="@+id/sb_play_ui_seekbar"
android:layout_match_parent"
android:layout_wrap_content"
android:thumb="@drawable/seekbar_cycle"
android:layout_toRightOf="@+id/tv_play_ui_play_time"
android:layout_toLeftOf="@+id/tv_play_ui_end_time"/>

android:id="@+id/tv_play_ui_end_time"
android:layout_wrap_content"
android:layout_wrap_content"
android:text="00:00"
android:layout_centerVertical="true"
android:textColor="@color/white"
android:layout_marginRight="10dp"
android:layout_alignParentRight="true"/>


android:gravity="center_vertical"
android:layout_match_parent"
android:layout_wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="20dp"
android:orientation="horizontal">

android:id="@+id/iv_play_ui_play_mode"
android:layout_wrap_content"
android:layout_30dp"
android:src="@drawable/list_cycle"
android:layout_weight="1"/>

android:id="@+id/iv_play_ui_previous"
android:layout_wrap_content"
android:layout_wrap_content"
android:src="@drawable/previous"
android:layout_weight="1"/>

android:id="@+id/iv_play_ui_play"
android:layout_wrap_content"
android:layout_wrap_content"
android:src="@drawable/play"
android:layout_weight="1"/>

android:id="@+id/iv_play_ui_next"
android:layout_wrap_content"
android:layout_wrap_content"
android:src="@drawable/next"
android:layout_weight="1"/>

android:id="@+id/iv_play_ui_menu"
android:layout_wrap_content"
android:layout_35dp"
android:src="@drawable/menu"
android:layout_weight="1"/>


android:layout_marginLeft="70dp"
android:layout_marginRight="70dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="10dp"
android:layout_match_parent"
android:layout_wrap_content">

android:id="@+id/iv_play_ui_like"
android:layout_wrap_content"
android:layout_25dp"
android:layout_weight="1"
android:src="@drawable/like"/>

android:id="@+id/iv_play_ui_download"
android:layout_wrap_content"
android:layout_25dp"
android:layout_weight="1"
android:src="@drawable/download"/>

android:id="@+id/iv_play_ui_add"
android:layout_wrap_content"
android:layout_28dp"
android:layout_weight="1"
android:src="@drawable/add"/>





android:layout_match_parent"
android:layout_250dp"
android:background="#00FFFFFF"
android:id="@+id/iv_ablum2"
android:layout_below="@+id/relativeLayout"
android:layout_marginTop="25dp"
/>


PlayUIActivity.java

public class PlayUIActivity extends BaseActivity implements View.OnClickListener{

private ImageView iv_pull_down,iv_play_ui_play,iv_play_ui_next,iv_play_ui_previous,iv_play_ui_play_mode,iv_ablum2;
private TextView tv_play_ui_song,tv_play_ui_artist,tv_play_ui_end_time,tv_play_ui_play_time;
private ArrayList mp3Infos;
private SeekBar sb_play_ui_seekbar;
private static final int UPDATE_TIME = 0x1;
private static MyHandler myHandler;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_play_ui);
iv_pull_down = (ImageView)findViewById(R.id.iv_pull_down);
iv_ablum2 = (ImageView)findViewById(R.id.iv_ablum2);
tv_play_ui_song = (TextView)findViewById(R.id.tv_play_ui_song);
tv_play_ui_artist = (TextView)findViewById(R.id.tv_play_ui_artist);
tv_play_ui_end_time = (TextView)findViewById(R.id.tv_play_ui_end_time);
tv_play_ui_play_time = (TextView)findViewById(R.id.tv_play_ui_play_time);
iv_play_ui_play = (ImageView)findViewById(R.id.iv_play_ui_play);
iv_play_ui_next = (ImageView)findViewById(R.id.iv_play_ui_next);
iv_play_ui_previous = (ImageView)findViewById(R.id.iv_play_ui_previous);
iv_play_ui_play_mode = (ImageView)findViewById(R.id.iv_play_ui_play_mode);
sb_play_ui_seekbar = (SeekBar)findViewById(R.id.sb_play_ui_seekbar);
iv_pull_down.setOnClickListener(this);
iv_play_ui_play.setOnClickListener(this);
iv_play_ui_next.setOnClickListener(this);
iv_play_ui_previous.setOnClickListener(this);
iv_play_ui_play_mode.setOnClickListener(this);
mp3Infos = MediaUtils.getMp3Infos(this);
myHandler = new MyHandler(this);
}

@Override
protected void onDestroy() {
super.onDestroy();
}

@Override
protected void onResume() {
super.onResume();
bindMusicPlayService();
}

@Override
protected void onPause() {
super.onPause();
unbindMusicPlayService();
}

/**
* 进度条控件已经内部处理过了,开始时间的改变是在子线程中改变主线程的UI,这当然是不可以的
* 怎么办呢,用你最熟悉的Handler处理吧
*/
static class MyHandler extends android.os.Handler{
//内部类去要想使用外部类的权限,就得把外部类拿进来
private PlayUIActivity playUIActivity;
public MyHandler(PlayUIActivity playUIActivity){
this.playUIActivity = playUIActivity;
}

@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(playUIActivity!=null){
switch (msg.what){
case UPDATE_TIME:
playUIActivity.tv_play_ui_play_time.setText(MediaUtils.formatTime(msg.arg1));
break;
}
}
}
}

//这里是子线程,不断的发送msg给主线程,通知其更改UI
@Override
public void publish(int progress) {
Message msg = myHandler.obtainMessage(UPDATE_TIME);
msg.arg1 = progress;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
myHandler.sendMessage(msg);
sb_play_ui_seekbar.setProgress(progress);
}

@Override
public void change(int position) {
Mp3Info mp3Info = mp3Infos.get(position);
tv_play_ui_song.setText(mp3Info.getTitle());
tv_play_ui_artist.setText(mp3Info.getArtist());
tv_play_ui_end_time.setText(MediaUtils.formatTime(mp3Info.getDuration()));
iv_play_ui_play.setImageResource(R.drawable.pause);
//获取专辑封面图片
Bitmap albumBitmap = MediaUtils.getArtwork(this, mp3Info.getId(), mp3Info.getAlbumId(), true, false);
//改变播放界面专辑封面图片
iv_ablum2.setImageBitmap(albumBitmap);
sb_play_ui_seekbar.setProgress(0);
sb_play_ui_seekbar.setMax((int)mp3Info.getDuration());
if(musicPlayService.isPlaying()){
iv_play_ui_play.setImageResource(R.drawable.pause);
}else {
iv_play_ui_play.setImageResource(R.drawable.play);
}


switch (musicPlayService.getPlay_mode()){
case MusicPlayService.ORDER_PLAY:
iv_play_ui_play_mode.setImageResource(R.drawable.list_cycle);
//iv_play_ui_play_mode.setTag(MusicPlayService.ORDER_PLAY);
break;
case MusicPlayService.RANDOM_PLAY:
iv_play_ui_play_mode.setImageResource(R.drawable.random);
//iv_play_ui_play_mode.setTag(MusicPlayService.RANDOM_PLAY);
break;
case MusicPlayService.SINGLE_PLAY:
iv_play_ui_play_mode.setImageResource(R.drawable.single_cycle);
//iv_play_ui_play_mode.setTag(MusicPlayService.SINGLE_PLAY);
break;
default:
break;
}

}

@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.iv_pull_down:
finish();
overridePendingTransition(R.anim.abc_fade_in, R.anim.abc_fade_out);
break;
case R.id.iv_play_ui_play:
if(musicPlayService.isPlaying()){
musicPlayService.pause();
iv_play_ui_play.setImageResource(R.drawable.play);
}else{
if(musicPlayService.isPause()){
musicPlayService.start();
iv_play_ui_play.setImageResource(R.drawable.pause);
}else{
musicPlayService.play(0);
}
}
break;
case R.id.iv_play_ui_previous:
musicPlayService.previous();
break;
case R.id.iv_play_ui_next:
musicPlayService.next();
break;
case R.id.iv_play_ui_play_mode:
switch (musicPlayService.getPlay_mode()){
case MusicPlayService.ORDER_PLAY:
iv_play_ui_play_mode.setImageResource(R.drawable.random);
musicPlayService.setPlay_mode(MusicPlayService.RANDOM_PLAY);
break;
case MusicPlayService.RANDOM_PLAY:
iv_play_ui_play_mode.setImageResource(R.drawable.single_cycle);
musicPlayService.setPlay_mode(MusicPlayService.SINGLE_PLAY);
break;
case MusicPlayService.SINGLE_PLAY:
iv_play_ui_play_mode.setImageResource(R.drawable.list_cycle);
musicPlayService.setPlay_mode(MusicPlayService.ORDER_PLAY);
}
break;
default:
break;

}
}
}
BaseActivity.java

/**
* 自定义基础activity,用来让其他activity继承,作为工具activity,用于绑定服务
*/
public abstract class BaseActivity extends FragmentActivity {

protected MusicPlayService musicPlayService;
private boolean isBound = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
MusicPlayService.PlayBinder playBinder = (MusicPlayService.PlayBinder)iBinder;
musicPlayService = playBinder.getMusicPlayService();
musicPlayService.setMusicUpdateListener(musicUpdateListener);
//绑定成功后调用监听onChange方法
musicUpdateListener.onChange(musicPlayService.getCurrentPosition());
}

@Override
public void onServiceDisconnected(ComponentName componentName) {
musicPlayService = null;
isBound = false;
}
};

private MusicPlayService.MusicUpdateListener musicUpdateListener = new MusicPlayService.MusicUpdateListener(){
@Override
public void onPublish(int progress) {
publish(progress);
}

@Override
public void onChange(int position) {
change(position);
}
};

public abstract void publish(int progress);
public abstract void change(int position);

//绑定服务
public void bindMusicPlayService(){
if(!isBound){
Intent intent = new Intent(this,MusicPlayService.class);
bindService(intent,conn,BIND_AUTO_CREATE);
isBound = true;
}

}

//解除绑定服务
public void unbindMusicPlayService(){
if(isBound){
unbindService(conn);
isBound = false;
}

}
}
MusicPlayService.java

/**
* 实现功能:
* 1、点击列表上的某首歌播放
* 2、点击播放按钮,从暂停转为播放状态
* 3、点击暂停按钮,从播放状态转为暂停状态
* 4、上一首
* 5、下一首
* 6、播放进度显示
* 7、播放模式
*/
public class MusicPlayService extends Service implements MediaPlayer.OnCompletionListener,MediaPlayer.OnErrorListener{

private MediaPlayer mediaPlayer;
private ArrayList mp3Infos;
private int currentPosition;//列表当前位置
private MusicUpdateListener musicUpdateListener;//设置属性
private boolean isPause = false;

//顺序播放、单曲循环、随机播放
public static final int ORDER_PLAY = 1;
public static final int RANDOM_PLAY = 2;
public static final int SINGLE_PLAY = 3;
public int play_mode = ORDER_PLAY;


//用于设置或者获得播放模式
public int getPlay_mode() {
return play_mode;
}

public void setPlay_mode(int play_mode) {
this.play_mode = play_mode;
}


//在fragment或者activity中轻松获得状态
public boolean isPause(){
return isPause;
}

//开启线程池
private ExecutorService es = Executors.newSingleThreadExecutor();

Runnable updateStatusRunnable = new Runnable() {
@Override
public void run() {
while (true){
if(musicUpdateListener!=null&&mediaPlayer!=null&&mediaPlayer.isPlaying()){
musicUpdateListener.onPublish(getCurrentProgress());
}
}
}
};

public MusicPlayService() {

}

Random random = new Random();
//用于监听当前歌曲播放完后,下一首该如何播放
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
switch (play_mode){
case ORDER_PLAY:
next();
break;
case RANDOM_PLAY:
play(random.nextInt(mp3Infos.size()));
break;
case SINGLE_PLAY:
play(currentPosition);
break;
default:
break;
}
}

@Override
public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
mediaPlayer.reset();
return false;
}

class PlayBinder extends Binder{
public MusicPlayService getMusicPlayService(){
return MusicPlayService.this;
}
}

@Override
public void onCreate() {
super.onCreate();
mediaPlayer = new MediaPlayer();
mp3Infos = MediaUtils.getMp3Infos(this);
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnErrorListener(this);
//在进入每一个绑定service时,就监听进度改变事件,而状态改变监听则是在启动播放的时候
es.execute(updateStatusRunnable);
}

//启动线程就得销毁
@Override
public void onDestroy() {
super.onDestroy();
if(es!=null && es.isTerminated()){
es.shutdown();
es = null;
}
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
return new PlayBinder();
}

//点击列表上的某首歌播放
public void play(int position){
if(position>=0 && position<mp3Infos.size()){
Mp3Info mp3Info = mp3Infos.get(position);
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(this, Uri.parse(mp3Info.getUrl()));
mediaPlayer.prepare();
mediaPlayer.start();
currentPosition = position;
}catch (IOException e){
e.printStackTrace();
}
if(musicUpdateListener!=null){
musicUpdateListener.onChange(currentPosition);
}
}
}

//点击播放按钮,从暂停转为播放状态
public void start(){
if(mediaPlayer!=null && !mediaPlayer.isPlaying()){
mediaPlayer.start();
}
}

//点击暂停按钮,从播放状态转为暂停状态
public void pause(){
if(mediaPlayer.isPlaying()){
mediaPlayer.pause();
isPause = true;
}
}

//下一首
public void next(){
if(currentPosition >= mp3Infos.size()-1){
currentPosition = 0;
}else{
currentPosition++;
}
play(currentPosition);
}

//上一首
public void previous(){
if(currentPosition<=0){
currentPosition = mp3Infos.size()-1;
}else{
currentPosition--;
}
play(currentPosition);
}

//更新状态的接口
public interface MusicUpdateListener{
public void onPublish(int progress);
public void onChange(int position);
}

public void setMusicUpdateListener(MusicUpdateListener musicUpdateListener) {
this.musicUpdateListener = musicUpdateListener;
}

//在音乐播放中,获得播放的位置信息
public int getDuration(){
return mediaPlayer.getDuration();
}

//跳转到某个地方
public void seekTo(int msec){
mediaPlayer.seekTo(msec);
}

//返回当前的位置
public int getCurrentPosition(){

return currentPosition;
}

//获得当前位置
public int getCurrentProgress(){
if(mediaPlayer!=null && mediaPlayer.isPlaying()){
return mediaPlayer.getCurrentPosition();
}
return 0;
}

//反馈状态
public boolean isPlaying(){
if(mediaPlayer!=null&&mediaPlayer.isPlaying()){
return mediaPlayer.isPlaying();
}
return false;
}


}



推荐阅读
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • 本文详细介绍了在ASP.NET中获取插入记录的ID的几种方法,包括使用SCOPE_IDENTITY()和IDENT_CURRENT()函数,以及通过ExecuteReader方法执行SQL语句获取ID的步骤。同时,还提供了使用这些方法的示例代码和注意事项。对于需要获取表中最后一个插入操作所产生的ID或马上使用刚插入的新记录ID的开发者来说,本文提供了一些有用的技巧和建议。 ... [详细]
author-avatar
捡到宝开封
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有