IntentService实例讲解和源码分析

    xiaoxiao2022-07-03  131

    前言

    IntentService= Service+ 多线程,其中涉及到Handler队列请求,多线程Lopper的使用,IntentService的自动销毁

    1. 演示示例

    效果是连续点击一个按钮,触发startService,将任务交给IntentService处理;

    public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } //点击button触发 public void startService(View view) { Log.d(TAG, "click button to start service"); Intent intent = new Intent(this, TestIntentService.class); startService(intent); } } //service 代码 public class TestIntentService extends IntentService { private static final String TAG = "IntentService"; public TestIntentService() { super("intent-service"); Log.d(TAG, "constructor"); } @Override public void onCreate() { Log.d(TAG, "onCreate"); super.onCreate(); } @Override public void onStart(Intent intent, int startId) { Log.d(TAG, "onStart"); super.onStart(intent, startId); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override protected void onHandleIntent(Intent intent) { Log.d(TAG, "onHandleIntent"); for (int i = 0; i < 8; i++) { Log.d(TAG, "onHandleIntent ----"+Thread.currentThread().getName()+", i="+i); try { Thread.sleep(800); } catch (InterruptedException e) { e.printStackTrace(); } } } @Override public void onDestroy() { Log.d(TAG, "onDestroy"); super.onDestroy(); } } 多次频繁点击按钮,日志如下: 2019-05-22 11:13:41.793 5863-5863/com.linx.jnitest D/MainActivity: click button to start service 2019-05-22 11:13:41.876 5863-5863/com.linx.jnitest D/IntentService: constructor 2019-05-22 11:13:41.877 5863-5863/com.linx.jnitest D/IntentService: onCreate 2019-05-22 11:13:41.890 5863-5863/com.linx.jnitest D/IntentService: onStartCommand 2019-05-22 11:13:41.890 5863-5863/com.linx.jnitest D/IntentService: onStart 2019-05-22 11:13:41.891 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent 2019-05-22 11:13:41.891 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=0 2019-05-22 11:13:42.121 5863-5863/com.linx.jnitest D/MainActivity: click button to start service 2019-05-22 11:13:42.149 5863-5863/com.linx.jnitest D/IntentService: onStartCommand 2019-05-22 11:13:42.149 5863-5863/com.linx.jnitest D/IntentService: onStart 2019-05-22 11:13:42.484 5863-5863/com.linx.jnitest D/MainActivity: click button to start service 2019-05-22 11:13:42.489 5863-5863/com.linx.jnitest D/IntentService: onStartCommand 2019-05-22 11:13:42.490 5863-5863/com.linx.jnitest D/IntentService: onStart 2019-05-22 11:13:42.692 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=1 2019-05-22 11:13:43.493 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=2 2019-05-22 11:13:44.294 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=3 2019-05-22 11:13:45.095 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=4 2019-05-22 11:13:45.895 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=5 2019-05-22 11:13:46.696 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=6 2019-05-22 11:13:47.497 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=7 2019-05-22 11:13:48.300 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent 2019-05-22 11:13:48.300 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=0 2019-05-22 11:13:49.101 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=1 2019-05-22 11:13:49.901 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=2 2019-05-22 11:13:50.702 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=3 2019-05-22 11:13:51.503 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=4 2019-05-22 11:13:52.304 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=5 2019-05-22 11:13:53.104 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=6 2019-05-22 11:13:53.905 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=7 2019-05-22 11:13:54.708 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent 2019-05-22 11:13:54.708 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=0 2019-05-22 11:13:55.509 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=1 2019-05-22 11:13:56.310 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=2 2019-05-22 11:13:57.110 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=3 2019-05-22 11:13:57.911 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=4 2019-05-22 11:13:58.712 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=5 2019-05-22 11:13:59.513 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=6 2019-05-22 11:14:00.313 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=7 2019-05-22 11:14:01.118 5863-5863/com.linx.jnitest D/IntentService: onDestroy

    2. 分析结果

    constructor、onCreate仅走了一次,IntentService和普通Service一样,多次start,仅仅创建一个实例,onCreate生命周期仅走一次;多次start,都会重复走生命周期:onStartCommand–>onStart–>onHandleIntentonHandleIntent中可以执行多线程操作,例如阻塞线程;这是与UI线程不可阻塞最大的区别;onHandleIntent的任务是顺序执行的,当前一个任务执行完毕后才能执行下一个任务onHandleIntent执行在工作线程,线程名称是IntentService[name],name是构造函数中传入的当所有任务执行完毕之后,IntentService自动onDestroy,自动销毁本身,无需stop

    3. 分析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,name是用来给工作线程命名的,可以用来debug;很简单那么name哪里用到呢?IntentService的两大组件:HandlerThread和ServiceHandler@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() /*这里获取该子线程的Looper*/ mServiceHandler = new ServiceHandler(mServiceLooper); } 从这里可以看出,onCreate中创建了一个HandlerThread和一个ServiceHandler;name作为HandlerThread的[name]参数传入 ServiceHandler使用了HandlerThread的looper,所以这个Handler创建后,会采用HandlerThread线程的Looper来构建内部消息循环系统,也就是说其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); } } HandlerThread继承自Thread,是一个线程,并且具备自己的looper,可以通过 getLooper() 获取;@Override 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 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; } 这里可以看出,Looper是在run()方法中创建的,如果getLooper()为null时,就等待直到run方法创建了looper 下面来看看onHandleIntent何时调用的:onHandleIntent的调用:@Override public void onStart(@Nullable 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(@Nullable Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } 这里可以看出onStartCommand调用了onStart,onStart又发送了消息,消息中携带了startService时传入的 intent;后续的任务都交给了handlMessage处理;handleMessage的逻辑: 我们再来看一下ServiceHandler怎么处理消息的: @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); } 可以看出,首先将消息交给子线程处理,然后再结束掉该Service;那么onDestroy应该每次都执行,显然不对,那么为什么最后才onDestroy呢? 再看stopSelf的源码:在Service.java中/** * Old version of {@link #stopSelfResult} that doesn't return a result. * * @see #stopSelfResult */ public final void stopSelf(int startId) { if (mActivityManager == null) { return; } try { mActivityManager.stopServiceToken( new ComponentName(this, mClassName), mToken, startId); } catch (RemoteException ex) { } } /** * Stop the service if the most recent time it was started was * <var>startId</var>. This is the same as calling {@link * android.content.Context#stopService} for this particular service but allows you to * safely avoid stopping if there is a start request from a client that you * haven't yet seen in {@link #onStart}. * * <p><em>Be careful about ordering of your calls to this function.</em>. * If you call this function with the most-recently received ID before * you have called it for previously received IDs, the service will be * immediately stopped anyway. If you may end up processing IDs out * of order (such as by dispatching them on separate threads), then you * are responsible for stopping them in the same order you received them.</p> * * @param startId The most recent start identifier received in {@link * #onStart}. * @return Returns true if the startId matches the last start request * and the service will be stopped, else false. * * @see #stopSelf() */ public final boolean stopSelfResult(int startId) { if (mActivityManager == null) { return false; } try { return mActivityManager.stopServiceToken( new ComponentName(this, mClassName), mToken, startId); } catch (RemoteException ex) { } return false; }   这里stopSelf与stopSelfResult代码基本一致,只是返回值为void;通过注释可以看出,这个接口的每次调用不一定真的就销毁了该Service,只有当startId与最近一次startService的Id相同,才会stop这个服务。   参数startId:int,用来标识Service的启用号。每次startService()系统会自动为开启的Service产生一个不同的startId,之前赋予它的startId(如果有)将会被覆盖,并且这个新产生的startId会成为这个Service的新的startId,无论Service是否正在运行。说明一下,startId是AMS生成的,不可由应用层指定   因此当最后一次onHandleIntent执行完毕后,会发现,这次的startId与最后一次的startId一致,因此才会成功的销毁这个服务;

    总结

    IntentService是一个内置了工作线程的服务工作线程是单线程,且任务按照队列先入先出原则依次执行工作线程执行完毕就会自动销毁服务,不必手动stopIntentService可以用来做可靠的耗时任务处理,例如网络下载、关键的异步任务等等,因为是由Service创建的线程,因此执行过程不会由于Activity的退出而降低优先级而被系统清理中断,因此很可靠
    最新回复(0)