IntentService实例讲解和源码分析

前言
  • 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. 分析结果
  1. constructor、onCreate仅走了一次,IntentService和普通Service一样,多次start,仅仅创建一个实例,onCreate生命周期仅走一次;
  2. 多次start,都会重复走生命周期:onStartCommand–>onStart–>onHandleIntent
  3. onHandleIntent中可以执行多线程操作,例如阻塞线程;这是与UI线程不可阻塞最大的区别;
  4. onHandleIntent的任务是顺序执行的,当前一个任务执行完毕后才能执行下一个任务
  5. onHandleIntent执行在工作线程,线程名称是IntentService[name],name是构造函数中传入的
  6. 当所有任务执行完毕之后,IntentService自动onDestroy,自动销毁本身,无需stop
3. 分析IntentService源码
  1. 首先从构造函数看起:
    /**
     * 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哪里用到呢?
  2. IntentService的两大组件:HandlerThreadServiceHandler
    @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何时调用的:
  3. 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调用了onStartonStart又发送了消息,消息中携带了startService时传入的 intent;后续的任务都交给了handlMessage处理;
  4. 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;
    }
    
      这里stopSelfstopSelfResult代码基本一致,只是返回值为void;通过注释可以看出,这个接口的每次调用不一定真的就销毁了该Service,只有当startId与最近一次startService的Id相同,才会stop这个服务
      参数startId:int,用来标识Service的启用号。每次startService()系统会自动为开启的Service产生一个不同的startId,之前赋予它的startId(如果有)将会被覆盖,并且这个新产生的startId会成为这个Service的新的startId,无论Service是否正在运行。说明一下,startId是AMS生成的,不可由应用层指定
      因此当最后一次onHandleIntent执行完毕后,会发现,这次的startId与最后一次的startId一致,因此才会成功的销毁这个服务;
总结
  1. IntentService是一个内置了工作线程的服务
  2. 工作线程是单线程,且任务按照队列先入先出原则依次执行
  3. 工作线程执行完毕就会自动销毁服务,不必手动stop
  4. IntentService可以用来做可靠的耗时任务处理,例如网络下载、关键的异步任务等等,因为是由Service创建的线程,因此执行过程不会由于Activity的退出而降低优先级而被系统清理中断,因此很可靠
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值