IntentServiceの原理の詳細
5108 ワード
InentServiceはサービスに継承されていますが、その特徴は何ですか?龍叔小プログラムの特徴と同じように、「使い終わったらすぐ行く」.
IntentServiceを利用したことがある人はみな知っています.使用は非常に簡単で、自分でスレッドを構築したり、スレッドの通信を維持したりする必要はありません.最後のリソースの解放も私たちが自分で処理する必要はありません.私たちは業務の実現に専念すればいいです.つまり、onHandleIntent(Intent intent)方法のコードを書くことです.具体的にはここでは言いません.実は私たちは前の文章:タイミングタスクのAlarmは、すでにIntentServiceを使用しています.今日は主にIntentServiceの原理を分析します.
原理を分析するには、もちろんソースコードを見なければなりません.一歩一歩見てみましょう.
InentServiceを起動するには、もちろん先進的なonCreate方法があります.上のソースコードから見ると、最初のステップではHandlerThreadを作成し(HandlerThreadに関する説明については、Handler関連はこの記事を見てください)、スレッドを起動してLooperを取得し、HandlerThreadのLooperをServiceHandlerにバインドします.ServiceHandlerのソースコードを見てみましょう.
ServiceHandlerは内部クラスで、Handlerに継承されています.handleMessageではよく知られている方法を見ました.onHandleIntent(Intent intent)です.ああ、IntentServiceで最も重要なオーバーライドを使用していたonHandleIntent方法はここで呼び出されました.ここでは、いくつかの点を説明します.1)ServiceHandlerはHandlerThreadのLooperにバインドされているので、したがってonHandleIntentメソッドはサブスレッドで実行される.2)onHandleIntentの実行が完了するとstopSelf(msg.arg 1)が呼び出されることに気づきました.これは、IntentServiceが「使い終わったらすぐに行く」ことができる理由です.タスクが完了すると、自分のサービスが停止するからです.3)注意:ここで自分でサービスを止めるのはstopSelf(int startId)方法で、stopSelf()ではありません.なぜですか.では、まずこの2つのAPIの違いを説明しなければなりません.まずstopSelf()のソースコードを見てみましょう.
stopSelf()がstopSelf(int startId)を呼び出したのは、startIdが-1にすぎないことが分かった.このstartIdといえば、何ですか?実はサービスのライフサイクルです.onStartCommand(@Nullable Intent intent,int flags,int startId)の最後のパラメータです.同じサービスを起動するためにstartServiceを複数回呼び出すと、onCreateが最初に実行され、onStartCommandが複数回呼び出されます.logを印刷すると、onCreateは1回しか実行されませんが、startIdは毎回異なり、0より大きいことがわかります.一方、stopSelf(int startId)のstartIdは、onStartCommandのstartIdと一対一の関係にあるため、stopSelf(int startId)を呼び出すと、他のstartIdが存在するか否かが検出され、現在のサービスが破棄されず、存在しない場合は破棄される.stopSelf()を呼び出すと、他のstartIdが存在するかどうかにかかわらず、現在のサービスはすぐに破棄されます.これがstopSelf()とstopSelf(int startId)の2つの方法の違いです!
以前の質問に戻りますが、なぜIntentServiceではstopSelf()ではなくstopSelf(int startId)がセルフストップサービスで使われているのでしょうか.上記の2つの方法の違いを比較すると、これはIntentServiceの利用率を向上させるためであり、つまりonHandleIntentメソッドの実行が完了する前にstartServiceを呼び出して同じIntentServiceを起動した場合、現在のサービスを破棄する必要はなく、現在のサービスオブジェクトでタスクを実行し続けるだけでよい.これにより、オブジェクトの破棄や作成を減らすことができます.
また、ここでは、IntentServiceではHandlerThread、つまり単一のスレッドを使用しているため、IntentServiceでタスクを実行するのはシリアル順のみです.
次に、ソースコードの分析を続けます.onStartCommandについてお話ししました.ソースコードも見てみましょう.
onStartCommandの最初のステップはonStartを呼び出します.onStartメソッドから、実は上のhandlerでメッセージを送信し、メインスレッドからサブスレッドに切り替えてタスクを実行していることがわかります.これは何も言うことはありません.次に、次の行のコードを見て、値を返します:mRedelivery?START_REDELIVER_INTENT : START_NOT_STICKY; mRedeliveryのデフォルト値がfalseであることを確認しました.もちろん、設定する方法はあります.onStartCommandのいくつかの戻り値と違いを簡単に説明します.
1)START_STICKY:サービスプロセスがkillによって削除された場合、サービスを保持する状態は開始状態ですが、送信されたintentオブジェクトは保持されません.その後、サービスステータスが開始状態であるため、サービスを作成すると必ずonStartCommand(Intent,int,int)メソッドが呼び出されます.その間にサービスに起動コマンドが渡されない場合、パラメータIntentはnullになります.2)START_NOT_STICKY:「非粘性」.この戻り値を使用すると、onStartCommandの実行後に異常killでサービスが停止した場合、自動的にサービスを再起動することはありません3)START_REDELIVER_INTENT:Intentを再送します.この戻り値を使用すると、onStartCommandの実行後にサービスが異常killによって削除されると、自動的にサービスが再起動され、Intentの値が入力されます.4)START_STICKY_COMPATIBILITY:START_STICKYの互換バージョンですが、サービスがkillされた後に必ず再起動できる保証はありません.
上の説明から分かりましたが、onStartCommandはデフォルトでSTART_を返しました.NOT_STICKYですので、ここで注意しておきますが、IntentServiceで実行するタスクが非常に重要であれば、setIntentReadeliveryを設定してmReadeliveryをtrueに設定することをお勧めします.そうするとonStartCommandの戻りがSTART_になりますREDELIVER_INTENTは、異常な場合のサービスの再起動とリカバリに有利です.
最後に、破棄方法を見てみましょう.
前にHandler関連でこの文章を見て十分です.この文章でHandlerThreadを紹介したら、HandlerThreadを使うにはLooperを解放することに注意しなければなりません.これは?IntentServiceはonDestroyライフサイクルでLooperの解放を手伝ってくれたので、私たちは「使い終わったらすぐに行く」ことができて、何も処理しなくても、とても便利です.
まあ、多分これだけですが、InentServiceのソースコードを見ても100行以上ですが、実は細かく考えてみると多くのことを学ぶことができます.
IntentServiceを利用したことがある人はみな知っています.使用は非常に簡単で、自分でスレッドを構築したり、スレッドの通信を維持したりする必要はありません.最後のリソースの解放も私たちが自分で処理する必要はありません.私たちは業務の実現に専念すればいいです.つまり、onHandleIntent(Intent intent)方法のコードを書くことです.具体的にはここでは言いません.実は私たちは前の文章:タイミングタスクのAlarmは、すでにIntentServiceを使用しています.今日は主にIntentServiceの原理を分析します.
原理を分析するには、もちろんソースコードを見なければなりません.一歩一歩見てみましょう.
@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);
}
InentServiceを起動するには、もちろん先進的なonCreate方法があります.上のソースコードから見ると、最初のステップではHandlerThreadを作成し(HandlerThreadに関する説明については、Handler関連はこの記事を見てください)、スレッドを起動してLooperを取得し、HandlerThreadのLooperをServiceHandlerにバインドします.ServiceHandlerのソースコードを見てみましょう.
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);
}
}
ServiceHandlerは内部クラスで、Handlerに継承されています.handleMessageではよく知られている方法を見ました.onHandleIntent(Intent intent)です.ああ、IntentServiceで最も重要なオーバーライドを使用していたonHandleIntent方法はここで呼び出されました.ここでは、いくつかの点を説明します.1)ServiceHandlerはHandlerThreadのLooperにバインドされているので、したがってonHandleIntentメソッドはサブスレッドで実行される.2)onHandleIntentの実行が完了するとstopSelf(msg.arg 1)が呼び出されることに気づきました.これは、IntentServiceが「使い終わったらすぐに行く」ことができる理由です.タスクが完了すると、自分のサービスが停止するからです.3)注意:ここで自分でサービスを止めるのはstopSelf(int startId)方法で、stopSelf()ではありません.なぜですか.では、まずこの2つのAPIの違いを説明しなければなりません.まずstopSelf()のソースコードを見てみましょう.
public final void stopSelf() {
stopSelf(-1);
}
stopSelf()がstopSelf(int startId)を呼び出したのは、startIdが-1にすぎないことが分かった.このstartIdといえば、何ですか?実はサービスのライフサイクルです.onStartCommand(@Nullable Intent intent,int flags,int startId)の最後のパラメータです.同じサービスを起動するためにstartServiceを複数回呼び出すと、onCreateが最初に実行され、onStartCommandが複数回呼び出されます.logを印刷すると、onCreateは1回しか実行されませんが、startIdは毎回異なり、0より大きいことがわかります.一方、stopSelf(int startId)のstartIdは、onStartCommandのstartIdと一対一の関係にあるため、stopSelf(int startId)を呼び出すと、他のstartIdが存在するか否かが検出され、現在のサービスが破棄されず、存在しない場合は破棄される.stopSelf()を呼び出すと、他のstartIdが存在するかどうかにかかわらず、現在のサービスはすぐに破棄されます.これがstopSelf()とstopSelf(int startId)の2つの方法の違いです!
以前の質問に戻りますが、なぜIntentServiceではstopSelf()ではなくstopSelf(int startId)がセルフストップサービスで使われているのでしょうか.上記の2つの方法の違いを比較すると、これはIntentServiceの利用率を向上させるためであり、つまりonHandleIntentメソッドの実行が完了する前にstartServiceを呼び出して同じIntentServiceを起動した場合、現在のサービスを破棄する必要はなく、現在のサービスオブジェクトでタスクを実行し続けるだけでよい.これにより、オブジェクトの破棄や作成を減らすことができます.
また、ここでは、IntentServiceではHandlerThread、つまり単一のスレッドを使用しているため、IntentServiceでタスクを実行するのはシリアル順のみです.
次に、ソースコードの分析を続けます.onStartCommandについてお話ししました.ソースコードも見てみましょう.
@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;
}
onStartCommandの最初のステップはonStartを呼び出します.onStartメソッドから、実は上のhandlerでメッセージを送信し、メインスレッドからサブスレッドに切り替えてタスクを実行していることがわかります.これは何も言うことはありません.次に、次の行のコードを見て、値を返します:mRedelivery?START_REDELIVER_INTENT : START_NOT_STICKY; mRedeliveryのデフォルト値がfalseであることを確認しました.もちろん、設定する方法はあります.onStartCommandのいくつかの戻り値と違いを簡単に説明します.
1)START_STICKY:サービスプロセスがkillによって削除された場合、サービスを保持する状態は開始状態ですが、送信されたintentオブジェクトは保持されません.その後、サービスステータスが開始状態であるため、サービスを作成すると必ずonStartCommand(Intent,int,int)メソッドが呼び出されます.その間にサービスに起動コマンドが渡されない場合、パラメータIntentはnullになります.2)START_NOT_STICKY:「非粘性」.この戻り値を使用すると、onStartCommandの実行後に異常killでサービスが停止した場合、自動的にサービスを再起動することはありません3)START_REDELIVER_INTENT:Intentを再送します.この戻り値を使用すると、onStartCommandの実行後にサービスが異常killによって削除されると、自動的にサービスが再起動され、Intentの値が入力されます.4)START_STICKY_COMPATIBILITY:START_STICKYの互換バージョンですが、サービスがkillされた後に必ず再起動できる保証はありません.
上の説明から分かりましたが、onStartCommandはデフォルトでSTART_を返しました.NOT_STICKYですので、ここで注意しておきますが、IntentServiceで実行するタスクが非常に重要であれば、setIntentReadeliveryを設定してmReadeliveryをtrueに設定することをお勧めします.そうするとonStartCommandの戻りがSTART_になりますREDELIVER_INTENTは、異常な場合のサービスの再起動とリカバリに有利です.
最後に、破棄方法を見てみましょう.
@Override
public void onDestroy() {
mServiceLooper.quit();
}
前にHandler関連でこの文章を見て十分です.この文章でHandlerThreadを紹介したら、HandlerThreadを使うにはLooperを解放することに注意しなければなりません.これは?IntentServiceはonDestroyライフサイクルでLooperの解放を手伝ってくれたので、私たちは「使い終わったらすぐに行く」ことができて、何も処理しなくても、とても便利です.
まあ、多分これだけですが、InentServiceのソースコードを見ても100行以上ですが、実は細かく考えてみると多くのことを学ぶことができます.