Android Service(四) Service使用实例

2,818 阅读4分钟

「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

Android Service实践实例

音乐播放器

分别使用startService和bindService来启动本地服务

我们首先从startService启动Service学起

Activity

public class PlayMusic extends Activity implements OnClickListener {
    private static final String TAG = "PlayMusic";
    private Button playBtn;
    private Button stopBtn;
    private Button pauseBtn;
    private Button exitBtn;
    private Button closeBtn;
 
    //....(详见源码)
 
@Override
    public void onClick(View v) {
        int op = -1;
        Intent intent = new Intent("org.allin.android.musicService");
         
        //广播用
//      Intent intent = new Intent("org.allin.android.musicReceiver");
         
        switch (v.getId()) {
        case R.id.play:
            Log.d(TAG, "onClick: playing muic");
            op = 1;
            break;
        case R.id.stop:
            Log.d(TAG, "onClick: stoping music");
            op = 2;
            break;
        case R.id.pause:
            Log.d(TAG, "onClick: pausing music");
            op = 3;
            break;
        case R.id.close:
            Log.d(TAG, "onClick: close");
            this.finish();
            break;
        case R.id.exit:
            Log.d(TAG, "onClick: exit");
            op = 4;
            stopService(intent);
            this.finish();
            break;
        }
         
        Bundle bundle  = new Bundle();
        bundle.putInt("op", op);
        intent.putExtras(bundle);
        startService(intent);
         
//      sendBroadcast(intent);
    }
 
 
}
​

通过重写onClick方法来实现对播放音乐的控制:

  • 把播放音乐的各种操作用数字的方式通过Intent传递给service
  • 构造一个Intent ,ntent intent = new Intent("org.allin.android.musicService")
  • "org.allin.android.musicService"是在AndroidManifest.xml文件中对service类的定义
<service android:enabled="true" android:name=".MusicService">
<intent-filter>
<action android:name="org.allin.android.musicService" />
</intent-filter>
</service>

Service

把操作码放在Bundle中: Bundle bundle = new Bundle(); bundle.putInt("op", op); intent.putExtras(bundle); 最后使用startService(intent);启动服务。

MusicService.java

public class MusicService extends Service {
 
    private static final String TAG = "MyService";
    private MediaPlayer mediaPlayer;
 
    /*
     * (non-Javadoc)
     * 
     * @see android.app.Service#onBind(android.content.Intent)
     */
    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }
 
    @Override
    public void onCreate() {
        Log.v(TAG, "onCreate");
        if (mediaPlayer == null) {
            mediaPlayer = MediaPlayer.create(this, R.raw.tmp);
            mediaPlayer.setLooping(false);
        }
    }
 
    @Override
    public void onDestroy() {
        Log.v(TAG, "onDestroy");
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
        }
    }
 
    @Override
    public void onStart(Intent intent, int startId) {
        Log.v(TAG, "onStart");
        if (intent != null) {
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
 
                int op = bundle.getInt("op");
                switch (op) {
                case 1:
                    play();
                    break;
                case 2:
                    stop();
                    break;
                case 3:
                    pause();
                    break;
                }
 
            }
        }
 
    }
 
    public void play() {
        if (!mediaPlayer.isPlaying()) {
            mediaPlayer.start();
        }
    }
 
    public void pause() {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
        }
    }
 
    public void stop() {
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            try {
                // 在调用stop后如果需要再次通过start进行播放,需要之前调用prepare函数
                mediaPlayer.prepare();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
 
}

使用了系统自带MediaPlayer进行音乐的播放控制。

当调用了startService后服务会先调用onCreate,我们在里面对MediaPlayer进行初始化。接着会调用onStart,可以看到传递给startService()的Intent对象会传递给onStart()方法,这样我们就可以得到intent里面的操作码: Iundle bundle = intent.getExtras(); int op = bundle.getInt("op");

BroadcastReceiver

有时候如果服务只提供一些操作接口,则可以通过广播的方式来启动服务。

首先要定义一个Receiver,并继承BroadcastReceiver,然后在AndroidManifest.xml中进行注册:

<receiver android:name=".MusicReceiver">
<intent-filter>
<action android:name="org.allin.android.musicReceiver" />
</intent-filter>
</receiver>

MusicReceiver.java

public class MusicReceiver extends BroadcastReceiver {
 
    private static final String TAG = "MusicReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "onReceive");
        Intent it = new Intent("org.allin.android.musicService");
        Bundle bundle = intent.getExtras();
        it.putExtras(bundle);
         
        if(bundle != null){
            int op = bundle.getInt("op");
            if(op == 4){
                context.stopService(it);
            }else{
                context.startService(it);
            }
        }
         
    }
 
}

