Android IntentService用法和源码分析

关于IntentService的介绍,我个人觉得还是先看官方描述比较好:

IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
IntentService是Service的子类,它可以处理异步处理请求。Client使用startService(Intent),来发起异步请求。这个Service是会根据需要,使用一个工作线程去处理每个请求,当它处理完所有请求的时候会停止它自身。

This “work queue processor” pattern is commonly used to offload tasks from an application’s main thread. The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.
这种工作队列的模式通常是用于从application 的主线程加载任务。IntentService 这个类的存在是为了简化这种模式并且更加关心机制。为了为了IntentServie,继承IntentService并实现onHandleIntent方法。IntentService将接收Intents,开启一个工作线程,在合适的时候,停止这个Service

All requests are handled on a single worker thread – they may take as long as necessary (and will not block the application’s main loop), but only one request will be processed at a time.
所有的请求都在一个工作线程中处理,这些请求可能花费很多请求(不会阻塞application主线程),但是在同一时间只会处理一个。

通过官网的介绍,我们可以抓住这几个重点:IntentService可以用来处理异步请求,因为它有一个工作线程;它只能通过startService(Intent)这个方法来发送请求;它处理完请求后会自动关闭。

在IntentService中,我们可以知道,有一个很重要的方法:onHandleIntent,先看一下它的官方介绍:

This method is invoked on the worker thread with a request to process. Only one Intent is processed at a time, but the processing happens on a worker thread that runs independently from other application logic. So, if this code takes a long time, it will hold up other requests to the same IntentService, but it will not hold up anything else. When all requests have been handled, the IntentService stops itself, so you should not call stopSelf().
当某个请求需要处理时,这个方法会在工作者线程被调用,一次仅仅会有一个请求被处理,但是处理过程会运行在工作者线程(独立于其他应用程序逻辑运行)。因此,如果某段代码需要执行很长时间,它会阻塞住其他提交到该IntentService的请求,但是不会阻塞住其他任何东西。当所有的请求被处理完成之后,IntentService会停止它自身,因此你不应该手动调用stopSelf()方法。

接下来,我们来看看它的用法:

public class HandlerService extends IntentService {

    private static final String TAG = "HandlerService";

    public HandlerService() {
        super("HandlerService");
        Log.d(TAG, "HandlerService: "+Thread.currentThread().getName());
        
    }


    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {

        Log.d(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {

        Log.d(TAG, "onStart: ");
        super.onStart(intent, startId);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        Log.d(TAG, "onHandleIntent: ");
        Log.d(TAG, "HandlerService: "+Thread.currentThread().getName());
        String path = intent.getStringExtra("path");
        downloadTask(path);

    }

    private void downloadTask(String path){
        Log.d(TAG, "downloadTask: ");
       try {
           Thread.sleep(3*1000);
       }catch (InterruptedException e){
           e.printStackTrace();
       }

      Intent intent = new Intent(MainActivity.BROCAST_MSG);
       intent.putExtra("path",path);
       sendBroadcast(intent);
    }


    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy: ");
        super.onDestroy();
    }

}

然后看看调用:

    public static String BROCAST_MSG = "FINISH";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        registerReceiver(broadcastReceiver,new IntentFilter(BROCAST_MSG));

        Intent intent = new Intent(this,HandlerService.class);
        intent.putExtra("path","http://www:xxx.xxx");
        startService(intent);
        startService(intent);
        startService(intent);


    }

    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if(intent!=null){
                if(intent.getAction()!=null&&intent.getAction().equals(BROCAST_MSG)){
                    System.out.println(intent.getStringExtra("path"));
                }
            }
        }
    };

记得在Manifest中注册
我们看看结果:

D/HandlerService: HandlerService: main
D/HandlerService: onStartCommand: 
    onStart: 
D/HandlerService: onHandleIntent: 
    HandlerService: IntentService[HandlerService]
    downloadTask: 
D/HandlerService: onStartCommand: 
    onStart: 
    onStartCommand: 
    onStart: 

D/HandlerService: onHandleIntent: 
D/HandlerService: HandlerService: IntentService[HandlerService]
    downloadTask: 
I/System.out: http://www:xxx.xxx
D/HandlerService: onHandleIntent: 
D/HandlerService: HandlerService: IntentService[HandlerService]
    downloadTask: 
