IntentService简析

一、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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值