(5)bindservice不能多次解绑 多次解绑会报错
总结:
混合方式开启服务
(1)先调用startService()方法 保证服务在后台长期运行
(2)调用bindservice()目的获取我们定义的中间人对象 调用服务里面的方法
(3)unbindservice() 看这时候服务会不会销毁
(4)最后调用stopservice() 停止服务 :
通过bindservice方式调用服务方法里面的过程:
(1)定义一个服务 服务里面有一个方法需要Activity调用
(2)定义一个中间人对象(IBinder) 继承Binder;
(3)在onbind方法里面把我们定义的中间人对象返回
(4)在Activity的oncreate 方法里面调用bindservice 目的是为来获取我们定义的中间人对象
(4.1)获取中间人对象
(5)拿到中间人对象后就可以间接的调用到服务里面的方法
百度音乐盒案例:
在软件开发中,一般不会只是单一的使用startservice(),或者是bindService,而是两种相结合。下面这个小程序,则演示了两者服务同时使用需求:我既想让服务在后台长期运行 又想调用服务里面的方法
UI:
Mainactivity代码:
package com.itheima.baidumusic;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
public class MainActivity extends Activity {
private Iservice iservice; // 这个就是我们定义的中间人对象
private MyConn conn;
private static SeekBar sbar;
public static Handler handler = new Handler(){
//当 接收到消息该方法执行
public void handleMessage(android.os.Message msg) {
//[1]获取msg 携带的数据
Bundle data = msg.getData();
//[2]获取当前进度和总进度
int duration = data.getInt("duration");
int currentPosition = data.getInt("currentPosition");
//[3]设置seekbar的最大进度和当前进度
sbar.setMax(duration); //设置进度条的最大值
sbar.setProgress(currentPosition);//设置当前进度
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sbar = (SeekBar) findViewById(R.id.seekBar1);
//[0]先调用startservice 方法开启服务 保证服务在后台长期运行
Intent intent = new Intent(this, MusicService.class);
startService(intent);
// [1]调用bindservice 目的是为了获取我们定义的中间人对象
conn = new MyConn();
// 连接MusicService 服务 获取我们定义的中间人对象
bindService(intent, conn, BIND_AUTO_CREATE);
//[2]给seekbar 设置监听
sbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
//当停止拖动执行
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
//设置播放的位置
iservice.callSeekToPosition(seekBar.getProgress());
}
//开始拖动
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
}
});
}
// 点击按钮 进行 音乐播放
public void click1(View v) {
// 调用播放音乐的方法
iservice.callPlayMusic();
}
// 暂停音乐
public void click2(View v) {
// 调用暂停音乐的方法
iservice.callPauseMusic();
}
// 继续播放
public void click3(View v) {
// 调用继续播放
iservice.callrePlayMusic();
}
// 当Activity销毁的时候调用
@Override
protected void onDestroy() {
// 在Activity销毁的时候 取消绑定服务
unbindService(conn);
super.onDestroy();
}
private class MyConn implements ServiceConnection {
// 当连接成功时候调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 获取我们定义的中间人对象
iservice = (Iservice) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
}
MusicService代码如下:
package com.itheima.baidumusic;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
//音乐播放服务
public class MusicService extends Service {
private MediaPlayer player;
//[2]把我们定义的中间人对象 返回
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
//服务第一次开启的是调用
@Override
public void onCreate() {
//[1]初始化mediaplayer
player = new MediaPlayer();
super.onCreate();
}
//当服务销毁的时候调用
@Override
public void onDestroy() {
super.onDestroy();
}
//设置播放音乐指定位置的方法
public void seekToPosition(int position){
player.seekTo(position);
}
//专门用来播放音乐的
public void playMusic(){
System.out.println("音乐播放了");
//[2]设置要播放的资源 path 可以是本地也可是网络路径
try {
player.reset();
player.setDataSource("/mnt/sdcard/xpg.mp3");
//[3]准备播放
player.prepare();
//[4]开始播放
player.start();
//[5]更新进度条
updateSeekBar();
} catch (Exception e) {
e.printStackTrace();
}
}
//更新进度条的方法
private void updateSeekBar() {
//[1]获取当前歌曲总时长
final int duration = player.getDuration();
//[2]一秒钟获取一次当前进度
final Timer timer = new Timer();
final TimerTask task = new TimerTask() {
@Override
public void run() {
//[3]获取当前歌曲的进度
int currentPosition = player.getCurrentPosition();
//[4]创建message对象
Message msg = Message.obtain();
//[5]使用msg携带多个数据
Bundle bundle = new Bundle();
bundle.putInt("duration", duration);
bundle.putInt("currentPosition", currentPosition);
msg.setData(bundle);
//发送消息 MainActivity的handlemessage方法会执行
MainActivity.handler.sendMessage(msg);
}
};
//300毫秒后 每隔1秒钟获取一次当前歌曲的进度
timer.schedule(task, 300, 1000);
//[3]当歌曲播放完成的时候 把timer 和task 取消
player.setOnCompletionListener(new OnCompletionListener() {
//当歌曲播放完成的回调
@Override
public void onCompletion(MediaPlayer mp) {
System.out.println("歌曲播放完成了 ");
timer.cancel();
task.cancel();
}
});
}
//音乐暂停了
public void pauseMusic(){
System.out.println("音乐暂停了");
//暂停
player.pause();
}
//音乐继续播放的方法
public void rePlayMusic(){
System.out.println("音乐继续播放了");
player.start();
}
//[1]定义一个中间人对象(IBinder)
private class MyBinder extends Binder implements Iservice{
//调用播放音乐的方法
@Override
public void callPlayMusic() {
playMusic();
}
//调用暂停音乐的方法
@Override
public void callPauseMusic() {
pauseMusic();
}
//调用继续播放的方法
@Override
public void callrePlayMusic() {
rePlayMusic();
}
//调用设置播放指定位置的方法
@Override
public void callSeekToPosition(int position) {
seekToPosition(position);
}
}
}
接口Iservice的具体代码:
package com.itheima.baidumusic;
public interface Iservice {
//把我们想暴露的方法放到接口中
public void callPlayMusic();
public void callPauseMusic();
public void callrePlayMusic();
public void callSeekToPosition(int position);
}