断断续续学Android也有1年多了,内心一直摇摆不定,犹豫着要不要往这方向发展下去。因为自己是C++出身的,对语言这方面内心总有那么点偏见;经过1年多的徘徊,总算认清了事实,开发你总得基于某一平台吧,而市面上基于纯C++开发的太少了(主要是自己能力不够);自己身边目标明确的同事,他们成长的速度快得惊人,看着就很是嫉妒,所以啊,我也必须找准目标,然后锲而不舍。先从Android应用开发入手,慢慢地再往系统层研究。从现在开始要养成写博客的习惯,记录学习的点滴,也见证自己的成长。
唠叨了这么多,也该进入正题了。第一篇博客,我想记录一下Android的四大组件之一Service。对于Service,一开始我以为就是一线程,只不过是Android的开发团队给它起了个响亮的别名,但事实上并不是,它依然是在主线程中执行它的生命周期;既然不是线程,也就是说不能在它的生命周期里执行耗时的操作,那它到底有什么用呢?等我们分析完就知道原因啦!
Service它有两种启动方式:
1、Started:通过调用startService()来启动Service;
2、Bound:通过调用bindService()来启动Service;bound服务提供了一个客户端/服务器接口,实现组件与服务间通讯,还可以实现进程间通讯(IPC)。多个组件可以同时与一个服务绑定,不过需要等到所有的组件都解绑了后,服务才会被销毁。
对于startService这种启动方式,第一次调用的时候会走一下onCreate,再走onStartCommand方法,之后再次startService,只会走onStartCommand,一般这种启动方式主要用来处理一些耗时的操作,如网络资源的下载;常见的写法是在onStartCommand中启动一线程来执行耗时操作:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
// do something here
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
服务一启动之后就一直保持运行的状态,直到stopService()或stopSelf()方法被调用才消亡。无论调用多少次startService(),只要调用1次stopService()或stopSelf()方法,服务就会停止。对于这种方式启动的服务,基本与组件没什么联系了,默默地干活,默默地消亡。
为了实现组件与服务间能够通讯,需要使用bindService启动服务;这种方式我们会用到onBind()方法,获取Binder对象;
public class MyService extends Service {
private final static String TAG = "MyService";
private MyBinder mBinder = new MyBinder();
public class MyBinder extends Binder {
public void doSomething() {
new Thread(new Runnable() {
@Override
public void run() {
// do something here
Log.i(TAG, "doSomething");
}
}).start();
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
这样我们就可以在组件中通过ServiceConnection的回调来实现通讯了;
private ServiceConnection mConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
((MyService.MyBinder)service).doSomething();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
通过以下代码启动服务:
Intent intent = new Intent(MainActivity.this, MyService.class);
bindService(intent, mConn, BIND_AUTO_CREATE);
解邦也很简单:
unbindService(mConn);
以下是两种方式的生命周期流程图:
最后,我们还要在AndroidManifest.xml中添加Service的注册。
<service android:name=".MyService" />
现在我们有个疑问,Service既通过startService启动,又通过bindService绑定,这是完全有可能的,那它怎样才能销毁呢(走onDestroy()方法)?因为服务一启动或被绑定后,它就一直处于运行状态,所以必须同时调用stopService()和unbindService()方法,才能销毁该服务。
目前为止,我们都是在自己进程内进行通讯,现修改一下AndroidManifest.xml:
<service android:name=".MyService" android:process=":remote"/>
使服务在另一进程中启动,但我们会发现,执行bindService后程序会崩溃,这是因为组件和服务在不同进程,它们不能用传统的方式建立连接。这种情况下我们就需要用到AIDL(Android Interface Definition Language)来进行跨进程通讯了(IPC)。
现添加一aidl文件IMyAidlInterface.aidl:
// IMyAidlInterface.aidl
package com.example.service;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
void doSomething();
}
修改一下原来MyService.java的代码,将之前自定义Binder类中的操作移到下面:
IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
@Override
public void doSomething() throws RemoteException {
// do something here
Log.i(TAG, "doSomething");
}
};
在我们的onBind()方法中返回上面的mBinder对象。
我们组件中建立连接的回调接口也要修改一下:
private ServiceConnection mConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
IMyAidlInterface.Stub.asInterface(service).doSomething();
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
到这里我们的服务就可以正常的跨进程与我们的组件进行通讯了。
目前为止我们都只是在单个应用内通讯,为了实现不同应用间可以建立联系,我们可以将服务端的aidl接口(文件包名必须完全一样)提供给客户端调用,达到以上那种跨进程间通讯。
讲了那么多关于Service的知识,那么它到底有什么用呢?Service没有界面,它可以后台运行(也可以前台,通过startForeground),另一个作用就是我们上面一直在讲的跨进程通讯。
好啦!第一次写博客,就先写这么多吧!