转载请注明出处:http://blog.csdn.net/llew2011/article/details/51373243

提起Service大家都很熟悉,它乃Android四(si)大(da)组(jing)件(gang)之一。但是说起IntentService有童靴或许有点陌生,看名字感觉和Service有关连。不错,不仅有关联而且关系还不一般,IntentService是Service的子类,所以它也是正宗的Service,由于IntentService借助了HandlerThread,我们今天就从源码的角度巴拉一下IntentService及HandlerThread,看看它们是何方神圣,如果你对它们非常熟悉,请跳过本文(*^__^*) ……

开始巴拉IntentService源码之前我们先看看它的基本用法,既然IntentService是正宗的Service,那它的用法就和Service一样。IntentService也是一个抽象类,需要实现其抽象方法onHandleIntent()。我们先定义BackgroundService,使之继承IntentService并实现其抽象方法onHandleIntent(),然后重写IntentService的生命周期方法并打印日志,代码如下:

public class BackgroundService extends IntentService {private static final String TAG = BackgroundService.class.getSimpleName();public BackgroundService() {super("TT");Log.e(TAG, "BackgroundService()    " + Thread.currentThread());}@Overridepublic void onCreate() {Log.e(TAG, "onCreate()             " + Thread.currentThread());super.onCreate();}@Overridepublic void onStart(Intent intent, int startId) {Log.e(TAG, "onStart()              " + Thread.currentThread());super.onStart(intent, startId);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.e(TAG, "onStartCommand()       " + Thread.currentThread());return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {Log.e(TAG, "onDestroy()            " + Thread.currentThread());super.onDestroy();}@Overridepublic IBinder onBind(Intent intent) {Log.e(TAG, "onBind()               " + Thread.currentThread());return super.onBind(intent);}@Overrideprotected void onHandleIntent(Intent intent) {Log.e(TAG, "onHandleIntent()       " + Thread.currentThread());}}
我们在重写的部分方法中添加了日志,主要打印当前方法名和方法执行时所在的线程名称。然后在配置文件manifest.xml中配置BackgroundService,代码如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.llew.wb.source.intentservice"    android:versionCode="1"    android:versionName="1.0" >    <uses-sdk android:minSdkVersion="8" />    <application        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme" >        <activity            android:name="com.llew.wb.source.MainActivity"            android:label="@string/app_name" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <service android:name="com.llew.wb.source.BackgroundService" >        </service>    </application></manifest>
最后在MainActivity的布局文件activity_layout.xml中添加一个button按钮,该按钮用来启动BackgroundService。布局文件代码如下:
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:onClick="startService"        android:text="测试IntentService" /></FrameLayout>

定义完布局文件后,在MainActivity中添加startIntentService()方法,代码如下:

public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void startService(View view) {Intent action = new Intent(this, BackgroundService.class);startService(action);}}
OK,一切就绪,我们运行一下看看打印结果。运行程序,输出结果如下图所示:

根据打印结果可以确定IntentService的生命周期函数执行顺序是onCreate()→onStartCommon()→onStart()→onHandleIntent()→onDestroy()。再观察打印的线程信息发现只有onHandleIntent()的线程信息和其他函数的线程信息是不同的,也就是说onHandleIntent()所在的线程和其他函数所在的不是同一个线程,我们知道其他函数都是在主线程中执行的。所以onHandleIntent()的执行是在子线程中进行的。还有一点onDestroy()方法是在onHandleIntent()方法执行结束后才执行,因为我们并没有主动的调用停止Service的相关方法,所以可以猜测使IntentService停止的操作一定是在和onHandleIntent()方法所在的线程中操作的。

基于猜测,我们继续做实验,既然onHandleIntent()方法是在子线程中执行的,那我们就可以利用线程休眠来模拟后台比较耗时的操作,修改onHandleIntent()方法,代码如下:

@Overrideprotected void onHandleIntent(Intent intent) {Log.e(TAG, "onHandleIntent()       " + Thread.currentThread());try {Thread.sleep(3000);Log.e(TAG, "sleep finish           " + Thread.currentThread());} catch (Exception e) {e.printStackTrace();}}
在onHandleIntent()方法中让其所在的线程休眠了3秒钟,然后运行程序,输出结果如下: 从源码的角度深入理解IntentService及HandlerThread_第1张图片" width="904" height="148" style="border:1px solid black;">

根据输出结果看到,在onHandleIntent()方法中先是打印了第一句log,等待3秒钟后又把第二句log内容打印出来了,log打印完之后是执行Service的onDestroy()方法。我们继续做实现,刚刚只是在onHandleIntent()的方法中模拟做了一个耗时任务,现在我们启动多个IntentService,每一次启动时都传递进来一个参数来表示每一个任务,继续修改startService()方法,代码如下:

public void startService(View view) {Intent action1 = new Intent(this, BackgroundService.class);action1.putExtra("params", "task 1");startService(action1);Intent action2 = new Intent(this, BackgroundService.class);action2.putExtra("params", "task 2");startService(action2);Intent action3 = new Intent(this, BackgroundService.class);action3.putExtra("params", "task 3");startService(action3);}
我们在startService()方法中启动了3次BackgroundService,并在启动时传递了参数。然后修改onHandleIntent()方法,代码如下:
@Overrideprotected void onHandleIntent(Intent intent) {String params = intent.getStringExtra("params");Log.e(TAG, params + " in onHandleIntent()   " + Thread.currentThread());try {Thread.sleep(3000);Log.e(TAG, params + " is finished           " + Thread.currentThread());} catch (Exception e) {e.printStackTrace();}}
运行程序,日志打印结果如下图所示: 从源码的角度深入理解IntentService及HandlerThread_第2张图片" width="904" height="270" style="border:1px solid black;">

观察输出结果发现onHandleIntent()的执行是有序的,当所有的模拟耗时任务都结束后该Service才销毁。也就是说我们可以方便的使用IntentService来执行一些有序的并且非常耗时的异步操作,当所有的任务都执行完毕后该IntentService会主动销毁自己,我们无需关心IntentService的销毁。

好了,现在我们清楚了IntentService的执行流程,那接下来我们就从源码的角度来巴拉一下IntentService,看看其内部流程,首先看一下官网对其的说明:从源码的角度深入理解IntentService及HandlerThread_第3张图片" width="650" height="151" style="border:1px solid black;">

IntentService是一个继承Service的用来处理异步请求的类,客户端通过调用startService(Intent)发送请求,Service服务就会在必要的时候启动然后在工作线程中依次处理每一个Intent,当工作线程执行完毕后Service服务就关闭自己。

这个"工作队列处理器"是将任务从一个应用的主线程中做分离的最常用的模式,IntentService类就是该模式的经典代表。为了使用IntentService需要先继承IntentService然后实现其抽象方法onHandleIntent(),它在工作线程中接收发送来的所有Intent并在适当的时候结束自己。

所有的请求都会在一个单一的工作线程中被接收,工作线程可以随意耗时而不会阻塞主线程,但是在同一时刻只能处理一个请求。

知晓了IntentService的说明后我们继续往下看代码,首先看一下IntentService的定义的成员变量有哪些,代码如下:

// 提供消息队列和private volatile Looper mServiceLooper;// 处理消息private volatile ServiceHandler mServiceHandler;// 表示工作线程的名字private String mName;// 是否重新发送Intentprivate boolean mRedelivery;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);    }}
IntentService中仅仅定义了4个成员变量,其中Looper类型的mServiceLooper童靴们应该很熟悉了(不熟悉也无妨我会在后续文章中从源码的角度出发讲解Android消息机制之Handler, Looper, Message和MessageQueue等),还定义了ServiceHandler类型的mServiceHandler,ServiceHandler继承Handler,并在handleMessage()方法中调用了抽象方法onHandleIntent()方法和结束Service的stopSelf()方法。

了解完IntentService的成员变量后我们紧接着看一下构造方法,源码如下:

/** * Creates an IntentService.  Invoked by your subclass's constructor. * * @param name Used to name the worker thread, important only for debugging. */public IntentService(String name) {    super();    mName = name;}
IntentService的构造方法要求必须传递进来一个String类型的值(该值表示的是工作线程的名称),把name赋值给了其成员变量mName。看完了构造方法后接着看IntentService的onCreate()方法,源码如下:
@Overridepublic 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()方法中首先调用了父类的onCreate()方法,接着创建了一个HandlerThread的实例thread,看到这里或许有的童靴会有疑问了,HandlerThread又是何方神圣了?不必担心,我们进入HandlerThread的源码看看它到底是何方神圣,其源码如下:
/** * Handy class for starting a new thread that has a looper. The looper can then be  * used to create handler classes. Note that start() must still be called. */public class HandlerThread extends Thread {    int mPriority;    int mTid = -1;    Looper mLooper;    public HandlerThread(String name) {        super(name);        mPriority = Process.THREAD_PRIORITY_DEFAULT;    }        /**     * Constructs a HandlerThread.     * @param name     * @param priority The priority to run the thread at. The value supplied must be from      * {@link android.os.Process} and not from java.lang.Thread.     */    public HandlerThread(String name, int priority) {        super(name);        mPriority = priority;    }        /**     * Call back method that can be explicitly over ridden if needed to execute some     * setup before Looper loops.     */    protected void onLooperPrepared() {    }    public void run() {        mTid = Process.myTid();        Looper.prepare();        synchronized (this) {            mLooper = Looper.myLooper();            notifyAll();        }        Process.setThreadPriority(mPriority);        onLooperPrepared();        Looper.loop();        mTid = -1;    }        /**     * This method returns the Looper associated with this thread. If this thread not been started     * or for any reason is isAlive() returns false, this method will return null. If this thread      * has been started, this method will block until the looper has been initialized.       * @return The looper.     */    public Looper getLooper() {        if (!isAlive()) {            return null;        }                // If the thread has been started, wait until the looper has been created.        synchronized (this) {            while (isAlive() && mLooper == null) {                try {                    wait();                } catch (InterruptedException e) {                }            }        }        return mLooper;    }        /**     * Ask the currently running looper to quit.  If the thread has not     * been started or has finished (that is if {@link #getLooper} returns     * null), then false is returned.  Otherwise the looper is asked to     * quit and true is returned.     */    public boolean quit() {        Looper looper = getLooper();        if (looper != null) {            looper.quit();            return true;        }        return false;    }        /**     * Returns the identifier of this thread. See Process.myTid().     */    public int getThreadId() {        return mTid;    }}
哦,看完HandlerThread的源码我们就可以放心了,原来HandlerThread继承自Thread,那也就是说HandlerThread也是一个正宗的线程类。HandlerThread类有三个成员变量,mPriority表示当前线程的优先级(默认值为0),mTid表示线程的标识符,mLooper的作用为当前线程添加消息队列并循环读取消息。

HandlerThread的成员变量了解之后,看一下其重写的run()方法,在run()方法中先调用Process.myTid()给mTid赋值,接着调用Looper.prepare()方法为当前线程创建一个消息队列,创建完消息队列后为成员变量mLooper赋值并唤醒可能处于等待状态的锁机制,紧接着又设置了当前线程的优先级,最后进入Looper.loop()的方法中。

总的来看HandlerThread核心就是对外提供一个带有Looper功能的线程,当我们创建完HandlerThread实例之后要立即调用其start()方法,如果不调用start()方法,当我们需要使用HandlerThread中的Looper时该线程就会处于挂起状态,因为在调用HandlerThread实例对象的getLooper()方法时,如果当前线程是isAlive()并且mLooper为null,那么该线程就将一直wait()下去,所以在创建完HandlerThread后要立即调用其start()方法。

看完HandlerThread源码后我们接着看IntentService的onCreate()方法,在该方法中实例化了一个HandlerThread类型的thread,紧接着调用该thread的start()方法,然后再调用thread的getLooper()方法为mServiceLooper赋值,最后利用mServiceLooper完成mServiceHandler的初始化工作。

看完IntentService的onCreate()方法,接着看onStartCommand()方法,源码如下:

/** * 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 */@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {    onStart(intent, startId);    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;}
onStartCommand()函数中调用了onStart()函数,然后通过对mRedelivery的判断决定返回START_REDELIVER_INTENT或START_NOT_STICKY,需要注意在onStartCommand()函数中只能返回以下三种类型中的一种:

  • START_NOT_STICKY
    如果该服务在onStartCommand()方法返回后被系统杀死,那么知道接收到新的Intent对象,该服务才会重新创建。这是安全的选项,用来避免在你不需要的时候运行里的服务。
  • START_STICKY
    如果该服务在onStartCommand()方法返回后被系统杀死,那么系统就会重新创建这个服务并且尝试调用onStartCommand()方法,但是系统不会重新传递最后的Intent对象,系统会用一个null的Intent对象来调用onStartCommand()方法。在这个情况下除非有一些被发送的Intent对象在等待启动服务。这适用于不执行命令的媒体播放器(或类似的服务),它只是无限期的运行着并等待工作的到来。
  • START_REDELIVER_INTENT
    如果该服务在onStartCommand()方法返回后被系统杀死,那么系统会重新创建这个服务,并且用发送给这个服务的最后一个Intent对象来调用onStartCommand()方法。任意等待的Intent对象会依次被发送,这适合于那些应该立即恢复正在执行工作的服务,例如下载文件。

然后我们看一下onStart()方法,源码如下:

@Overridepublic void onStart(Intent intent, int startId) {    Message msg = mServiceHandler.obtainMessage();    msg.arg1 = startId;    msg.obj = intent;    mServiceHandler.sendMessage(msg);}
在onStart()方法中利用mServiceHandler发送消息并把传递进来的Intent等参数也一同打包发送。该消息最后在文章开头看到的在handleMessage()方法中被处理:
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()方法中调用了onHandleIntent()方法,等其执行完毕后调用stopSelf()方法关闭服务。

总的来说IntentService适合在后台执行比较耗时的,有序的异步操作并且无需我们关心何时结束该服务。HandlerThread不仅是标准的Thread而且对外提供了Looper功能,需要注意的是当创建了HandlerThread后需要立即执行其start()方法,否则该线程可能一直处于挂起状态。

好了,到这里有关IntentService和HandlerThread的讲解就告一段落,感谢观看。




更多相关文章

  1. Android设计模式系列(9)--SDK源码之适配器模式
  2. Android音乐播放器 -- 滑动切换实现
  3. EventBus 和RxLifecycle 一起使用所引发的问题及解决办法 -java.
  4. ViewPager 使用方法详解
  5. 安卓开发到底是什么
  6. 由浅入深研究Android(3)--浅谈线程的一些东西
  7. android Content provider 组件
  8. 第一行代码读书笔记 Kotlin Android
  9. android 呼吸灯实现源码

随机推荐

  1. 写给前端早读课读者的公众号总结
  2. 【第475期】这些chrome插件你有吗?
  3. 【招聘】北京滴滴打车招前端
  4. 如何遇到前端早读课活动获奖名单
  5. 数据库中间件 Sharding-JDBC 源码分析 —
  6. 【招聘】腾讯CDC招前端
  7. Android(安卓)studio导入Github的项目
  8. 分布式消息队列 RocketMQ 源码分析 ——
  9. 免费且支持远程连接的MySql空间
  10. 专访|腾讯UI工程师@张鑫旭