I/System.out: http://www:xxx.xxx
I/System.out: http://www:xxx.xxx
D/HandlerService: onDestroy: 

在这里,我用的是广播来传递消息。如果不想使用广播的,可以使用EventBus。

接下来就来看看IntentService的源码:

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    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);
        }
    }

  
    public IntentService(String name) {
        super();
        mName = name;
    }

  	
  	//设置Intent是否重投递,如果重投递,在onHandleIntent方法返回前,
  	//如果进程死了,会重启进程,重新分发Intent
  	//但是只会分发最近的一个Intent
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {
     
        super.onCreate();
        //通过实例化HandlerThreade新建线程&启动
        //故,使用IntentService时,不需要额外新建线程。
        //HandlerThread继承自Thread,内部封装了Looper
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
		//获取工程线程的Looper&维护自己的工作队列
        mServiceLooper = thread.getLooper();
		//新建ServiceHandler,绑定上面的Looper
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
    	//获取ServiceHandler消息的引用
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        //发送消息,添加到消息队列
        mServiceHandler.sendMessage(msg);
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
    	//调用omnStart()方法
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
    	//Looper停止
        mServiceLooper.quit();
    }

 
    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }

 
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}


//Service.java
 public final void stopSelf(int startId) {
        if (mActivityManager == null) {
            return;
        }
        try {
            mActivityManager.stopServiceToken(
                    new ComponentName(this, mClassName), mToken, startId);
        } catch (RemoteException ex) {
        }
    }

我们可以看到,在onCreate()方法中,有初始化一个HandlerThread,HandlerThread可以看出,就是Handler+Thread的结合,并且获取到了工作线程的Looper,使用工作线程的Looper现在属于工作线程的Handler。

从上面的源码中,我们可以看出:IntentService = Handler+HandlerThread。
通过onStartCommand()方法传递服务IntentServiceHandler,依次插入Intent到工作队列,在handleMeassage()中逐个调用onHandleIntent()方法。
通过onHandlerIntent()依次处理Intent对应的任务。

因此我们可以通过复写onHandleIntent(),根据Intent的不同进行不同线程操作即可。

注意事项
  1. 工作任务队列 = 顺序执行
    即若一个任务正在IntentService中执行,此时再发送一个新的任务请求,这个新的任务会一直等到直到前面一个任务执行完毕后才开始执行。
    原因:
    1. 由于onCreate()只会调用一次,所以只会创建一个工作线程。
    2. 当多次调用startService时(即onStartCommand()也会调用多次),其实不会创建新的工作线程,只是把消息加入消息队列,等待执行。
    3. 所以,多次启动IntentService会按顺序执行事件。

若服务停止,则会清楚消息队列中的消息,后续的事件不执行。如果服务已经停止,又地调用了startService,将重新开启一个新的IntentService。

  1. 不建议通过bindService()启动IntentService
    如果采用bindService()启动IntentService的声明周期:

onCreate() ->> onBind() ->> onunbind()->> onDestory()
即,并不会调用onStartonStartCommand,所以不会将消息发送给消息队列,那么onHandleIntent将不会调用。即无法实现多线程的操作。

这里有一个问题,还记得我们的例子嘛?我们连续调用了三次Service,onHandlerIntent确实调用了三次,但是onDestroy只调用了一次,在源码中,我们看到,在handleMessage方法中,在调用完onHandlerIntent方法后,立马调用了stopSelf(int)方法,为什么IntentService没有立马销毁,调用onDestroy,而是继续处理呢?

还记得public int onStartCommand(@Nullable Intent intent, int flags, int startId)方法吗?这里的startId和stopSelf(int startId)里的参数是一一对应的,如果stopSelf(int startId)后,如果onStartCommand成对调用后,service就会被销毁(onDestroy方法就会被调用),否则Service一直处于运行状态。

在调用stopSelf(int startId)的过程中,系统会检测是否还有startId存在,如果存在,则不销毁service,否则销毁service,当onStartCommand和它成对的时候,service才会被销毁,当然如果你直接调用stopSelf(-1),那么将直接销毁service,系统就不会检测是否还有其他的startId存在。因此,如果直接调用stopSelf(),它会调用stopSelf(-1),就会立即销毁service。

参考:https://www.jianshu.com/p/8a3c44a9173a

你可能感兴趣的:(android)