Android 多线程之IntentService

什么是IntentService及特点

IntentService是一种特殊的Service,是继承于Service并且是一个抽象类。

  • IntentService可用于执行后台耗时任务,当任务执行完后会自动停止销毁
  • 由于IntentServce是继承Service的原因,它优先级比普通线程高很多,可以执行一些高优先级的后台任务,并且不会轻易被系统进程杀死
  • IntentService内部是通过HandlerThread和Handler实现异步操作的
  • IntentSerivce使用比较简单,只需实现onHandlerIntent方法与构造函数,就可以实现异步任务。

IntentService使用方法

DownloadIntentService 类 ,注意service要在AndroidMainfest文件中注册

public class DownloadIntentService extends IntentService {

    public static final String TAG = "DownloadIntentService";

    /**
     * 定义内部接口回调,在子线程中执行
     */
    private static UpdateUI mUpdateUI;
    private HandlerActivity.IntentServiceReceiver mReceiver;
    private LocalBroadcastManager mBroadcastManager;

    public interface UpdateUI {
        void updateUI(Message message);
    }

    public static void setUpdateUI(UpdateUI updateUI) {
        mUpdateUI = updateUI;
    }

    /**
     * 在构造函数内必须传值,否则会抛出异常
     */
    public DownloadIntentService() {
        super("test");
    }

    /**
     *
     */
    @Override
    protected void onHandleIntent(@Nullable Intent intent) {

        //模拟网络请求等待
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        int result = 0;
        if (intent != null) {
            result = intent.getExtras().getInt(TAG);
        }
        Message message = Message.obtain();
        message.what = result;
        //通过接口回调的方式,把结果返回到activity,也可通过广播的形式回传
        if (mUpdateUI != null) {
            mUpdateUI.updateUI(message);
        }

    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate: ");
        //动态注册本地广播
       // mBroadcastManager = LocalBroadcastManager.getInstance(this);
       // IntentFilter intentFilter = new IntentFilter();
        //intentFilter.addAction("com.hzw.receiver.LOCAL_BROADCAST");
       // mReceiver = new HandlerActivity.IntentServiceReceiver();
        //mBroadcastManager.registerReceiver(mReceiver, intentFilter);
    }

    @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);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind: ");
        return super.onBind(intent);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG, "onUnbind: ");
        return super.onUnbind(intent);
    }

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


}

Activity类部分代码

Intent intent = new Intent(this, DownloadIntentService.class);
               //循环多次启动了service,其实只创建一个Service实例
                for (int i = 0; i <5 ; i++) {
                    intent.putExtra(DownloadIntentService.TAG,i);
                    startService(intent);
                }
                DownloadIntentService.setUpdateUI(new DownloadIntentService.UpdateUI() {
                    //必须通过handler更新UI,此方法是异步方法
                    @Override
                    public void updateUI(Message message) {
                        //通知主线程更新UI
                        mServiceHanlder.sendMessageAtTime(message,1000);
                    }
                });

-----------------------------------------------------------------
  private Handler mServiceHanlder=new Handler(){
       @Override
       public void handleMessage(Message msg) {
           mTvContent.setText(String.valueOf(msg.what));
       }
   };

使用IntentService需要注意构造方法内必须传入值实现,否则会抛出异常的,另外一个就是onHandleThread是异步方法,在通过接口回调到Activity时,需要同Handler来更新UI。在代码中我们循环多次启动service服务,并不会创建多个实例,只有一个service实例,这和传统的Service是一样的。当我们循环多次启动service,是不是会把之前的结果覆盖呢?其实是不会的,因为IntentServie内部是Handler+HandlerThread,有自己的Looper对象及消息队列,当我们每启动一次把onHandleThread异步执行的结果插入到消息队列中,然后通过Looper依次从消息队列中取出来。运行以上代码:

03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onCreate: 
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStartCommand: 
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStart: 
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStartCommand: 
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStart: 
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStartCommand: 
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStart: 
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStartCommand: 
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStart: 
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStartCommand: 
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStart: 
03-10 15:21:35.569 2474-2474/com.pos.handler D/DownloadIntentService: onDestroy: 

从以上Log日志打印可以看出,onCreate方法只调用一次,而onStartCommand和onStart方法会调用多次,从而验证了上面所说的多次启动IntentService只会有一个实例,最后当异步任务执行完成后,IntentService会自动销毁。

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);
    }

当IntentService一启动,onCreate方法就会被调用,从onCreate方法可以看出,其内部创建了HandlerThread对象(本身就是工作线程,有异步能力),接着启动了线程,然后把通过HandlerThread的getLooper方法获取Looper对象,并把HandlerThread持有的异步线程Looper对象传入ServiceHanlder对象(继承Handler)中,从而ServiceHandler内部就有异步线程的Looper对象,这样ServiceHandler对象就有了执行异步任务的能力。
上面分析了ServiceHandler持有异步线程,那IntentService是怎么启动异步任务的,接下来分析onStartComand和onStart方法:

 @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;
    }

当onCreate方法被调用后,接下来会执行onStartCommand方法,在onStartCommand内又会调用onStart方法,在onStart方法中,会通过mServiceHandler对象发送一个消息到HandlerThread处理并插入到消息队列中,接着HandlerThread中Looper对象会从消息队列中取出来,回传给ServiceHandler对象处理,ServiceHandler会调用handleMessage方法,在其内做异步任务操作,接下来看看mServiceHandler的源码:

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);
        }
    }

/**
     * 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 {@link #stopSelf}.
     *
     * @param intent The value passed to {@link
     *               android.content.Context#startService(Intent)}.
     *               This may be null if the service is being restarted after
     *               its process has gone away; see
     *               {@link android.app.Service#onStartCommand}
     *               for details.
     */
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);

从源码中可以看出handleMessage方法内的onHandleIntent是一个抽象方法,也就是该方法是必须实现的。因ServiceHandler本身就是一个处理异步任务的类(前面已经分析过了),所以onHandleIntent是异步方法,是在工作线程中运行的,当异步任务执行完后,会调用stopSelf(msg.arg1)尝试停止服务。这里采用stopSelf(int startId)而不是stopSelf()来停止服务,是因为stopSelf()会立即停止服务,而stopSelf(int startId)会等待所有消息都处理完后才终止服务。

总结

如果后台任务只有一个,在onHandleIntent内执行异步任务完后,IntentService会自动销毁;如果后台任务有多个,执行完最后一个IntentService的异步任务,才会自动销毁,因为每次执行一个后台异步任务,都会启动一次IntentService,而IntentService内部是通过发消息的方式给HandlerThread处理,会通过Handler中的Looper对象(就是HandlerThread内部的Looper对象)依次从消息队列取出回传给Handler的handleMessage方法处理。也就是说如果后台有多个异步任务,会按照外部的调用顺序依次执行 ,直到最后一个执行完毕后,IntentService才会自动销毁。

猜你喜欢

转载自blog.csdn.net/hzw2017/article/details/79504592