然后对PlayMusic中的onclick方法进行些改造,把Intent指向Receiver Intent intent = new Intent("org.allin.android.musicReceiver"); intent中绑定的操作码都不变,再调用sendBroadcast(intent);把intentg广播出去。 当MusicReceiver接受到广播后根据操作码进行相应的操作。

使用bindService来启动Service

Activity

public class PlayBindMusic extends Activity implements OnClickListener {
 
    private static final String TAG = "PlayBindMusic";
    private Button playBtn;
    private Button stopBtn;
    private Button pauseBtn;
    private Button exitBtn;
     
    private BindMusicService musicService;
 
    @Override
    public void onClick(View v) {
 
        switch (v.getId()) {
        case R.id.play:
            Log.d(TAG, "onClick: binding srvice");
            musicService.play();
            break;
        case R.id.stop:
            Log.d(TAG, "onClick: stoping srvice");
            if(musicService != null){
                musicService.stop();
            }
            break;
        case R.id.pause:
            Log.d(TAG, "onClick: pausing srvice");
            if(musicService != null){
                musicService.pause();
            }
            break;
        case R.id.exit:
            Log.d(TAG, "onClick: exit");
            this.finish();
            break;
        }
    }
 
 
private void connection(){
        Log.d(TAG, "connecting.....");
        Intent intent = new Intent("org.allin.android.bindService");
        bindService(intent, sc, Context.BIND_AUTO_CREATE);
         
    }
private ServiceConnection sc = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            musicService = null;
            Log.d(TAG, "in onServiceDisconnected");
        }
         
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            musicService = ((BindMusicService.MyBinder)(service)).getService();
            if(musicService != null){
                musicService.play();
            }
             
            Log.d(TAG, "in onServiceConnected");
        }
    };
}

这里使用了bindService(intent, sc, Context.BIND_AUTO_CREATE);来启动服务的, 我们需要定义ServiceConnectionnn,并实现里面的方法,当服务绑定成功后会调用ServiceConnectionnn中的回调函数: public void onServiceConnected(ComponentName name, IBinder service), 回调函数里面使用musicService = ((BindMusicService.MyBinder)(service)).getService();来获取BindMusicService服务对象,有了BindMusicService实例对象,就可以调用服务提供的各种控制音乐播放的功能。

BindMusicService.java

public class BindMusicService extends Service {
 
    private static final String TAG = "MyService";
    private MediaPlayer mediaPlayer;
 
    private final IBinder binder = new MyBinder();
 
    public class MyBinder extends Binder {
        BindMusicService getService() {
            return BindMusicService.this;
        }
    }
 
    /*
     * (non-Javadoc)
     * 
     * @see android.app.Service#onBind(android.content.Intent)
     */
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");
        play();
        return binder;
    }
 
    @Override
    public void onCreate() {
        super.onCreate();
         
        Log.d(TAG, "onCreate");
        Toast.makeText(this, "show media player", Toast.LENGTH_SHORT).show();
         
         
    }
 
    @Override
    public void onDestroy() {
        super.onDestroy();
         
        Log.d(TAG, "onDestroy");
        Toast.makeText(this, "stop media player", Toast.LENGTH_SHORT);
        if(mediaPlayer != null){
            mediaPlayer.stop();
            mediaPlayer.release();
        }
    }
 
     
    public void play() {
        if (mediaPlayer == null) {
            mediaPlayer = MediaPlayer.create(this, R.raw.tmp);
            mediaPlayer.setLooping(false);
        }
        if (!mediaPlayer.isPlaying()) {
            mediaPlayer.start();
        }
    }
 
    public void pause() {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
        }
    }
 
    public void stop() {
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            try {
                // 在调用stop后如果需要再次通过start进行播放,需要之前调用prepare函数
                mediaPlayer.prepare();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
 
}

可以看到Service中有个返回IBinder对象的onBind方法,这个方法会在Service被绑定到其他程序上时被调用,而这个IBinder对象和之前看到的onServiceConnected方法中传入的那个IBinder是同一个东西。应用和Service间就依靠这个IBinder对象进行通信。

下一篇将会介绍通过AIDL对Service进行远程调用。