Android四大组件之Service必备知识点
onBind(…)函数是Service基类中的唯一抽象方法,子类都必须重写实现,此函数的返回值是针对Bound Service类型的Service才有用的,在Started Service类型中,此函数直接返回 null 即可。
1.service启动状态
主要用于执行后台计算
Intent intentService = new Intent(this, AService.class);
//启动
startService(intentService);//onCreate()-->onStartCommand()
//关闭
stopService(intentService);
onCreate():Service第一次被创建的时候调用,如果当前Service已经被创建过了,不管怎样调用startService()方法,onCreate()方法都不会再执行
int onStartCommand(Intent intent, int flags, int startId):每次启动都会调用,一般默认调用父类返回值,特殊情况有三种:
1>START_NOT_STICKY
如果系统在onStartCommand()方法返回之后杀死这个服务,那么直到接受到新的Intent对象,这个服务才会被重新创建。这是最安全的选项,用来避免在不需要的时候运行你的服务。
2>START_STICKY
如果系统在onStartCommand()返回后杀死了这个服务,系统就会重新创建这个服务并且调用onStartCommand()方法,但是它不会重新传递最后的Intent对象,系统会用一个null的Intent对象来调用onStartCommand()方法,在这个情况下,除非有一些被发送的Intent对象在等待启动服务。这适用于不执行命令的媒体播放器(或类似的服务),它只是无限期的运行着并等待工作的到来。
3>START_REDELIVER_INTENT
如果系统在onStartCommand()方法返回后,系统就会重新创建了这个服务,并且用发送给这个服务的最后的Intent对象调用了onStartCommand()方法。任意等待中的Intent对象会依次被发送。这适用于那些应该立即恢复正在执行的工作的服务,如下载文件。
需要注意的点
1>onStartCommand(..)可以多次被调用,onDestroy()与onCreate()想匹配,当用户强制kill掉进程时,onDestroy()是不会执行的。
2>对于同一类型的Service,Service实例一次永远只存在一个,而不管Client是否是相同的组件,也不管Client是否处于相同的进程中。
3>Service通过startService(..)启动Service后,此时Service的生命周期与Client本身的什么周期是没有任何关系的,只有Client调用stopService(..)或Service本身调用stopSelf(..)才能停止此Service。当然,当用户强制kill掉Service进程或系统因内存不足也可能kill掉此Service。
4>Client A 通过startService(..)启动Service后,可以在其他Client(如Client B、Client C)通过调用stopService(..)结束此Service。
5>Client调用stopService(..)时,如果当前Service没有启动,也不会出现任何报错或问题,也就是说,stopService(..)无需做当前Service是否有效的判断。
6>当Service需要运行在单独的进程中,AndroidManifest.xml声明时需要通过android:process指明此进程名称,当此Service需要对其他App开放时,android:exported属性值需要设置为true(当然,在有intent-filter时默认值就是true)。
<service
android:name=".AService"
android:exported="true"
android:process=":MyCorn" >
<intent-filter>
<action android:name="com.dupeng.tsingda.AService" />
</intent-filter>
</service>
2.service绑定状态
主要用于其他组件和service的交互
Intent intentService = new Intent(this, AService.class);
bindService(Intent service, ServiceConnection conn, int flags);
private ServiceConnection conn = new ServiceConnection(){
//系统调用这个来传送在service的onBind()中返回的IBinder.
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
}
//Android系统在同service的连接意外丢失时调用这个.比如当service崩溃了或被强杀了.当客户端解除绑定时,这个方法不会被调用.
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
flags:默认传1(Context.BIND_AUTO_CREATE); 传0则表示不再开启新的服务
在onServiceConnected中可以拿到Service中的iBinder对象,即可以调用其相应的方法,实现客户端和service的通信(分为:app间即跨进程,app内部通信)。
//XXXService内部类
public class MyBinder extends Binder{
public TestService XXXService(){
return XXX;
}
}
跨进程不是此刻的重点,所以暂不深入
对了,别忘了解绑:unbindService(conn);
3.IntentService
在Service里面我们肯定不能直接进行耗时操作,一般都需要去开启子线程去做一些事情,自己去管理Service的生命周期以及子线程并非是个优雅的做法;好在Android给我们提供了一个类,叫做IntentService.
官方翻译:IntentService是一个基于Service的一个类,用来处理异步的请求。你可以通过startService(Intent)来提交请求,该Service会在需要的时候创建,当完成所有的任务以后自己关闭,且请求是在工作线程处理的。
使用了IntentService有两个好处,一方面不需要自己去new Thread了;另一方面不需要考虑在什么时候关闭该Service了。
源码解析:
1>IntentService源码
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
protected abstract void onHandleIntent(Intent intent);
}
2>HandlerThread源码:
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
}
源码解读: 当IntentService被第一次启动的时候,onCreate里面初始化了一个HandlerThread,然后使用它的Looper来构造一个Handler对象mServiceHandler,每次调用onStartCommand的时候,通过mServiceHandler发送一个消息,消息中包含我们的intent。然后在该mServiceHandler的handleMessage中去回调onHandleIntent(intent);即消息最终都会在HandlerThread中执行。
实际中的应用:如果存在多个后台任务,那么当onHandlerIntent执行完最后一个任务时,才会stopSelf(int startId);
stopSelf() 和stopSelf(int startId)区别:
stopSelf()会立刻停止服务,stopSelf(int startInd)则等待所有消息处理完才关闭服务。
初始化和启动了一个线程;然后我们看run()方法,可以看到该方法中调用了Looper.prepare(),Loop.loop();