Android 服务与多线程——编写简单的音乐播放器程序
2016-11-06 21:04
543 查看
Android 服务与多线程——编写简单的音乐播放器程序
一、实验目的
1) 学会使用MediaPlayer;
2) 学会简单的多线程编程,使用Handler更新UI;
3) 学会使用Service进行后台工作;
4) 学会使用Service与Activity进行通信。
二、实验要求
1) 实现音乐文件的播放控制(仅需要播放,暂停和停止)
2) 利用Handler更新播放进度
3) 利用Service开启(停止)后台服务进行后台播放
三、使用环境
Eclipse,Android 2.3
四、调试过程、代码解析及运行截图
1.向sdcard中添加音乐:
1)启动模拟器,打开DDMS视图;
2)选择FileExplorer标签页;
3)选择sdcard目录后点击右上角的push按钮即可。如下图:
2.创建MediaPlayer的对象,并利用控制条更新播放进度:
1)创建MediaPlayer及Handler:
[java]
view plain
copy
MediaPlayermPlayer = new MediaPlayer();
Handler handler = new Handler();
RunnableupdateThread = new Runnable(){
public void run() {
//获得歌曲现在播放位置并设置成播放进度条的值
seekbar.setProgress(mPlayer.getCurrentPosition());
//每次延迟100毫秒再启动线程
handler.postDelayed(updateThread, 100);
}
2)初始化音乐:
[java]
view plain
copy
try {
mPlayer.setDataSource("/sdcard/test.mp3"); //选择资源
mPlayer.prepare(); //准备就绪
text.setText("初始化歌曲…");
} catch (IOException e){
text.setText("初始异常");
e.printStackTrace();
//获取音乐的总长度以设置进度条的最大长度
seekbar.setMax(mPlayer.getDuration());
mPlayer.setOnCompletionListener(complete);
3)对开始/暂停键事件触发:
[java]
view plain
copy
privateImageButton.OnClickListenerbtn_play = new ImageButton.OnClickListener(){
@Override
public void onClick(View arg0) {
//TODOAuto-generated method stub
try {
if(mPlayer !=null) {
if(mPlayer.isPlaying()) { //判断是否正在播放
mPlayer.pause(); //暂停播放器
handler.post(updateThread); //使用handler的post方法用于更新
bn_play.setImageDrawable(getResources().getDrawable(R.drawable.play));
text.setText("已暂停"); //更新图标
}
else if(!mPlayer.isPlaying()) {
mPlayer.start(); //继续播放音乐
handler.post(updateThread);
bn_play.setImageDrawable(getResources().getDrawable(R.drawable.pause));
text.setText("播放中");
}
}
} catch (Exception e) {
text.setText("播放/暂停异常");
e.printStackTrace();
}
}
};
4)对停止键的事件触发:
[java]
view plain
copy
private ImageButton.OnClickListenerbtn_stop = new ImageButton.OnClickListener(){
@Override
public void onClick(View arg0) {
// TODO Auto-generated methodstub
try{
if(mPlayer.isPlaying()){
text.setText("已停止"); //更新文字提示
}
else {
text.setText("初始化歌曲…");
}
mPlayer.stop(); //停止播放音乐
handler.removeCallbacks(updateThread);
bn_play.setImageDrawable(getResources().getDrawable(R.drawable.play));
mPlayer.reset(); //恢复至初始状态
mPlayer.setDataSource("/sdcard/test.mp3");
mPlayer.prepare();
} catch (Exception e){
text.setText("停止异常");
e.printStackTrace();
}
}
};
5)退出的事件触发
[java]
view plain
copy
private Button.OnClickListenerbtn_exit = new Button.OnClickListener(){
@Override
public void onClick(View arg0) {
// TODO Auto-generated methodstub
onDestroy();
}
};
@Override
protected void onDestroy(){
mPlayer.release();
super.onDestroy();
System.exit(0); //完全退出系统
};
6)歌曲播放结束的事件:
[java]
view plain
copy
privateMediaPlayer.OnCompletionListenercomplete = new MediaPlayer.OnCompletionListener(){
@Override
public void onCompletion(MediaPlayerarg0) {
try {
handler.removeCallbacks(updateThread);//移除对线程的调用
bn_play.setImageDrawable(getResources().getDrawable(R.drawable.play));
mPlayer.reset(); nbsp; //恢复到初始状态
mPlayer.setDataSource("/sdcard/test.mp3");
mPlayer.prepare();
text.setText("播放结束!");
} catch (IOException e){
text.setText("完成异常");
e.printStackTrace();
}
}
7)对进度条的操作:
[java]
view plain
copy
privateSeekBar.OnSeekBarChangeListenerseekb = new SeekBar.OnSeekBarChangeListener(){
@Override
public void onProgressChanged(SeekBarseekBar, int progress,boolean fromUser) {
// fromUser判断是用户改变的滑块的值
if(fromUser==true){
mPlayer.seekTo(progress); //转到相应的进程中
}
}
@Override
public voidonStartTrackingTouch(SeekBar seekBar) {
//TODOAuto-generated methodstub
}
@Override
public void onStopTrackingTouch(SeekBarseekBar) {
//TODOAuto-generated method stub
}
};
8)添加时间进度显示:
A.定义两个变量,一为现在正播放的时间:playtime;二为总时常alltime:
[java]
view plain
copy
playtime =(TextView)findViewById(R.id.progress);
alltime =(TextView)findViewById(R.id.alltime);
B.在播放的设置中添加获取音乐总时长的数据:
[java]
view plain
copy
else if(!mPlayer.isPlaying()) {
mPlayer.start();
int Alltime=mPlayer.getDuration();
alltime.setText(ShowTime(Alltime));
handler.post(updateThread);
bn_play.setImageDrawable(getResources().getDrawable(R.drawable.pause));
text.setText("播放中");
C.在Runnable里获取正在运行的时间:
[java]
view plain
copy
Runnable updateThread = new Runnable(){
public void run() {
//获得歌曲现在播放位置并设置成播放进度条的值
//将播放的时间调到正在播放的时间
int CurrentPosition=mPlayer.getCurrentPosition();
playtime.setText(ShowTime(CurrentPosition));
seekbar.setProgress(CurrentPosition);
//每次延迟100毫秒再启动线程
handler.postDelayed(updateThread, 100);
}
};
D.显示时间的函数
[java]
view plain
copy
public String ShowTime(int time){
time/=1000;
int minute=time/60;
int hour=minute/60;
int second=time%60;
minute%=60;
return String.format("%02d:%02d", minute, second);
3.利用Service开启(停止)后台服务进行后台播放
Android中的服务,它与Activity不同,它是不能与用户交互的,不能自己启动的,运行在后台的程序,如果我们退出应用时,Service进程并没有结束,它仍然在后台运行。使用Service来管理音乐的后台播放
1) 创建Service子类,并在Manifest.xml中进行注册
<service
android:name=".MyService"/>
2) 创建接口MyBinder,负责Activity与Service之间进行沟通,帮助Activity调用Service里的方法
[java]
view plain
copy
package com.yzh;
import android.app.Service;
import android.os.Binder;
public interface MyBinder
{
public Service getService();
//负责Activity与Service之间进行沟通,帮助 Activity调用Service里的方法
3) 将之前写的MediaPlayer相关的代码全部移动到Service类中
A. OnCreate()
[java]
view plain
copy
@Override
publicvoid onCreate() { //初始化MediaPlayer
// TODO Auto-generated method stub
super.onCreate();
mPlayer =new MediaPlayer();
try {
mPlayer.setDataSource("/sdcard/test.mp3");
mPlayer.prepare();
} catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
B. OnDestroy()
[java]
view plain
copy
@Override
publicvoid onDestroy() {
// TODO Auto-generated methodstub
super.onDestroy();
mPlayer.release();
}
C. startorpauseMusic()
[java]
view plain
copy
publicboolean startorpauseMusic()
{
boolean playing =false;
if(!mPlayer.isPlaying()){
playing = false;
mPlayer.start();
}
else{
playing = true;
mPlayer.pause();
}
return playing;
}
D. stopMusic()
[java]
view plain
copy
public void stopMusic()
mPlayer.seekTo(0);
mPlayer.stop();
try {
mPlayer.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
4) 通过Binder来保持Activity与Service的通信
[java]
view plain
copy
private IBinder binder = new MyBinderImpl();
@Override
public IBinder onBind(Intentarg0) {
// TODO Auto-generated method stub
return binder;
}
//在主Activity退出时必须解除绑定,否则会抛出异常
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated methodstub
return super.onUnbind(intent);
}
public class MyBinderImpl extends Binderimplements MyBinder
{
@Override
public Service getService() {
// TODO Auto-generated methodstub
return MyService.this;
}
}
5) 在主Activity中调用 bindService 保持与Service的通信:
[java]
view plain
copy
ServiceConnection sc = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName arg0, IBinder binder) {
// TODO Auto-generated method stub
MyBinder myBinder = (MyBinder)binder;
service = (MyService)myBinder.getService();
seekbar.setMax(service.getDuration());
int length = service.getDuration();
int secLength = length/1000+1;
service.onComplete(handler);
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
// TODO Auto-generated method stub
}
};
6) 在Activity中将所有的MediaPlayer的方法都替换为Service里的函数。
7) 在Service中还需要定义的方法:
[java]
view plain
copy
//获取音乐的长度
lic int getDuration()
{
return mPlayer.getDuration();
}
//获取音乐的播放位置
public int getPosition()
{
return mPlayer.getCurrentPosition();
}
//跳转至音乐播放的进程
public void seekto(int progress){
mPlayer.seekTo(progress);
}
4.实验截图
图1 初始化状态
图2 点击播放按钮:播放音乐
显示总时长,以及现在播放的时间,进度条实时更新
图3 点击暂停按钮,暂停播放
显示“已暂停”,停止更新
图4 点击停止按钮,停止播放
当再次点击播放按钮时,音乐从头开始
图5 当音乐播放完后,显示“播放结束!”
图6 关掉运行界面后,
播放器在后台运行仍然运行
图7 项目的文件结构
五、遇到的困难和解决方法
在使用Service作后台处理的时候,忽略了音乐播放结束后的事件触发,无法显示“播放结束”,原来判断音乐播放结束是MediaPlayer的一个方法,无法在Activity里进行,必须要在Service里定义,于是采用使用Handler来传参的方法。具体解决步骤如下:
A. 在Service中定义OnComplete方法:
[java]
view plain
copy
public void onComplete(final Handler handler)
{
MediaPlayer.OnCompletionListener complete = newMediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer arg0) {
// TODO Auto-generated method stub
Message msg = new Message(); //获得消息
msg.arg1 = 0;
handler.sendMessage(msg); //传递给handler
}
};
mPlayer.setOnCompletionListener(complete);
}
B. 在Activity中获取消息:
[java]
view plain
copy
Handler handler = new Handler(){
@Override
public void handleMessage(Messagemsg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if(msg.arg1 == 0)
{
handler.removeCallbacks(updateThread);//移除对线程的调用
bn_play.setImageDrawable(getResources().getDrawable(R.drawable.play));
text.setText("播放结束");
}
}
};
六、附录——main.xml
[html]
view plain
copy
<?xml version="1.0"encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/linearLayout7"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:layout_gravity="center_horizontal"
android:textColor="#0489B1"
android:text="My MusicPlayer" />
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<LinearLayout
android:id="@+id/linearLayout5"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20dp"
android:text="Enjoy yourMusic: " />
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout6"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:text="test.mp3"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout9"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<TextView
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00"
android:textColor="#FFBF00"
android:textSize="18dp"/>
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFBF00"
android:textSize="18dp"
android:text=" / "/>
<TextView
android:id="@+id/alltime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFBF00"
android:textSize="18dp"
android:text="00:00"/>
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout8"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<SeekBar
android:id="@+id/seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal">
<ImageButton
android:id="@+id/bn_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play"/>
<ImageButton
android:id="@+id/bn_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/stop"/>
<Button
android:id="@+id/bn_exit"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="Exit"/>
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
</LinearLayout>
七、参考链接
[1]
http://www.verydemo.com/demo_c131_i30811.html
[2]
http://griffinshi.iteye.com/blog/641037
[3]
http://www.cnblogs.com/newcj/archive/2011/05/30/2061370.html
[4]
http://blog.csdn.net/cjjky/article/details/6552852
[5]
http://www.pocketdigi.com/20100908/92.html
一、实验目的
1) 学会使用MediaPlayer;
2) 学会简单的多线程编程,使用Handler更新UI;
3) 学会使用Service进行后台工作;
4) 学会使用Service与Activity进行通信。
二、实验要求
1) 实现音乐文件的播放控制(仅需要播放,暂停和停止)
2) 利用Handler更新播放进度
3) 利用Service开启(停止)后台服务进行后台播放
三、使用环境
Eclipse,Android 2.3
四、调试过程、代码解析及运行截图
1.向sdcard中添加音乐:
1)启动模拟器,打开DDMS视图;
2)选择FileExplorer标签页;
3)选择sdcard目录后点击右上角的push按钮即可。如下图:
2.创建MediaPlayer的对象,并利用控制条更新播放进度:
1)创建MediaPlayer及Handler:
[java]
view plain
copy
MediaPlayermPlayer = new MediaPlayer();
Handler handler = new Handler();
RunnableupdateThread = new Runnable(){
public void run() {
//获得歌曲现在播放位置并设置成播放进度条的值
seekbar.setProgress(mPlayer.getCurrentPosition());
//每次延迟100毫秒再启动线程
handler.postDelayed(updateThread, 100);
}
2)初始化音乐:
[java]
view plain
copy
try {
mPlayer.setDataSource("/sdcard/test.mp3"); //选择资源
mPlayer.prepare(); //准备就绪
text.setText("初始化歌曲…");
} catch (IOException e){
text.setText("初始异常");
e.printStackTrace();
//获取音乐的总长度以设置进度条的最大长度
seekbar.setMax(mPlayer.getDuration());
mPlayer.setOnCompletionListener(complete);
3)对开始/暂停键事件触发:
[java]
view plain
copy
privateImageButton.OnClickListenerbtn_play = new ImageButton.OnClickListener(){
@Override
public void onClick(View arg0) {
//TODOAuto-generated method stub
try {
if(mPlayer !=null) {
if(mPlayer.isPlaying()) { //判断是否正在播放
mPlayer.pause(); //暂停播放器
handler.post(updateThread); //使用handler的post方法用于更新
bn_play.setImageDrawable(getResources().getDrawable(R.drawable.play));
text.setText("已暂停"); //更新图标
}
else if(!mPlayer.isPlaying()) {
mPlayer.start(); //继续播放音乐
handler.post(updateThread);
bn_play.setImageDrawable(getResources().getDrawable(R.drawable.pause));
text.setText("播放中");
}
}
} catch (Exception e) {
text.setText("播放/暂停异常");
e.printStackTrace();
}
}
};
4)对停止键的事件触发:
[java]
view plain
copy
private ImageButton.OnClickListenerbtn_stop = new ImageButton.OnClickListener(){
@Override
public void onClick(View arg0) {
// TODO Auto-generated methodstub
try{
if(mPlayer.isPlaying()){
text.setText("已停止"); //更新文字提示
}
else {
text.setText("初始化歌曲…");
}
mPlayer.stop(); //停止播放音乐
handler.removeCallbacks(updateThread);
bn_play.setImageDrawable(getResources().getDrawable(R.drawable.play));
mPlayer.reset(); //恢复至初始状态
mPlayer.setDataSource("/sdcard/test.mp3");
mPlayer.prepare();
} catch (Exception e){
text.setText("停止异常");
e.printStackTrace();
}
}
};
5)退出的事件触发
[java]
view plain
copy
private Button.OnClickListenerbtn_exit = new Button.OnClickListener(){
@Override
public void onClick(View arg0) {
// TODO Auto-generated methodstub
onDestroy();
}
};
@Override
protected void onDestroy(){
mPlayer.release();
super.onDestroy();
System.exit(0); //完全退出系统
};
6)歌曲播放结束的事件:
[java]
view plain
copy
privateMediaPlayer.OnCompletionListenercomplete = new MediaPlayer.OnCompletionListener(){
@Override
public void onCompletion(MediaPlayerarg0) {
try {
handler.removeCallbacks(updateThread);//移除对线程的调用
bn_play.setImageDrawable(getResources().getDrawable(R.drawable.play));
mPlayer.reset(); nbsp; //恢复到初始状态
mPlayer.setDataSource("/sdcard/test.mp3");
mPlayer.prepare();
text.setText("播放结束!");
} catch (IOException e){
text.setText("完成异常");
e.printStackTrace();
}
}
7)对进度条的操作:
[java]
view plain
copy
privateSeekBar.OnSeekBarChangeListenerseekb = new SeekBar.OnSeekBarChangeListener(){
@Override
public void onProgressChanged(SeekBarseekBar, int progress,boolean fromUser) {
// fromUser判断是用户改变的滑块的值
if(fromUser==true){
mPlayer.seekTo(progress); //转到相应的进程中
}
}
@Override
public voidonStartTrackingTouch(SeekBar seekBar) {
//TODOAuto-generated methodstub
}
@Override
public void onStopTrackingTouch(SeekBarseekBar) {
//TODOAuto-generated method stub
}
};
8)添加时间进度显示:
A.定义两个变量,一为现在正播放的时间:playtime;二为总时常alltime:
[java]
view plain
copy
playtime =(TextView)findViewById(R.id.progress);
alltime =(TextView)findViewById(R.id.alltime);
B.在播放的设置中添加获取音乐总时长的数据:
[java]
view plain
copy
else if(!mPlayer.isPlaying()) {
mPlayer.start();
int Alltime=mPlayer.getDuration();
alltime.setText(ShowTime(Alltime));
handler.post(updateThread);
bn_play.setImageDrawable(getResources().getDrawable(R.drawable.pause));
text.setText("播放中");
C.在Runnable里获取正在运行的时间:
[java]
view plain
copy
Runnable updateThread = new Runnable(){
public void run() {
//获得歌曲现在播放位置并设置成播放进度条的值
//将播放的时间调到正在播放的时间
int CurrentPosition=mPlayer.getCurrentPosition();
playtime.setText(ShowTime(CurrentPosition));
seekbar.setProgress(CurrentPosition);
//每次延迟100毫秒再启动线程
handler.postDelayed(updateThread, 100);
}
};
D.显示时间的函数
[java]
view plain
copy
public String ShowTime(int time){
time/=1000;
int minute=time/60;
int hour=minute/60;
int second=time%60;
minute%=60;
return String.format("%02d:%02d", minute, second);
3.利用Service开启(停止)后台服务进行后台播放
Android中的服务,它与Activity不同,它是不能与用户交互的,不能自己启动的,运行在后台的程序,如果我们退出应用时,Service进程并没有结束,它仍然在后台运行。使用Service来管理音乐的后台播放
1) 创建Service子类,并在Manifest.xml中进行注册
<service
android:name=".MyService"/>
2) 创建接口MyBinder,负责Activity与Service之间进行沟通,帮助Activity调用Service里的方法
[java]
view plain
copy
package com.yzh;
import android.app.Service;
import android.os.Binder;
public interface MyBinder
{
public Service getService();
//负责Activity与Service之间进行沟通,帮助 Activity调用Service里的方法
3) 将之前写的MediaPlayer相关的代码全部移动到Service类中
A. OnCreate()
[java]
view plain
copy
@Override
publicvoid onCreate() { //初始化MediaPlayer
// TODO Auto-generated method stub
super.onCreate();
mPlayer =new MediaPlayer();
try {
mPlayer.setDataSource("/sdcard/test.mp3");
mPlayer.prepare();
} catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
B. OnDestroy()
[java]
view plain
copy
@Override
publicvoid onDestroy() {
// TODO Auto-generated methodstub
super.onDestroy();
mPlayer.release();
}
C. startorpauseMusic()
[java]
view plain
copy
publicboolean startorpauseMusic()
{
boolean playing =false;
if(!mPlayer.isPlaying()){
playing = false;
mPlayer.start();
}
else{
playing = true;
mPlayer.pause();
}
return playing;
}
D. stopMusic()
[java]
view plain
copy
public void stopMusic()
mPlayer.seekTo(0);
mPlayer.stop();
try {
mPlayer.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
4) 通过Binder来保持Activity与Service的通信
[java]
view plain
copy
private IBinder binder = new MyBinderImpl();
@Override
public IBinder onBind(Intentarg0) {
// TODO Auto-generated method stub
return binder;
}
//在主Activity退出时必须解除绑定,否则会抛出异常
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated methodstub
return super.onUnbind(intent);
}
public class MyBinderImpl extends Binderimplements MyBinder
{
@Override
public Service getService() {
// TODO Auto-generated methodstub
return MyService.this;
}
}
5) 在主Activity中调用 bindService 保持与Service的通信:
[java]
view plain
copy
ServiceConnection sc = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName arg0, IBinder binder) {
// TODO Auto-generated method stub
MyBinder myBinder = (MyBinder)binder;
service = (MyService)myBinder.getService();
seekbar.setMax(service.getDuration());
int length = service.getDuration();
int secLength = length/1000+1;
service.onComplete(handler);
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
// TODO Auto-generated method stub
}
};
6) 在Activity中将所有的MediaPlayer的方法都替换为Service里的函数。
7) 在Service中还需要定义的方法:
[java]
view plain
copy
//获取音乐的长度
lic int getDuration()
{
return mPlayer.getDuration();
}
//获取音乐的播放位置
public int getPosition()
{
return mPlayer.getCurrentPosition();
}
//跳转至音乐播放的进程
public void seekto(int progress){
mPlayer.seekTo(progress);
}
4.实验截图
图1 初始化状态
图2 点击播放按钮:播放音乐
显示总时长,以及现在播放的时间,进度条实时更新
图3 点击暂停按钮,暂停播放
显示“已暂停”,停止更新
图4 点击停止按钮,停止播放
当再次点击播放按钮时,音乐从头开始
图5 当音乐播放完后,显示“播放结束!”
图6 关掉运行界面后,
播放器在后台运行仍然运行
图7 项目的文件结构
五、遇到的困难和解决方法
在使用Service作后台处理的时候,忽略了音乐播放结束后的事件触发,无法显示“播放结束”,原来判断音乐播放结束是MediaPlayer的一个方法,无法在Activity里进行,必须要在Service里定义,于是采用使用Handler来传参的方法。具体解决步骤如下:
A. 在Service中定义OnComplete方法:
[java]
view plain
copy
public void onComplete(final Handler handler)
{
MediaPlayer.OnCompletionListener complete = newMediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer arg0) {
// TODO Auto-generated method stub
Message msg = new Message(); //获得消息
msg.arg1 = 0;
handler.sendMessage(msg); //传递给handler
}
};
mPlayer.setOnCompletionListener(complete);
}
B. 在Activity中获取消息:
[java]
view plain
copy
Handler handler = new Handler(){
@Override
public void handleMessage(Messagemsg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if(msg.arg1 == 0)
{
handler.removeCallbacks(updateThread);//移除对线程的调用
bn_play.setImageDrawable(getResources().getDrawable(R.drawable.play));
text.setText("播放结束");
}
}
};
六、附录——main.xml
[html]
view plain
copy
<?xml version="1.0"encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/linearLayout7"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:layout_gravity="center_horizontal"
android:textColor="#0489B1"
android:text="My MusicPlayer" />
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<LinearLayout
android:id="@+id/linearLayout5"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20dp"
android:text="Enjoy yourMusic: " />
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout6"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:text="test.mp3"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout9"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<TextView
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00"
android:textColor="#FFBF00"
android:textSize="18dp"/>
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFBF00"
android:textSize="18dp"
android:text=" / "/>
<TextView
android:id="@+id/alltime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFBF00"
android:textSize="18dp"
android:text="00:00"/>
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout8"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<SeekBar
android:id="@+id/seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal">
<ImageButton
android:id="@+id/bn_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play"/>
<ImageButton
android:id="@+id/bn_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/stop"/>
<Button
android:id="@+id/bn_exit"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="Exit"/>
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
</LinearLayout>
七、参考链接
[1]
http://www.verydemo.com/demo_c131_i30811.html
[2]
http://griffinshi.iteye.com/blog/641037
[3]
http://www.cnblogs.com/newcj/archive/2011/05/30/2061370.html
[4]
http://blog.csdn.net/cjjky/article/details/6552852
[5]
http://www.pocketdigi.com/20100908/92.html
相关文章推荐
- Android 服务与多线程——编写简单的音乐播放器程序
- Android 服务与多线程——编写简单的音乐播放器程序
- C,C++,C#,java,python编写简单的echo服务程序
- android实习程序——音乐播放器(简单播放)
- (转)Ubuntu下用eclipse cdt编写多线程程序的简单设置
- 编写多线程网络检测程序的简单实现
- C# Windows 服务 的简单程序的编写,安装 和 卸载
- 用ndk编写Android环境下的pthread多线程程序
- 简单的Linux环境下多线程TCP服务程序框架
- 编写一个简单的服务程序
- 简单的Linux环境下多线程TCP服务程序框架
- 网络编程与多线程的应用--基于socket udp编写一个简单聊天程序
- VC:简单聊天室程序1 --- 多线程编写网络聊天室程序
- Android 超简单音乐播放器(八)通知栏切换显示更新歌曲 服务和活动之间的相互通信~
- NT服务程序编写
- 用java编写简单UDP网络通信程序
- delphi多线程程序示例(与.net一样简单)
- 用VB编写最简单木马程序
- 用 C 语言编写 Windows 服务程序的五个步骤