Android IntentService源码解读

来源:互联网 发布:淘宝联盟点击数0 编辑:程序博客网 时间:2024/05/16 05:27

说到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 0