Android IntentService源码解读

说到IntentService,其实他内部也是一个Thread + Handler实现的,之前我们在阅读源码,让你彻底理解AsyncTask运行原理这篇中我们就说过,他的原型其实也是Thread+Handler,对吧。只不过这个Thread有点特别,怎么个特别法呢?这个线程run()方法执行是获取创建Looper的操作,而平常呢,我们看看线程run()方法里,一般是执行一些耗时操作的对吧,比如我Asynbctask里面就是这样的。好了,不多说,下面我们来阅读阅读IntentService的源码。

IntentService是一种特殊的Service,他继承了Service,而且它还是一个抽象类,因此,你作为一个开发者,就必须是他的子类才能使用它,顺便还说一句,有的面试官会问你,抽象类能不能继承非抽象类,那么你看了IntentService这个类,那你的回答又会是什么呢?哈哈!答案显而易见,是可以的,对不?IntentService可用于执行后台的耗时操作,而且当他执行完相关的任务时,他就会停止自己,这也是Google官方给出优化应用内存中的一种方法。这个道理也很明显,当你不需要一个常驻后,让他执行完他的任务之后,就释放内存,节省内存开销,这对一个开发者来说,是一个良好的习惯。好,我们先来看看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);
    }

你看看,他里面做了什么?首先,这onCreate()方法里创建了一个HandlerThread线程,这个HandlerThread里面做了什么,你暂时不要管,如果你想知道,你可以去先去看看这篇关于HandleThread的源码解读 HandleThread源码分析,其实HandlerThread主要的事情就是构造一个Looper实例,通过它得到这个Looper实例,通过Looper来构造一个ServiceHandler实例,那么,通过这个mServiceHandler发送的消息始终会在ServiceHandler里面去执行,当然,它也可以用于执行后台的任务,每次启动IntentService时,它的onStrartCommand()方法都会被调用一次,IntentService在onStartCommand()方法中处理每一个后台任务的Intent,下面我们看看,onStartCommand()中是如何处理外部的Intent的,它内部调用了onStart()方法,那我们就来看看onStart()方法内部的实现,如下所示:
    @Override
    public void onStart(Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    /**
     * You should not override this method for your IntentService. Instead,
     * override {@link #onHandleIntent}, which the system calls when the IntentService
     * receives a start request.
     * @see android.app.Service#onStartCommand
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
从上面代码可以看出,IntentService仅仅是通过mService发出一个消息,这个消息会在ServiceHandler中处理,mServiceHandler收到消息后,它会把这个Intent对象传递给onHandleIntent()方法去处理。注意,这里这个Intent对象跟你外部传来的Intent对象完全一致,通过这个Intent对象就可以解析在外部启动IntentService所传过来的相关参数,然后你通过这些参数就能区分具体的后台任务,这样在onHandleIntent()方法中就可以对不同的后台人物做处理了。当onHandleIntent()方法执行完之后,它就会调用stopSelf(int startId)方法来停止掉服务,那么这里采用stoptSelf(int startId)而不采用stopSelf()方法,那是因为,stopSelf()方法会立刻将服务停止掉,假如说某个时候,还有消息未处理,那怎么办?如果你调用stopSelf()方法的话,那么后面的消息,你将无法处理,这样,对我们来说是我们不想要的,而onStopSelf(int startId)就能帮我们解决这个问题,这个方法呢,会等待所有的消息处理完,才会将服务停止掉。

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

  我们知道,onHandleIntent()方法是一个抽象方法,在Java中,如果某个类有抽象方法那么这个类必须声明为抽象,抽象类中可以有抽象方法,也可以有实现的方法,所以呢,这个类是抽象类,那么我们就需要子类来实现这个抽象方法,他的作用是从Intent区分具体的任务并执行这些任务。如果当前后台之后一个任务,那么onHandleIntent()方法执行完成之后,服务就会停止掉,如果此时后台有多个任务时,那么当onHandleIntent执行完最后一个任务时,才会将服务停止掉。在IntentService中,我们执行一个后台任务,就需要启动一次IntentService,而IntentService内部又是通过消息的方式想HandleThread来请求执行任务的,而这个Looper中取出消息的消息也是有序的,那么我就可以猜测出,他的任务也是按照你启动IntentService的后台任务的顺序来执行的。如果有对Handler内部机制不熟的,可以看看这篇 阅读源码,让你彻底理解Handler、Message、Looper之间的关系博文。

下面,我们将通过一个例子来说明当需要在后台执行多个任务的情况,到底是不是要执行完所有的任务之后,才回去停掉服务。代码如下:

public class MyIntentService extends IntentService {

    private static final String TAG = "MyIntentService";

    public MyIntentService(){
        super(TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        String action = intent.getStringExtra("task_action");
        Log.e(TAG, "receive task" + action);
        SystemClock.sleep(5000);

        if("com.qhb.action.TASK1".equals(action)){
            Log.e(TAG,"handle task : "+action);
        }
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG,"service destroyed");
    }

实践结果,我就不贴了,不知道android studio为毛突然打印不出日志了,没法演示了,不过,大家可以自己动手试试。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        Intent intent = new Intent(this,MyIntentService.class);
        intent.putExtra("task_action", "com.qhb.action.TASK1");
        startService(intent);

        intent.putExtra("task_action","com.qhb.action.TASK2");
        startService(intent);

        intent.putExtra("task_action","com.qhb.action.TASK3");
        startService(intent);

        intent.putExtra("task_action", "com.qhb.action.TASK4");
        startService(intent);
    }
}

具体的都给贴上了,大家只要创建工程,复制黏贴到里面即可运行,非常不好意思,并不是我偷懒,不知道studio出什么毛病了。

这里顺便说一下,Service与IntentService的区别就是能否执行耗时操作而已。

欢迎大家拍砖、吐槽。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值