IntentService简析

来源:互联网 发布:手机自动录像软件 编辑:程序博客网 时间:2024/05/29 19:51

一、IntentService的使用

public class MyIntentService extends IntentService {    private static final String TAG = "MyIntentService";    public MyIntentService() {        super(TAG);        println("MyIntentService()");    }    @Override    public void onCreate() {        super.onCreate();        println("onCreate()");    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        println("onStartCommand()");        return super.onStartCommand(intent, flags, startId);    }    @Override    public void onDestroy() {        println("onDestroy()");        super.onDestroy();    }    @Nullable    @Override    public IBinder onBind(Intent intent) {        println("onBind()");        return super.onBind(intent);    }    @Override    protected void onHandleIntent(Intent intent) {        println("onHandleIntent()");        try {            Thread.sleep(6000);        } catch (Exception e) {            e.printStackTrace();        }    }    private void println(String info) {        System.out.println(TAG + " " + info);    }}

实际上,如果需要使用IntentService,直接重写onHandleIntent(Intent intent)这个方法就行。不过在这里,主要是为了看看IntentService的生命周期,所以把IntentService的所有方法都重写了一遍,然后将相关的日志打印出来。

在onHandleIntent(Intent intent)里,就只打印了一行日志,然后将当前线程暂停6秒。为什么是6秒,因为在主线程中,如果暂停时间超过5秒,那么就会产生臭名昭著的ANR问题。在这里主要就是想看看,如果在这里线程暂停超过5秒,会不会产生ANR。

<service android:name=".service.MyIntentService"/>

首先在清单文件中将这个服务进行注册,然后通过一个按钮来启动服务。

startService(new Intent(this, MyIntentService.class));

启动服务之后,等待一段时间查看日志,日志如下

I/System.out: MyIntentService MyIntentService()I/System.out: MyIntentService onCreate()I/System.out: MyIntentService onStartCommand()I/System.out: MyIntentService onHandleIntent()I/System.out: MyIntentService onDestroy()

通过上述的日志可以看出,这个服务会自动停止,并且不会导致ANR问题。那么下面,我们将通过源码看看,为什么IntentService会自动停止,并且不会导致ANR问题。(在普通的Service中执行上述的Thread.Sleep(6000)将会导致ANR)。

二、IntentService代码解析

在这里我们就通过服务的回调函数执行顺利来分析。首先是onCreate()

 @Override    public void onCreate() {        // TODO: It would be nice to have an option to hold a partial wakelock        // during processing, and to have a static startService(Context, Intent)        // method that would launch the service & hand off a wakelock.        super.onCreate();        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");        thread.start();        mServiceLooper = thread.getLooper();        mServiceHandler = new ServiceHandler(mServiceLooper);    }

在这里主要是启动一个HanderThread,这里我们称之为服务线程,然后给这个线程定义一个Handler(注意,这里不是给UI线程创建的Handler)。然后再看看onStartCommand()的实现。

 @Override    public int onStartCommand(Intent intent, int flags, int startId) {        onStart(intent, startId);        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;    }

这里很简单,先调用onStart(intent, startId),然后给一个返回值。那么我们直接去看onStart()里的实现好了。

 @Override    public void onStart(Intent intent, int startId) {        Message msg = mServiceHandler.obtainMessage();        msg.arg1 = startId;        msg.obj = intent;        mServiceHandler.sendMessage(msg);    }

先通过这个线程的Handler去获取一个消息,然后将startId,intent这些参数赋值给这个消息。通过服务线程的Handler将这个消息发送到这个线程的消息队列中去,然后这个线程中的Loop方法就会解除阻塞,获取到这个消息,并将这个消息交给这个消息指定的Handler进行处理。那么我们来看看这个handler的实现。

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);        }    }

在handleMessage(Message msg)实现比较简单,先是将启动这个服务的Intent从消息中取出,然后调用onHandleIntent((Intent)msg.obj)函数。onHandleIntent函数的定义在上面已经看过,很简单,就是打印一条日志,然后暂停6秒钟。onHandleIntent函数完成后,就会调用stopSelf(msg.arg1)来停止这个服务。

现在我们来梳理一下:

  1. 通过在onCreate()中启动一个HanlderThread线程(考虑一下,为什么不在onStartCommand中启动这个线程)。
  2. 在onStartCommand中获取startId和Intent,然后通过Handler获取消息,将startId和Intent设置在这个消息中,然后通过Handler将这个消息发送到消息队列中。
  3. 在loop()函数中,由于消息的入队,这个时候会解除阻塞,接收这个消息,然后将这个消息直接给这个Handler处理。
  4. 因为Handler是在服务线程中运行的,所以虽然在onHandleIntent中等待了6秒钟,但是由于不是在UI线程,所以不会导致ANR。
  5. 在执行完onHandleIntent后,IntentService会自动调用stopSlef来停止服务本身。
0 0