Android IntentService源码分析

概述

大家知道,普通Service服务是运行在UI线程上的,这就意味着如果我们需要通过Service执行一些耗时的操作,我们必须要通过创建一个工作线程来完成,否则应用可能会出现ANR异常。

IntentService就是为了解决这个问题而出现的。IntentService是Service的一个子类,该类的作用就是可以让服务在工作线程中执行任务,而不需要自行创建工作线程。

IntentService的主要作用(优点):
1. 在IntentService中会默认创建工作线程用于执行传递的Intent,这样在执行耗时操作时不需要手动去创建线程了
2. 在IntentService中创建工作队列,用于将 Intent 逐一传递给 onHandleIntent() 实现,这样就永远不必担心多线程问题。
3. 在处理完所有启动请求后停止服务,因此您永远不必调用 stopSelf()。
4. IntentService的onBind方法默认返回null

IntentService源码分析

在IntentService中,主要使用到了HandlerThread。HandlerThread是Thread的一个子类,在该类中可以使用Handler。其实HandlerThread的实现原理非常简单,就是在run方法中通过Looper.prepare()来创建消息队列,然后通过Looper.loop()方法开启消息循环,整个实现流程如同ActivityThread.main()方法中MainLooper的初始化过程。

具体关于HandlerThread的介绍,请看 Android HandlerThread源码分析

IntentServcie源码分析

public abstract class IntentService extends Service {

    /**
     * 1、在IntentServcie被首次创建时,会执行onCreate方法
     */
    @Override
    public void onCreate() {
        super.onCreate();
        // 1、创建一个HandlerThread,用于接收消息
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        // 2、获取上面HandlerThread的实例的looper
        mServiceLooper = thread.getLooper();

        // 3、通过HandlerThread的looper,创建一个handler对象mServiceHandler,这样通过mServiceHandler发送的对象都会在HandlerThread中被处理
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }


    /**
     * 2、每次启动IntentServcie, onStartCommand方法会被调用,该方法内部主要调用onStart方法
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    /**
     * 3、在onStrat方法中主要是通过mServiceHandler发送了一条消息。
     * 

* 在mServiceHandler发送的消息中,intent对象会作为发送消息的参数(这里的intent和通过startServcie方法传递的intent是同一个对象) *

* 同时,消息中会被携带一个startId的参数,该参数主要用于判断服务是否结束 */ @Override public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } /** * 4、ServiceHandler,该handler对象是通过HandlerThread的looper创建的,所以通过ServiceHandler * 发送的消息都会被发送到HandlerThread中执行,由于HandlerThread是一个Thread类,这样就实现了在IntentService * 无需创建一个Thread来执行后台耗时任务。 *

* 同时,由于ServiceHandler内部的消息队列是通过looper维护的,这样就保证了消息队列是顺序执行的,所以IntentService也是 * 顺序执行任务的。 */ private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { /* * 1、抽象方法,需要在子类中实现具体后台任务的实现 */ onHandleIntent((Intent) msg.obj); /* * 2、在任务执行完成,自动停止服务。 * * msg.arg1 就是在startId,这是为每一消息生成的唯一标识。每通过IntentService处理一个请求时, * 都会有一个消息被放入到消息队列中,只有当最后一个消息执行完成即msg.arg1等于最后一个放入到消息队列的startId, * 服务才会被停止,否者IntentService不会被停止 * * 这样做的好处就是:保证消息队列中的所有消息都被处理,服务才会被停止。 * */ stopSelf(msg.arg1); } } /** * 5、抽象方法,该方法需要在IntentService的子类中实现,也是IntentService中唯一一个需要实现的方法 * * @param intent */ protected abstract void onHandleIntent(Intent intent); @Override public void onDestroy() { // 退出消息队列循环 mServiceLooper.quit(); } @Override @Nullable public IBinder onBind(Intent intent) { // 默认返回null return null; } }

IntentService的简单使用

这里通过IntentService模拟一个简单的下载任务。


public class IntentServcieActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_intent_servcie);

        Button button = findViewById(R.id.btn);
        button.setOnClickListener(new View.OnClickListener() {
            private int urlid;
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(IntentServcieActivity.this, DownloadService.class);
                intent.putExtra(DownloadService.DOWN_URL, "url" + ++urlid);
                startService(intent);
            }
        });
    }
}


/**
 * 通过IntentService完成下载任务
 */
public class DownloadService extends IntentService {
    public static final String DOWN_URL = "down_url";
    public DownloadService() {
        super("DownloadService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        String url = intent.getStringExtra(DOWN_URL);
        downlaod(url);
    }

    /**
     * 模拟下载任务
     */
    private void downlaod(String url) {
        Log.e("zhangke", "url = " + url + "  正在下载中...");
        SystemClock.sleep(3000);
        Log.e("zhangke", "url = " + url + "  下载完成");
    }

}

你可能感兴趣的:(Android,四大组件,Android,系统源码)