Android异步实现——IntentService

人生的很多转折点是由不经意的人和事引发的,但是更多是由经意的人和事引发的。

相信我们一开始接触安卓的时候,书上都会介绍到IntentService,但是自从我们接触Handler多了,就遗忘掉了这个类了,最近在工作中一次偶然的机会使用到这个类,使用过程中发现这个类出乎意料的简单,简直是不学白不学,学习的过程中还能够对Handler的知识进一步深入了解一下。

介绍

IntentService是一个继承自Service的抽象子类,客户端通过startService发送请求传递Intent,开启一个服务并且用一个工作线程轮流解决每一个intent,当结束工作后自动关闭服务。因为这个类继承自Service,所以它依然拥有Service的特性,所以当我们在Service还没关闭的时候调用Service,那么不会创建新的Service,也就不会执行onCreate,直接触发的是startService的时候。

所有的请求都会在一个单一的工作线程处理,它们不会阻塞主线程的loop,但一次只会处理一个请求。如果你想下载10个文件,调用10次startService,那么就会依次下载10个文件。

构造方法

构造方法需要传递一个name参数,这个name字段主要用于命名工作线程,对调试比较重要。

    public IntentService(String name) {
        super();
        mName = name;
    }

不过大多数时候我们可以直接传递一个固定的字符串

    @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();
        // 创建一个子线程,这个子线程内部包含一个Handler
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        //使用上面线程的looper来创建一个Handler,
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

对于onBind,IntentService的默认实现是返回null,也可以理解为默认不与任何组件绑定,除非我们需要将它和某个组件绑定,不然不需要重写这个方法,但是出于对IntentService的设计考虑,我认为我们不应该重写这个方法,不然使用IntentService就没有意义了。

Handler消息机制

为了兼容新旧版本的安卓系统,对于onStart和onStartCommand都进行了兼容

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

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
       //如果Service不幸被系统杀死了,START_REDELIVER_INTENT 表示重启之后重新重新发送这个Intent,START_NOT_STICKY表示不重启
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

可以看到IntentService实现了一个叫ServiceHandler的类

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            //发送消息到这个looper的messagequeue,也从这个messagequeue中获取消息
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            //模板模式,onHandleIntent是抽象方法
            onHandleIntent((Intent)msg.obj);
            // 关闭指定startid的服务
            stopSelf(msg.arg1);
        }
    }

构造方法传入了一个Looper,而handlerMessage中则是获取消息中的Intent,然后调用onHandleIntent方法,执行完之后就会根据startId来关闭service。
需要注意的是stopSelf(int startId )这个方法,这个方法会尝试关闭Service,为什么说是尝试?因为我们要知道Service,也就是服务,它可以向客户提供不止一次的服务。每次通过startService( )启动的服务,系统都会生成一个startId,也就是标记了一次服务,在onStartCommand中可以获得这个startId。所以只有当stopSelf里面的startId等于最后一次调用startService( )所生成的startId,才会真正停止服务,否则服务是不会停止的。

那么IntentService是怎么开启一个工作线程来执行任务呢?前面已经提及到,在onCreate里面,会开启一个线程,在线程内部looper轮询MessageQueue的消息,当有消息到达之后取出消息进行处理,执行handler的handleMessage方法,所以我们handler所实现的handle方法是在looper所在的线程处理的,这也就是为什么能够实现异步了。
如果我们有什么耗时操作,我们就可以直接放到IntentService里面执行。

应用

比如,很多时候我们会在Application中做一些第三方类库的初始化,但是当我们的类库越来越多,或者第三方类库的初始化越来越复杂的时候就会出现一个问题,开机时间过长,俗称(冷启动时间过长)。要知道,我们初始化我们的应用,做的可不仅仅是这些初始化第三方,如果都放在主线程中进行的话,那么势必会出现问题。而为了优化这个问题,我们可以尝试使用IntentService来进行一些第三方类库的初始化操作。好比如:

AppInitializeService调用start方法即可进行初始化
在查看代码的过程中,我发现了一个比较有趣的东西,就是activity中的runOnUiThread这个方法

    public final void runOnUiThread(Runnable action)           {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }

代码很简单,如果不在主线程,那么就使用mHandler发送消息,如果在主线程,那么就直接执行。简而言之,实现异步的所有方法(异步的概念是不用阻塞当前的线程来等待处理结果,允许后续操作),仅且只有一种,那就是handler,而其余的所有方法,都是对handler的一种封装而已,有人可能会对IntentService的异步不是很了解,要知道,IntentService继承自Service,Service是一个在主线程运行的组件,只是这个组件运行在后台而已,看不到的东西俗称叫后台。所以在这个Service内,我们可以通过handleIntent来实现一些异步操作,当然了,我们可以在handleIntent中需要想办法把消息发送到主线程的handler,通知主线程操作已经完成了。

总结

当我们真正想了解一个类的时候,常常会发现研究代码的时候会涉及到越来越多的API,越来越多的机制和代码,即使简单如AsyncTask,虽然代码量不多,但是展开了研究也是够呛的。单纯多线程,锁机制等就已经很复杂了,这也是为什么任职要求里面总是有多线程开发这一点。

然而大多数人对多线程也只是局限于new一个Thread,重写run方法而已…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值