Android实战项目

您所在的位置:网站首页 android实战项目视频 Android实战项目

Android实战项目

2023-08-09 11:55| 来源: 网络整理| 查看: 265

Android实战项目——音乐播放器 由四大组件之一Service、使用Service进行本地通信、Handle消息机制、Android动画共同完成 类似主流音乐APP界面 简单实用 实际开发经常会涉及服务有Handler消息机制,两者具有紧密的联系,本文将通过一个音乐播放器案例演示如何使用服务进行本地通信,让大家更好的理解服务通信在实际开发中的应用。

实现音乐播放器功能的具体步骤如下:

1、创建程序

创建一个名为MusicPlayer的应用程序,指定包名为cn.itcast.musicplayer。

2、导入音乐文件

音频文件一般放在res/raw文件夹【raw文件夹中的文件会被映射到R.java文件中,访问该文件时可直接使用资源ID,即R.id.music(文件名)】中,因此需要在res文件夹中创建一个raw文件夹。首先将Android Studio中的选项卡切换到Project,接着选中程序中的res文件夹,右击选择【New】—>【Directory】选项,创建一个名为raw的文件夹,接着将音乐文件music.mp3(不能为中文)导入到raw文件夹中。

3、导入界面图片

将播放器界面所需的背景图片、音乐图片导入到程序中的drawable文件夹中。

4、放置界面控件

界面实现效果如图 在这里插入图片描述 在activity_main.xml布局文件中,放置1个ImageView控件用于显示界面上的旋转图片,1个SeekBar用于显示音乐播放器的进度条,2个TextView分别用于显示音乐播放的进度时间与音乐的总时间,4个Button控件分别用于显示“播放音乐”按钮、“暂停播放”按钮、“继续播放”按钮、“退出”按钮,完整布局代码如下:

5、创建背景选择器btn_bg_selector.xml

通过背景选择器实现界面4个按钮背景的四个角是圆角,并且背景在按下与弹起时,背景颜色会有明显区别。选中drawable文件夹,右击选择【New】——>【Drawable resource file】选项,创建一个背景选择器btn_bg_selector.xml,具体代码+注释如下:

6、创建MusicService服务

由于音乐的加载、播放、暂停以及播放进度条的更新是一件比较耗时的操作,因此需要创建一个MusicService服务来处理这些操作。首先选择cn.itcast.musicplayer包,右击选择【new】—>【Service】—>【Service】选项,创建名为MusicService的服务。具体代码如下:

