标签:
转载请注明出处: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()); } @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()函数中只能返回以下三种类型中的一种:
然后我们看一下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的讲解就告一段落,感谢观看。
Android 源码系列之<七>从源码的角度深入理解IntentService及HandlerThread
标签:
原文地址:http://blog.csdn.net/llew2011/article/details/51373243