前言:闲着也是闲着,不如多学点东西
下面的程序开发了一个基于Service组件的音乐盒,程序的音乐将会由后台运行的Service组件负责播放,当后台的播放状态发生改变时,程序将会通过发生广播通知前台Activity更新界面;当用户单击前台Activity的界面按钮时,系统将通过发送广播通知后台Service来改变播放状态。
Activity界面代码如下:
package com.example.musicproject;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener{
private TextView title,author;
private ImageButton play,stop;
ActivityReceiver activityReceiver;
public static final String CTL_ACTION="org.crazyit.action.CTL_ACTION";
public static final String UPDATE_ACTION="org.crazyit.action.UPDATE_ACTION";
//定义音乐的播放状态
int status = 0x11;
String[] titleStrs = new String[]{"心愿","约定","美丽"};
String[] autorStrs = new String[]{"未知艺术照","作者1","作者2"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
title = (TextView) findViewById(R.id.title);
author = (TextView) findViewById(R.id.author);
play = (ImageButton) findViewById(R.id.play);
stop = (ImageButton) findViewById(R.id.stop);
play.setOnClickListener(this);
stop.setOnClickListener(this);
//广播
IntentFilter filter = new IntentFilter();
filter.addAction(UPDATE_ACTION);
registerReceiver(activityReceiver, filter);
//服务
Intent intent = new Intent(this,MusicService.class);
startService(intent);
}
//自定义的BroadcastReceiver,负责监听从service传回来的广播
public class ActivityReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// 获取Intent中的update消息,update代表播放状态
int update = intent.getIntExtra("update", -1);
//获取Intent中的current消息,current代表正在播放的歌曲
int current = intent.getIntExtra("current", -1);
if(current>=0){
title.setText(titleStrs[current]);
author.setText(autorStrs[current]);
}
switch (update) {
case 0x11:
play.setImageResource(R.drawable.button_grey_play);
status = 0x11;
break;
//进入播放
case 0x12:
play.setImageResource(R.drawable.gnome_session_suspend);
status = 0x12;
break;
//进入暂停
case 0x13:
play.setImageResource(R.drawable.button_grey_play);
status = 0x13;
break;
default:
break;
}
}
}
@Override
public void onClick(View v) {
// 创建Intent
Intent intent = new Intent("org.crazyit.action.CTL_ACTION");
switch (v.getId()) {
//按下播放、暂停按钮
case R.id.play:
intent.putExtra("contorl", 1);
break;
//按下停止按钮
case R.id.stop:
intent.putExtra("contorl", 2);
break;
default:
break;
}
}
}
上面代码关键地方有2处。
1)在ActivityReceiver中,代码主要用于相应后台Service所发出的广播,该程序将会根据广播Intent里的消息来改变播放状态,并更新程序界面中按钮的图标;当正在播放时,显示暂停图标;当正在暂停时,显示播放图表。并根据传回来的current数据来更新title.author两个文本框所显示的文本------显示当前正在播放的歌曲的歌名和歌手。
2)第二段粗体代码则根据用户单击的按钮发送广播,发送广播时会把所按下的按钮的标识发送出来。发送的广播将激发后台Service的BroadcastReceiver,该BroadcastReceiver将会根据广播消息来改变播放状态。
与之对应收到是,该程序的后台Service也一样,他会在播放状态发生改变时对外发送广播;它也会采用BroadcastReceiver监听来自前台Activity所发出的广播。
package com.example.musicproject;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.IBinder;
public class MusicService extends Service{
MyReceiver serviceReceiver;
AssetManager am;
String[] musics = new String[]{"wish.mp3","promise.mp3","beautiful.mp3"};
MediaPlayer mPlayer;
//当前的状态,0x11表示没有播放,0x22表示正在播放,0x33表示暂停
int status = 0x11;
//记录当前正在播放的音乐
int current = 0;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
am = getAssets();
//创建BroadcastReceiver
serviceReceiver =new MyReceiver();
//创建IntentFilter
IntentFilter filter = new IntentFilter();
filter.addAction(MainActivity.CTL_ACTION);
registerReceiver(serviceReceiver, filter);
//创建MediaPlayer
mPlayer = new MediaPlayer();
//为MediaPlayer播放完成事件绑定监听器
mPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
current++;
if(current >=3){
current = 0;
}
//发送广播通知Activity更改文本框
Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION);
sendIntent.putExtra("current", current);
//发送广播,将被Activity组件中的BroadcastReceiver接收到
sendBroadcast(sendIntent);
//准备并播放音乐
prepareAndPlay(musics[current]);
}
});
super.onCreate();
}
private void prepareAndPlay(String music) {
// TODO Auto-generated method stub
try {
//打开指定音乐文件
AssetFileDescriptor afd = am.openFd(music);
mPlayer.reset();
//使用MediaPlayer加载指定的声音文件
mPlayer.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength());
//准备声音
mPlayer.prepare();
//播放
mPlayer.start();
} catch (Exception e) {
// TODO: handle exception
}
}
public class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
int control = intent.getIntExtra("control", -1);
switch (control) {
case 1:
//原来处于没有播放状态
if(status == 0x11){
prepareAndPlay(musics[current]);
status = 0x12;
}
//原来处于播放状态
else if(status == 0x12){
//暂停
mPlayer.pause();
//改变为暂停状态
status = 0x13;
}
//原来处于暂停状态
else if(status == 0x13){
//播放
mPlayer.start();
//改变状态
status= 0x12;
}
break;
case 2:
//如果原来正在播放或者正在播放或者暂停状态
if(status == 0x12 || status == 0x13){
//停止播放
mPlayer.stop();
status=0x11;
}
break;
default:
break;
}
//广播通知Activity更改图标,文本框
Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION);
sendIntent.putExtra("update", status);
sendIntent.putExtra("current", current);
//发送广播,将被Activity组件中的BroadcastReceiver接收到
sendBroadcast(sendIntent);
}
}
}
除此之外,为了让该程序能按顺序依次播放每首歌曲,程序为MediaPlayer增加了ONCompletionListener监听器,当MediaPlayer播放完成后将让它自动播放下一首歌曲。