package cn.itcast.musicplayer; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.Message; import java.util.Timer; import java.util.TimerTask; public class MusicService extends Service { private MediaPlayer player; private Timer timer; public MusicService() { } @Override public IBinder onBind(Intent intent) { return new MusicControl(); } public void onCreate(){ super.onCreate(); player = new MediaPlayer();//创建音乐播放器对象 } public void addTimer(){ //添加计时器用于设置音乐播放器中的播放进度条 if(timer ==null){ timer = new Timer(); //创建计时器对象 TimerTask task = new TimerTask() { @Override public void run() { //创建一个线程 if(player == null) return; //获取歌曲总时长 int duration = player.getDuration(); //获取播放进度 int currentPosition = player.getCurrentPosition(); //创建消息对象 Message msg = MainActivity.handler.obtainMessage(); //将音乐的总时长和播放进度封装至消息对象中 Bundle bundle = new Bundle(); bundle.putInt("duration",duration); bundle.putInt("currentPosition",currentPosition); msg.setData(bundle); //将消息发送到主线程的消息列表 MainActivity.handler.sendMessage(msg); } }; //调用Timer对象的schedule()方法执行TimerTask任务 // 该方法有三个参数:1、要执行的任务;2、开始执行计时任务的5毫秒后第一次执行task任务;3、每隔500毫秒执行一次 timer.schedule(task,5,500); } } class MusicControl extends Binder{ //实现播放、暂停、继续播放、设置音乐播放进度条的功能 public void play(){ try { player.reset(); //重置音乐播放器 //加载多媒体文件 player = MediaPlayer.create(getApplicationContext(),R.raw.music); player.start();//播放音乐 addTimer(); //添加计时器 }catch (Exception e){ e.printStackTrace(); } } public void pausePlay(){ player.pause(); //暂停播放音乐 } public void continuePlay(){ player.start(); //继续播放音乐 } public void seekTo(int progress){ player.seekTo(progress); //设置音乐的播放位置 } } public void onDestroy(){ super.onDestroy(); if(player == null) return; if(player.isPlaying()) player.stop(); //停止播放音乐 player.release(); //释放占用的资源 player = null; //将player置为空 } }

上述代码中,addTimer()方法用于每隔500毫秒更新音乐播放器的进度条,在该方法中首先创建一个计时器Timer的对象,接着创建一个TimerTask任务task,在该任务中重写了run()方法创建一个线程,在run()方法中通过getDuration()方法与getCurrentPosition()方法分别获取歌曲的总时长与歌曲当前的播放进度。getDuration()方法与getCurrentPosition()方法是MediaPlayer常用方法,更多Mediaplayer常用方法见:MediaPlayer常用方法介绍

7、编写界面交互代码

MainActivity实现了音乐文件的播放、暂停播放、继续播放、播放进度的设置、退出音乐播放界面的功能以及实现音乐播放界面4个按钮的点击事件。具体代码如下(带详细注释):

package cn.itcast.musicplayer; import androidx.appcompat.app.AppCompatActivity; import android.animation.ObjectAnimator; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.view.View; import android.view.animation.LinearInterpolator; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static SeekBar sb; private static TextView tv_progress, tv_total; private ObjectAnimator animator; private MusicService.MusicControl musicControl; MyServiceConn conn; Intent intent; private boolean isUnbind = false;//记录服务是否被解绑 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } private void init() { tv_progress = (TextView) findViewById(R.id.tv_progress); tv_total = (TextView) findViewById(R.id.tv_total); sb = (SeekBar) findViewById(R.id.sb); findViewById(R.id.btn_play).setOnClickListener(this); findViewById(R.id.btn_pause).setOnClickListener(this); findViewById(R.id.btn_continue_play).setOnClickListener(this); findViewById(R.id.btn_exit).setOnClickListener(this); intent = new Intent(this, MusicService.class);//创建意图对象 conn = new MyServiceConn();//创建服务连接对象 bindService(intent, conn, BIND_AUTO_CREATE); //绑定服务 //为滑动条添加事件监听 sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override //滑动条进度改变时会调用该方法 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if(progress ==seekBar.getMax()){ //当滑动条滑到末端时,结束动画 animator.pause(); //停止播放动画 } } //滑动条开始滑动时调用 @Override public void onStartTrackingTouch(SeekBar seekBar) { } //滑动条停止滑动时调用 @Override public void onStopTrackingTouch(SeekBar seekBar) { //根据拖动的进度改变音乐播放进度 int progress = seekBar.getProgress(); //获取seekBar的进度 musicControl.seekTo(progress); //改变播放进度 } }); ImageView iv_music = (ImageView) findViewById(R.id.iv_music); animator = ObjectAnimator.ofFloat(iv_music,"rotation",0f,360.0f); animator.setDuration(10000); //动画旋转一周的时间为10秒 animator.setInterpolator(new LinearInterpolator()); animator.setRepeatCount(-1); //-1表示设置动画无线循环 } //创建消息处理器对象 public static Handler handler = new Handler(){ //在主线程中处理从子线程发送过来的消息 public void handleMessage(Message msg){ Bundle bundle = msg.getData(); //获取从子线程发送过来的音乐播放进度 int duration = bundle.getInt("duration"); //歌曲的总时长 int currentPostition = bundle.getInt("currentPosition");//歌曲当前进度 sb.setMax(duration); //设置SeekBar的最大值为歌曲总时长 sb.setProgress(currentPostition);//设置SeekBar当前的进度位置 //歌曲的总时长转换格式 int minute = duration / 1000 / 60; int second = duration / 1000 % 60; String strMinute = null; String strSecond = null; if (minute strMinute = minute + ""; } if (second strSecond = second + ""; } tv_total.setText(strMinute + ":" + strSecond); //歌曲当前播放时长 minute = currentPostition / 1000 / 60; second = currentPostition / 1000 % 60; if (minute strMinute = minute + ""; } if (second strSecond = second + ""; } tv_progress.setText(strMinute + ":" + strSecond); } }; @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_play: //播放按钮点击事件 musicControl.play(); //播放音乐 animator.start(); //播放动画 break; case R.id.btn_pause: //暂停按钮点击事件 musicControl.pausePlay(); //暂停播放音乐 animator.pause(); //暂停播放动画 break; case R.id.btn_continue_play: //继续播放按钮点击事件 musicControl.continuePlay(); //继续播放音乐 animator.start(); //播放动画 break; case R.id.btn_exit: //退出按钮点击事件 unbind(isUnbind); //解绑服务绑定 isUnbind = true; //完成解绑服务 finish(); //关闭音乐播放界面 break; } } private class MyServiceConn implements ServiceConnection { //用于实现连接服务 @Override public void onServiceConnected(ComponentName componentName, IBinder service) { musicControl = (MusicService.MusicControl) service; } @Override public void onServiceDisconnected(ComponentName componentName) { } } private void unbind(Boolean isUnbind){ if(!isUnbind){ //判断服务是否解绑 musicControl.pausePlay(); //暂停播放音乐 unbindService(conn); //解绑服务 stopService(intent); //停止服务 } } protected void onDestroy() { super.onDestroy(); unbind(isUnbind); //解绑服务 } } 8、运行程序

运行上诉程序,分别点击界面上的“播放音乐”按钮、“暂停播放”按钮、“继续播放”按钮,可实现音乐的播放、暂停、继续播放的功能。点击界面上的“退出”按钮,可退出音乐播放器界面。运行结果如图所示: 在这里插入图片描述 文件创建地址不明白的可参考下图: 在这里插入图片描述

Handler消息机制:

Handler消息处理首先需要在UI线程中创建一个Handler对象,然后在子线程中调用Handler的SendMessage()方法,接着这个消息会存放在UI线程的MessageQueue中,通过Looper对象取出MessageQueue中的消息,最后分发回Handler的HandleMessage()方法中。 谢谢观看!祝学习进步编程开心~希望可以得到你的赞与关注哟



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3