9.3.3 活动和服务进行通讯android
上一小节中咱们学习了启动和中止服务的方法,不知道你有没有发现,虽然服务是在活 动里启动的,但在启动了服务以后,活动与服务基本就没有什么关系了。确实如此,咱们在 活动里调用了 startService()方法来启动 MyService 这个服务,而后 MyService 的 onCreate()和 onStartCommand()方法就会获得执行。以后服务会一直处于运行状态,但具体运行的是什么 逻辑,活动就控制不了了。这就相似于活动通知了服务一下:“你能够启动了!”而后服务就 去忙本身的事情了,但活动并不知道服务到底去作了什么事情,以及完成的如何。ide
那么有没有什么办法能让活动和服务的关系更紧密一些呢?例如在活动中指挥服务去 干什么,服务就去干什么。固然能够,这就须要借助咱们刚刚忽略的 onBind()方法了。布局
好比说目前咱们但愿在 MyService 里提供一个下载功能,而后在活动中能够决定什么时候开 始下载,以及随时查看下载进度。实现这个功能的思路是建立一个专门的 Binder 对象来对下 载功能进行管理,修改 MyService 中的代码,以下所示:学习
public class MyService extends Service {测试
private DownloadBinder mBinder = new DownloadBinder();this
class DownloadBinder extends Binder {spa
public void startDownload() {日志
Log.d("MyService", "startDownload executed");xml
}对象
public int getProgress() {
Log.d("MyService", "getProgress executed");
return 0;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
……
}
能够看到,这里咱们新建了一个 DownloadBinder 类,并让它继承自 Binder,而后在它 的内部提供了开始下载以及查看下载进度的方法。固然这只是两个模拟方法,并无实现真 正的功能,咱们在这两个方法中分别打印了一行日志。
接着,在 MyService 中建立了 DownloadBinder 的实例,而后在 onBind()方法里返回了这 个实例,这样 MyService 中的工做就所有完成了。
下面就要看一看,在活动中如何去调用服务里的这些方法了。首先须要在布局文件里新 增两个按钮,修改 activity_main.xml 中的代码,以下所示:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical" >
……
<Button android:id="@+id/bind_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Bind Service" />
<Button android:id="@+id/unbind_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Unbind Service" />
</LinearLayout>
这两个按钮分别是用于绑定服务和取消绑定服务的,那到底谁须要去和服务绑定呢?当 然就是活动了。当一个活动和服务绑定了以后,就能够调用该服务里的 Binder 提供的方法了。 修改 MainActivity 中的代码,以下所示:
public class MainActivity extends Activity implements OnClickListener {
private Button startService; private Button stopService; private Button bindService; private Button unbindService;
private MyService.DownloadBinder downloadBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) { downloadBinder = (MyService.DownloadBinder) service; downloadBinder.startDownload();
downloadBinder.getProgress();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
……
bindService = (Button) findViewById(R.id.bind_service); unbindService = (Button) findViewById(R.id.unbind_service); bindService.setOnClickListener(this);
unbindService.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
……
case R.id.bind_service:
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE); // 绑定服务
break;
case R.id.unbind_service:
unbindService(connection); // 解绑服务
break;
default:
break;
}
}
}
能够看到,这里咱们首先建立了一个 ServiceConnection 的匿名类,在里面重写了 onServiceConnected()方法和 onServiceDisconnected()方法,这两个方法分别会在活动与服务 成功绑定以及解除绑定的时候调用。在 onServiceConnected()方法中,咱们又经过向下转型 获得了 DownloadBinder 的实例,有了这个实例,活动和服务之间的关系就变得很是紧密了。 如今咱们能够在活动中根据具体的场景来调用 DownloadBinder 中的任何 public 方法,即实 现了指挥服务干什么,服务就去干什么的功能。这里仍然只是作了个简单的测试,在 onServiceConnected()方法中调用了 DownloadBinder 的 startDownload()和 getProgress()方法。
固然,如今活动和服务其实还没进行绑定呢,这个功能是在 Bind Service 按钮的点击事 件里完成的。能够看到,这里咱们仍然是构建出了一个 Intent 对象,而后调用 bindService() 方法将 MainActivity 和 MyService 进行绑定。bindService()方法接收三个参数,第一个参数就 是刚刚构建出的 Intent 对象,第二个参数是前面建立出的 ServiceConnection 的实例,第三个 参数则是一个标志位,这里传入 BIND_AUTO_CREATE 表示在活动和服务进行绑定后自动 建立服务。这会使得 MyService 中的 onCreate()方法获得执行,但 onStartCommand()方法不 会执行。
而后若是咱们想解除活动和服务之间的绑定该怎么办呢?调用一下 unbindService()方法 就能够了,这也是 Unbind Service 按钮的点击事件里实现的功能。
如今让咱们从新运行一下程序吧,界面如图 9.9 所示。
图 9.9
点击一下 Bind Service 按钮,而后观察 LogCat 中的打印日志如图 9.10 所示:
图 9.10
能够看到,首先是 MyService 的 onCreate() 方法获得了执行,而后 startDownload() 和getProgress()方法都获得了执行,说明咱们确实已经在活动里成功调用了服务里提供的方法了。 另外须要注意,任何一个服务在整个应用程序范围内都是通用的,即 MyService 不只可以和 MainActivity 绑定,还能够和任何一个其余的活动进行绑定,并且在绑定完成后它们都 能够获取到相同的 DownloadBinder 实例。