Android中bindService的使用及Service生命周期

Android中有两种主要方式使用Service,通过调用Context的startService方法或调用Context的bindService方法,本文只探讨纯bindService的使用,不涉及任何startService方法调用的情况。如果想了解startService相关的使用,请参见《Android中startService的使用及Service生命周期》。

bindService启动服务的特点

相比于用startService启动的Service,bindService启动的服务具有如下特点: 1. bindService启动的服务在调用者和服务之间是典型的client-server的接口,即调用者是客户端,service是服务端,service就一个,但是连接绑定到service上面的客户端client可以是一个或多个。这里特别要说明的是,这里所提到的client指的是组件,比如某个Activity。 2. 客户端client(即调用bindService的一方,比如某个Activity)可以通过IBinder接口获取Service的实例,从而可以实现在client端直接调用Service中的方法以实现灵活的交互,并且可借助IBinder实现跨进程的client-server的交互,这在纯startService启动的Service中是无法实现的。 3. 不同于startService启动的服务默认无限期执行(可以通过Context的stopService或Service的stopSelf方法停止运行),bindService启动的服务的生命周期与其绑定的client息息相关。当client销毁的时候,client会自动与Service解除绑定,当然client也可以通过明确调用Context的unbindService方法与Service解除绑定。当没有任何client与Service绑定的时候,Service会自行销毁(通过startService启动的除外)。 4. startService和bindService二者执行的回调方法不同:startService启动的服务会涉及Service的的onStartCommand回调方法,而通过bindService启动的服务会涉及Service的onBind、onUnbind等回调方法。

bindService代码示例

使用bindService主要分两种情形: 1. Service的调用者client与Service在同一个App中; 2. Service的调用者client是App1中的一个Activity,而Service是App2中的Service,client与service分属两个App,这种情形下主要用于实现跨进程的通信。

为了简单起见,本文只讨论第一种情形,即Service的调用者client与Service在同一个App中,该情形也是我们在实际开发中用到最多的情形。下面我们通过一个例子演示一下第一种情形下bindService的基本使用流程。

首先我们有一个TestService,该类继承自Service,其是client-server接口中的server端。我们在其主要的生命周期回调方法中都加入了输出语句。TestService代码如下:

package com.ispring.startservicedemo;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.util.Log;import java.util.Random;{{public TestService getService(){return TestService.this;}}//通过binder实现调用者client与Service之间的通信private MyBinder binder = new MyBinder();private final Random generator = new Random();() {Log.i(“DemoLog”,”TestService -> onCreate, Thread: ” + Thread.currentThread().getName());super.onCreate();}(Intent intent, int flags, int startId) {Log.i(“DemoLog”, “TestService -> onStartCommand, startId: ” + startId + “, Thread: ” + Thread.currentThread().getName());return START_NOT_STICKY;}@Overridepublic IBinder onBind(Intent intent) {Log.i(“DemoLog”, “TestService -> onBind, Thread: ” + Thread.currentThread().getName());return binder;}(Intent intent) {Log.i(“DemoLog”, “TestService -> onUnbind, from:” + intent.getStringExtra(“from”));return false;}() {Log.i(“DemoLog”, “TestService -> onDestroy, Thread: ” + Thread.currentThread().getName());super.onDestroy();}(){return generator.nextInt();}}

在该App中,除了TestService,还有两个Activity: ActivityA和ActivityB,它们都是Service的调用者,即client-server接口中的client。

ActivityA是App的启动界面,界面如下:

ActivityA的代码如下:

package com.ispring.startservicedemo;import android.app.Activity;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.util.Log;import android.view.View;import android.widget.Button;.OnClickListener {private TestService service = null;private boolean isBound = false;private ServiceConnection conn = new ServiceConnection() {(ComponentName name, IBinder binder) {isBound = true;TestService.MyBinder myBinder = (TestService.MyBinder)binder;service = myBinder.getService();Log.i(“DemoLog”, “ActivityA onServiceConnected”);int num = service.getRandomNumber();Log.i(“DemoLog”, “ActivityA 中调用 TestService的getRandomNumber方法, 结果: ” + num);}(ComponentName name) {isBound = false;Log.i(“DemoLog”, “ActivityA onServiceDisconnected”);}};(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_a);Log.i(“DemoLog”, “ActivityA -> onCreate, Thread: ” + Thread.currentThread().getName());}(View v) {if(v.getId() == R.id.btnBindService){//单击了“bindService”按钮Intent intent = new Intent(this, TestService.class);intent.putExtra(“from”, “ActivityA”);Log.i(“DemoLog”, “———————————————————————-“);Log.i(“DemoLog”, “ActivityA 执行 bindService”);bindService(intent, conn, BIND_AUTO_CREATE);}else if(v.getId() == R.id.btnUnbindService){//单击了“unbindService”按钮if(isBound){Log.i(“DemoLog”, “———————————————————————-“);Log.i(“DemoLog”, “ActivityA 执行 unbindService”);unbindService(conn);}}else if(v.getId() == R.id.btnStartActivityB){//单击了“start ActivityB”按钮Intent intent = new Intent(this, ActivityB.class);Log.i(“DemoLog”, “———————————————————————-“);Log.i(“DemoLog”, “ActivityA 启动 ActivityB”);startActivity(intent);}else if(v.getId() == R.id.btnFinish){//单击了“Finish”按钮Log.i(“DemoLog”, “———————————————————————-“);Log.i(“DemoLog”, “ActivityA 执行 finish”);this.finish();}}() {super.onDestroy();Log.i(“DemoLog”, “ActivityA -> onDestroy”);}}

通过单击ActivityA上的“start ActivityB”可以启动ActivityB,ActivityB的界面如下:

勇于接受自己的不完美,认清自己不足的地方,

Android中bindService的使用及Service生命周期

相关文章:

你感兴趣的文章:

标签云: