您的位置:首页 > 移动开发 > Android开发

Android 源码系列之<七>从源码的角度深入理解IntentService及HandlerThread

2016-05-30 07:47 1191 查看
转载请注明出处:/article/11851863.html

提起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());
}

@Override
public void onCreate() {
Log.e(TAG, "onCreate()             " + Thread.currentThread());
super.onCreate();
}

@Override
public void onStart(Intent intent, int startId) {
Log.e(TAG, "onStart()              " + Thread.currentThread());
super.onStart(intent, startId);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand()       " + Thread.currentThread());
return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
Log.e(TAG, "onDestroy()            " + Thread.currentThread());
super.onDestroy();
}

@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind()               " + Thread.currentThread());
return super.onBind(intent);
}

@Override
protected 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 {

@Override
protected 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()方法,代码如下:

@Override
protected 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秒钟,然后运行程序,输出结果如下:


根据输出结果看到,在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()方法,代码如下:
@Override
protected 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();
}
}
运行程序,日志打印结果如下图所示:


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

好了,现在我们清楚了IntentService的执行流程,那接下来我们就从源码的角度来巴拉一下IntentService,看看其内部流程,首先看一下官网对其的说明:


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;
// 是否重新发送Intent
private 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()方法,源码如下:
@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()方法中首先调用了父类的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
*/
@Override
public 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()方法,源码如下:

@Override
public 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的讲解就告一段落,感谢观看。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: