创建Service开发步骤
上一篇文章中我们完成了步骤【1】,下面我们来完善剩下的步骤。
【2】开发 Service
1)创建并注册 Service
a)创建 PlayMusicService
b)注册
2)在 Service 内部完成播放控制相关方法,例如 play() 等
a)声明 MediaPlayer
b)声明数据源 List<Music>
c)声明必要变量,例如 currentMusicIndex、pausePosition
d)在 onCreate()
中初始化 MediaPlayer、List<Music>
e)添加歌曲的播放控制相关方法,包括:void play()
、void play(int position)
、void pause()
、void previous()
、void next()
按照步骤2开发Service
创建 PlayMusicService
public class PlayMusicService extends Service {
public PlayMusicService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
AndroidManifest 注册
<service
android:name=".service.PlayMusicService"
android:enabled="true"
android:exported="true"></service>
在 MainActivity 中启动 service
public class MainActivity extends AppCompatActivity {
......
@Override
protected void onCreate(Bundle savedInstanceState) {
......
//激活Service
Intent intent = new Intent(this, PlayMusicService.class);
startService(intent);
}
......
}
PlayMusicService 中获取数据的时候虽然可以用
musics = MusicDaoFactory.newInstance(this).getData();
得到数据,但是我们的 MainActivity 中执行了一次getData()
,PlayMusicService 中又执行了一次,不合理。我们这时就要用到 Application
新建 MusicPlayerApplication
public class MusicPlayerApplication extends Application {
private List<Music> musics;
@Override
public void onCreate() {
super.onCreate();
musics = MusicDaoFactory.newInstance(this).getData();
}
public List<Music> getMusics() {
return musics;
}
}
在 AndroidManifest 中注册
<application
android:name=".MusicPlayerApplication"
......>
</application>
我们在 MainActivity 和 PlayMusicService 中获取数据的代码需要修改
MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
//获取数据
MusicPlayerApplication application = (MusicPlayerApplication)getApplication();
musics = application.getMusics();
adapter = new MusicAdapter(this, musics);
listView.setAdapter(adapter);
......
}
PlayMusicService 增加其他播放方法,完整的PlayMusicService代码如下
public class PlayMusicService extends Service {
private MediaPlayer player;
private List<Music> musics;
private int currentMusicIndex;
private int pausePosition;
@Override
public void onCreate() {
player = new MediaPlayer();
player.setOnCompletionListener(mediaPlayer -> next());
//获取数据
MusicPlayerApplication application = (MusicPlayerApplication) getApplication();
musics = application.getMusics();
}
//播放
private void play() {
try {
player.reset();
player.setDataSource(musics.get(currentMusicIndex).getPath());
player.prepare();
player.seekTo(pausePosition);
player.start();
} catch (IOException e) {
e.printStackTrace();
}
}
//播放指定位置歌曲
private void play(int position) {
currentMusicIndex = position;
pausePosition = 0;
play();
}
//暂停
private void pause() {
player.pause();
pausePosition = player.getCurrentPosition();
}
//上一首
private void priviout() {
currentMusicIndex--;
if (currentMusicIndex < 0) {
currentMusicIndex = musics.size() - 1;
}
pausePosition = 0;
play();
}
//播放下一首
private void next() {
currentMusicIndex++;
if (currentMusicIndex >= musics.size()) {
currentMusicIndex = 0;
}
pausePosition = 0;
play();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
实现基本控制开发步骤
【3】实现基本控制
1)实现播放和暂停功能
a)在 Activity 声明并初始化相关控件,并配置监听器
b)点击监听方式中,发送广播,使用“频道号”标识要求执行的操作是“播放或暂停”
c)在 Service 中使用内部类创建广播接受者,并动态注册接收 Activity 发送的广播,并根据当前的播放状态决定调用播放或暂停方法
d)在 Service 的播放和暂停方法中,分别发送广播,要求 Activity 把界面显示设置为播放或暂停状态
e)在 Activity 中使用内部创建广播接受者,并动态注册接收 Service 发送的 2 种广播,根据广播的“频道号”设置界面显示
f)在 Activity 和 Service 的 onDestroy()
中注销各自广播接收者
2)使用类似的模式实现上一首、下一首
3)使用类似的模式实现播放指定歌曲
按照步骤3实现基本控制
我们按照开发步骤,写下重点代码
MainActivity 中增加播放按钮的点击事件
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
......
private void setListeners() {
ibPlay.setOnClickListener(this);
}
......
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ib_play:
//发送广播
sendBroadcast(new Intent("play or pause"));
break;
default:
break;
}
}
}
PlayMusicService 中自定义广播接收者
public class PlayMusicService extends Service {
......
//内部广播接收者对象
private InnerReceiver receiver;
@Override
public void onCreate() {
......
//注册广播接收者
receiver = new InnerReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("play or pause");
registerReceiver(receiver, filter);
}
......
/**
* 内部广播接收者
*/
private class InnerReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//获取广播中的Action
String action = intent.getAction();
//判断Action
if ("play or pause".equals(action)) {
//判断应该播放或暂停
if (player.isPlaying()) {
pause();
} else {
play();
}
}
}
}
@Override
public void onDestroy() {
//注销广播接收者
unregisterReceiver(receiver);
super.onDestroy();
}
}
这样播放或暂停功能就做好了,但播放按钮的状态没有改变,下面我们在 PlayMusicService 中发送广播来通知 MainActivity 改变按钮样式
//播放
private void play() {
try {
......
//发送广播要求界面显示为播放状态
//发送广播要求界面显示为播放状态
Intent intent = new Intent("set play state");
sendBroadcast(intent);
} catch (IOException e) {
e.printStackTrace();
}
}
//暂停
private void pause() {
......
//发送广播要求界面显示为暂停状态
Intent intent = new Intent("set pause state");
sendBroadcast(intent);
}
MainActivity 按照同样的方式接收广播
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
......
private InnerReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
......
//注册广播接收者
receiver = new InnerReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("set play state");
filter.addAction("set pause state");
registerReceiver(receiver,filter);
}
......
private class InnerReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if ("set play state".equals(action)) {
ibPlay.setImageResource(android.R.drawable.ic_media_pause);
} else if ("set pause state".equals(action)) {
ibPlay.setImageResource(android.R.drawable.ic_media_play);
}
}
}
@Override
protected void onDestroy() {
//注销广播接收者
unregisterReceiver(receiver);
super.onDestroy();
}
}
同样的方法增加上一首和下一首按钮的功能。
下面说一下点击 Listview 播放相应歌曲的实现
MainActivity
package com.example.musicapplication.activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.example.musicapplication.R;
import com.example.musicapplication.adapter.MusicAdapter;
import com.example.musicapplication.app.MusicPlayerApplication;
import com.example.musicapplication.entity.Music;
import com.example.musicapplication.service.PlayMusicService;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener, AdapterView.OnItemClickListener {
......
private void setListeners() {
......
listView.setOnItemClickListener(this);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent();
intent.setAction("play appoint");
intent.putExtra("position", position);
sendBroadcast(intent);
}
......
}
PlayMusicService
public class PlayMusicService extends Service {
......
@Override
public void onCreate() {
......
//注册广播接收者
receiver = new InnerReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("play or pause");
filter.addAction("play appoint");
registerReceiver(receiver, filter);
}
......
/**
* 内部广播接收者
*/
private class InnerReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//获取广播中的Action
String action = intent.getAction();
//判断Action
if ("play or pause".equals(action)) {
......
} else if ("play appoint".equals(action)) {
int position = intent.getIntExtra("position", 0);
play(position);
}
}
}
......
}