一、实验目的和要求
- 理解Service组件: 通过本实验,加深对Android Service组件的理解,包括它的生命周期、运行方式以及如何与Activity进行交互。
- 掌握后台播放音乐: 学习如何在后台使用Service组件播放音乐,实现音乐播放的持续性,即使用户切换应用或屏幕关闭。
- 学习Intent和BroadcastReceiver的使用: 通过实现音乐播放器的控制(播放、暂停、停止),掌握使用Intent传递信息和使用BroadcastReceiver监听广播事件的技巧。
- 提高UI更新技能: 学习如何根据Service的状态更新Activity界面,例如更新播放、暂停按钮的状态或显示当前播放的音乐信息。
- 实验原理(技术分析)、方法与步骤
- 实验原理
Service 组件原理:Service 是 Android 中运行在后台的一种组件,它可以执行长时间运行的操作,不提供用户界面。ervice 可以是启停的(StartStop),也可以是绑定的(Bound),本项目中主要使用启停Service。
音乐播放原理:使用 MediaPlayer 类来加载和播放音乐文件。
广播通信原理:使用 BroadcastReceiver 和 Intent 来实现组件间的消息传递。当音乐播放状态改变时,Service 发送广播通知界面更新。
生命周期管理:理解 Service 的生命周期,包括 onCreate(), onStartCommand(), onDestroy() 等方法。
界面更新原理:使用 Handler 或 BroadcastReceiver 来实现从 Service 到 Activity 的通信,更新UI。
实验方法与步骤
- 创建一个新的Android Studio项目。
- 设置项目的最小SDK版本和目标SDK版本。
- 使用XML布局文件设计播放器创建一个Activity来承载计算器的UI界面。
- 编写MainActivity用于实现前台Activity。
- 编写Music Service用于实现后台Service。
- MainActivity
public class MainActivity extends Activity implements OnClickListener{ //获取界面中的显示歌曲标题,作者文本框 TextView title, author; //播放、暂停 终止按钮 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"; // 定文音乐的播放状态,0x11 代表没有播放:0x12 代表正在播放:0x13 代表暂停 int status = 0x11; String[] titleStrs = new String[]{"心愿", "约定", "美丽新世界"}; String[] authorStrs = new String[]{"未知艺术家", "周蕙", "伍佰"}; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //获取程序界面中的两个按钮 play = (ImageButton) this.findViewById(R.id.play); stop = (ImageButton) this.findViewById(R.id.stop); title = (TextView) findViewById(R.id.titlel); author = (TextView) findViewById(R.id.author); //为两个按钮的单击事件添加监听器 play.setOnClickListener(this); stop.setOnClickListener(this); activityReceiver = new ActivityReceiver(); // 创建Intenteilter IntentFilter filter = new IntentFilter(); // 指定 BroadcastReceiver 监听的 Action filter.addAction(UPDATE_ACTION); //注册 BroadcastReceiver registerReceiver(activityReceiver, filter); Intent intent = new Intent(this, MusicService.class); // 启动后台 Service 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(authorStrs[current]); } switch(update) { case 0x11: play.setImageResource(R.drawable.ic_play1); status = 0x11; break; //控制系统进入播放状态 case 0x12: //在播放状态下设置使用暂停图标 play.setImageResource(R.drawable.ic_stop1); //设置当前状态 status = 0x12; break; case 0x13: play.setImageResource(R.drawable.ic_play1); status = 0x13; break; } } } @Override public void onClick(View source) { Intent intent = new Intent("org.crazyit.action.CTL_ACTION"); switch (source.getId()) { case R.id.play: intent.putExtra("control",1); break; case R.id.stop: intent.putExtra("control",2); break; } sendBroadcast(intent); } }
- Music Service
public class MusicService extends Service { MyReceiver serviceReceiver; AssetManager am; String[] musics = new String[] {"wish.mp3","promise.mp3","beautiful.mp3"}; MediaPlayer mPlayer; int status = 0x11; int current = 0; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); am=getAssets(); serviceReceiver=new MyReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction(MainActivity.CTL_ACTION); registerReceiver(serviceReceiver,filter); mPlayer=new MediaPlayer(); mPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp){ current++; if (current >= 3){ current = 0; } Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION); sendIntent.putExtra("current",current); sendBroadcast(sendIntent); prepareAndPlay(musics[current]); } }); } public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(final 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; } } Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION); sendIntent.putExtra("update",status); sendIntent.putExtra("current",current); sendBroadcast(sendIntent); } } private void prepareAndPlay(String music) { try { AssetFileDescriptor afd = am.openFd(music); mPlayer.reset(); mPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); mPlayer.prepare(); mPlayer.start(); } catch (IOException e) { e.printStackTrace(); } } }
- Maim.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/titlel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/song_title"
android:textSize="24sp"
android:textStyle="bold"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp" />
<TextView
android:id="@+id/author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/song_author"
android:textSize="18sp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="4dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center_horizontal"
android:layout_marginTop="32dp">
<ImageButton
android:id="@+id/play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/play_button"
android:src="@drawable/ic_play1" />
<ImageButton
android:id="@+id/stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_stop1"
android:contentDescription="@string/stop_button"
android:layout_marginLeft="16dp" />
</LinearLayout>
</LinearLayout>