Android multi-threading-IntentService use and principle analysis

In the last chapter, we learned about HandlerThread. In this chapter, let's take a look at the last class IntentService commonly used in Android multi-threaded communication. As the name suggests, IntentService is a subclass of Service, and its essence is still a service, but it still has some differences from its parent class. Let's talk about it in detail below.

The difference between IntentService and Service

  • IntentService is a subclass of Service and also needs to be registered in the AndroidManifest file
  • IntentService can perform asynchronous operations in its onHandleIntent method. To perform asynchronous operations, Service needs to open up child threads
  • IntentService does not use bindService to start, because its asynchronous method will not be executed after using bindService, and the internal HandlerThread will not be initialized
  • IntentService does not need to execute the stop or stopSelf method to close. After the asynchronous task is executed, stopSelf will be automatically called internally.
  • IntentService is a serial mode, the tasks put into the IntentService will be executed in sequence, and they will be destroyed after all executions are completed.

Simple use of IntentService

The use of IntentService is very simple, divided into the following steps:

  1. Create a new subclass to inherit IntentService, register the Service in AndroidManifest, override the onHandleIntent method and perform asynchronous operations in the onHandleintent method
  2. Generally, IntentService is called in Activity, which is similar to using ordinary Service, but instead of using the binding method, startService should be used to start, and put the corresponding data in the Intent
  3. Use Handler or local broadcast to pass the asynchronous execution result of onHandleIntent to the main thread
  4. The main thread gets the result of the asynchronous operation and processes and displays it, etc.

code example

Create a new IntentService subclass and override the onHandleIntent method:

/**
 * 工作线程执行,其原理还是Handler,详细细节见源码
 * @param intent
 */
@WorkerThread
@Override
protected void onHandleIntent(@Nullable Intent intent) {
    Bundle bundle = intent.getExtras();
    String fileName = bundle.getString("file_name");
    Log.e(TAG,"当前下载"+fileName+"当前线程id"+Thread.currentThread().getId());
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    Intent resultIntent = new Intent(DOWNLOAD_FINISH);
    resultIntent.putExtras(bundle);
    LocalBroadcastManager.getInstance(this).sendBroadcast(resultIntent);
}

Activity start service

//启动两次,但是顺序执行,第一个任务执行完毕才会执行第二个任务的操作
public void onClick(View view) {
    Intent intent = new Intent(this,DownLoadIntentService.class);
    Bundle bundle = new Bundle();
    bundle.putString("file_name","巴啦啦小魔仙.mp4");
    intent.putExtras(bundle);
    startService(intent);

    Intent intent2 = new Intent(this,DownLoadIntentService.class);
    Bundle bundle2 = new Bundle();
    bundle2.putString("file_name","金刚葫芦娃.mp4");
    intent2.putExtras(bundle2);
    startService(intent2);
}

Use local broadcast to pass to the main thread

Intent resultIntent = new Intent(DOWNLOAD_FINISH);
resultIntent.putExtras(bundle);
LocalBroadcastManager.getInstance(this).sendBroadcast(resultIntent);

Activity gets the result and handles it accordingly

intentFilter = new IntentFilter(DownLoadIntentService.DOWNLOAD_FINISH);
receiver = new DownLoadBroadcastReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(receiver,intentFilter);

private class DownLoadBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if(TextUtils.equals(intent.getAction(),DownLoadIntentService.DOWNLOAD_FINISH)) {
            Bundle bundle = intent.getExtras();
            String fileName = bundle.getString("file_name");
            String result = tvResult.getText().toString();
            result += "名为"+fileName+"的文件下载完成!\r";
            tvResult.setText(result);
            Toast.makeText(IntentServiceDemoActivity.this,"下载完成,当前下载文件名"+fileName,Toast.LENGTH_SHORT).show();
        }
    }
}

Here I use local broadcast for message delivery.

program execution result

Source code analysis

We open the source code of IntentService to analyze its implementation principle.

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;//子线程绑定的Looper
    private volatile ServiceHandler mServiceHandler;//HandlerThread实例
    private String mName;//传入的参数,默认缺省
    private boolean mRedelivery;

    /** 绑定工作线程Handler,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);
        }
    }

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

    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //生成一个HandlerThread实例并启动这个线程
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
        //将HandlerThread中的Looper与该Service 绑定,并新建子线程Handler
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    //调用startService后调用onStartCommand并转到该方法中
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
        //发出消息,arg1带上自身ID,使其完成时关闭自身
    }

    //如果系统在服务完成之前关闭Service,START_NOT_STICKY型服务会直接被关闭,而START_REDELIVER_INTENT 型服务会在可用资源不再吃紧的时候尝试再次启动服务。
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        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) {
        //默认返回null
        return null;
    }

    /** 子线程中运行,在Handler的handleMessage中调用此方法 **/
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

You can see that there are only 100 lines after the comments are deleted. The specific analysis can be reflected as:

Call startService() -> onCreate() is called, bind a HandlerThread to the current Service, and generate a child thread Handler -> onStartCommand() is called -> finally call the onStart(@Nullable Intent intent, int startId) method and send The message is given to the message loop -> the rest is the Handler's message processing process, which finally calls onHandleIntent and calls stopSelf to close itself after execution.

This is the content of this chapter. If there are errors or deviations in the content of the article, I hope you can contact me and I will make changes as soon as possible.

demo ruins

My personal blog , welcome to visit~

Thanks for reading~

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325542865&siteId=291194637