Androidマルチスレッド(四)IntentServiceソースの原理解析

9425 ワード

InentServiceの概要
前の文章でHandlerThreadソースコードの原理解析はHandlerThreadの使い方と原理を学びましたが、実はAndroidのマルチスレッド実装にはHandlerThreadとServiceを有機的に結合したクラスがあります.それがIntentServiceです.まず、サービス自体に問題があります.サービスと起動コンポーネントは同じスレッドにあり、サービスで時間のかかる操作を処理するとプライマリ・スレッドがブロックされる可能性があります.IntentServiceの存在はこの問題を完璧に解決し、IntentServiceはServiceに継承され抽象クラスであるため、IntentServiceを使用するにはそのサブクラスを作成する必要があります.IntentServiceの使い方よりも簡単です.一般的には、onHandleIntentメソッドを書き直す必要があります.例えば、次の例です.
public class FaceDetectionService extends IntentService {
    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public FaceDetectionService(String name) {
        super(name);
    }
    public FaceDetectionService(){
        super("faceDetectionService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        ArrayList mMediaList = intent.getParcelableArrayListExtra("mediaItemList");
        for (int i = 0; i < mMediaList.size(); i++) {
            try {
                Bitmap bitmap = Glide
                        .with(getBaseContext())
                        .asBitmap()
                        .apply(new RequestOptions().format(DecodeFormat.PREFER_RGB_565))
                        .load(mMediaList.get(i).getUriString())
                        .submit()
                        .get();
                FaceDetector faceDetector = new FaceDetector(bitmap.getWidth(), bitmap.getHeight(), 5);
                FaceDetector.Face []faces = new FaceDetector.Face[5];

                long start = System.currentTimeMillis();
                System.out.println("get the face : " + faceDetector.findFaces(bitmap, faces));
                System.out.println("time is :" + (System.currentTimeMillis() - start));
                System.out.println("the bitmap size is : " + bitmap.getByteCount() / 1024);
                if (bitmap != null && !bitmap.isRecycled()) {
                    bitmap.recycle();
                    bitmap = null;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }

}

InentServiceソース分析
IntentServiceは他のコンポーネントが開始したIntentを管理するためにキューを使用し、新しいスレッドを開いてIntent要求を処理します.このスレッドはこのメッセージによって、一度に1つのIntentだけを処理することを保証します.そのため、IntentServiceは時間のかかるバックグラウンドタスクを処理するために使用できます.タスクが実行されると自動的に停止します.また、IntentService自体がServiceに継承されるため、単純なスレッドよりも優先度が高くなります.システムによって殺されにくいため、IntentServiceは優先度の高い長時間のバックグラウンドタスクを実行するのに適しています.次に、InentServiceがどのように機能しているかをソースコードから見てみましょう.
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;
    }

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

    @Override
    public void onCreate() {
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    @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() {
        mServiceLooper.quit();
    }

    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

実はIntentServiceのソースコードは少なく、注釈を除いて数十行程度しかありません.初めてInentServiceを起動すると、まずInentServiceのonCreate()メソッドにコールバックし、onCreate()にHandlerThreadを作成し、HandlerThreadでLooperオブジェクトmServiceLooperを取得し、mServiceLooperでHandlerオブジェクトmServiceHandlerを作成します.また、独自のメッセージ処理メカニズムがあり、mServiceHandlerによって送信されるメッセージは、mServiceHandlerのhandlerMessage()で処理されます.startServices()を複数回呼び出すとonCreate()が1回しか呼び出されないことを知っていますが、毎回onStartCommand()が呼び出され、このメソッドではonStart()というメソッドが呼び出され、onStart()で他のコンポーネントが発起したIntentが処理されます.このメソッドでは、IntentとstartIdをMessageにカプセル化してmServiceHandlerに送信し、メッセージを受信すると、IntentオブジェクトをonHandleIntent()に渡して処理します.Intentによって他のコンポーネントがIntentServiceに送信する処理が必要なパラメータを得ることができ、これらのパラメータによって具体的な操作を実行することができ、onHandleIntent()は抽象的な空の方法であることに気づいたので、私たちがしなければならないのはIntentServiceのサブクラスでこの方法を実現することです.onHandleIntent()が実行された後、stopSelf(startId)によってサービスを停止します.stopSelf(startId)は、特定のIntentによって開始されたサービス要求のいずれかを停止するだけであることに注意してください.この場合、IntentServiceサービスは完全に停止していません.後のメッセージは処理を継続することができ、すべてのメッセージが処理された後、IntentServiceサービスは本当に終了します.startService()を介してバックグラウンドタスクを開くたびに、mServiceHandlerによって情報が送信され、処理されることが知られています.HandlerのLooperは、メッセージの前後順に実行されます.これにより、InentServiceによって起動されるバックグラウンドタスクも順番に実行されます.これでInentServiceの解析は完了し、時間がかかる優先度の高いバックグラウンドタスクを実行する必要がある場合は、InentServiceを使用して実行することを考慮することができます.