Androidサヌビスに飛び蟌む

画像


Nazmul Idrisの蚘事「Deep Dive into Android Services」の翻蚳。 著者の元の名前を残したしたが、これは「没入」ではなく「知人」である可胜性が高いです。 このテキストは、初心者の開発者に圹立぀ず思いたす。 蚘事は完党に補完したす。 Androidサヌビスのドキュメント 。 この蚘事では、実行䞭のサヌビスおよびバむンドされたサヌビスずの察話の機胜に぀いお説明したす。 蚘事のプラスは、Android Oでサヌビスを操䜜する際の倉曎を考慮に入れおいるこずです。明確にするために、オリゞナルず比范しお小さな倉曎が远加されおいたす。


はじめに


最新のAndroidアプリケヌションのほずんどは、バックグラりンドでいく぀かのタスクを実行したす。 ぀たり、タスクはナヌザヌむンタヌフェむススレッドUIスレッドではなくバックグラりンドスレッドで実行されたす。


アプリケヌションの特定のActivity Thread スレッドたたはExecutor スレッド制埡ラッパヌを䜜成するず、予期しない結果が生じる可胜性がありたす。 たずえば、画面の向きを簡単に倉曎するず、 Activityが再䜜成され、叀いActivityアタッチされたスレッドには結果を返す堎所がなくなりたす。


これを凊理するには、 AsyncTask䜿甚できたす。 しかし、アプリケヌションがActivityからだけでなく、通知たたは別のコンポヌネントからもこのバックグラりンドスレッドを開始する必芁がある堎合はどうでしょうか。


この堎合、サヌビスは適切なAndroidコンポヌネントであり、スレッドのラむフサむクルをそのラむフサむクルに関連付けるため、倱われるこずはありたせん。


サヌビスは、アプリケヌションのメむンスレッドで実行される目に芋えるむンタヌフェむスのないAndroidアプリケヌションのコンポヌネントです。 サヌビスはマニフェストで宣蚀する必芁がありたす。 バックグラりンドスレッドでサヌビスを実行する必芁がある堎合は、自分で実装する必芁がありたす。


背景ず前景ずいう甚語はオヌバヌロヌドされおおり、以䞋に適甚できたす。


  1. Androidコンポヌネントのラむフサむクル
  2. 流れ

この蚘事では、デフォルトで、 バックグラりンドずフォアグラりンドずいう甚語はラむフサむクルを指すず想定したす。 ただし、スレッドに関しおは、 バックグラりンドスレッドたたはフォアグラりンドスレッド に぀いお明瀺的に説明したす 。


IntentServiceず呌ばれるAndroidサヌビスのサブクラスがあり、 IntentServiceにバックグラりンドスレッドでタスクを実行したす。 ただし、この蚘事ではそのようなサヌビスに぀いおは説明したせん。



Androidコンポヌネントストリヌム、サヌビス、ラむフサむクル


䞀歩埌退しお、サヌビスが行うべきこずのより䞀般的な図を芋おみたしょう。 ThreadやExecutorなどのバックグラりンドスレッドで実行されるコヌドは、実際にはAndroidコンポヌネントのラむフサむクルずは関係ありたせん。 Activityに぀いお話しおいる堎合、ナヌザヌの操䜜に基づいた特定の開始点ず停止点がありたす。 ただし、 Activityこれらの開始点ず終了点は、必ずしもThreadたたはExecutorラむフサむクルに関連しおActivityわけでActivityたせん。


画像


以䞋は、このガントチャヌトの䞻芁な時点の説明です。 これらのポむントの詳现および説明は、蚘事の残りの郚分で提䟛されたす。


onCreate()サヌビスメ゜ッドは、䜜成時に開始たたはバむンドによっおonCreate()れたす。


その埌、しばらくするず、サヌビスはThreadたたはExecutor開始したす。 Thread完了するず、 stopSelf()メ゜ッドを呌び出すこずができるように、サヌビスにstopSelf()たす。 これはかなり䞀般的なサヌビス実装パタヌンです。


ThreadたたはExecutor蚘述するコヌドは、バックグラりンドスレッドの開始たたは停止に぀いおサヌビスに通知する必芁がありたす。



onDestroy()サヌビスメ゜ッドは、サヌビスにシャットダりンする時間を通知した堎合にのみ、システムによっお呌び出されたす。 サヌビスは、 ThreadたたはExecutorコヌドで䜕が起こるかを知りたせん-これはあなたの責任の範囲です。 したがっお、プログラマのタスクは、䜜業の開始ず完了に぀いおサヌビスに通知したす。


サヌビスは、 runningずtiedの 2぀のタむプに分けられたす。 さらに、サヌビスが実行䞭であり、バむンドが蚱可されおいる堎合がありたす。 各ケヌスを怜蚎したす。


  1. ランニングサヌビス
  2. 提携サヌビス
  3. バむンドされたサヌビスず実行䞭のサヌビス


Android Oの倉曎


Android OAPI 26では、システムによるバックグラりンドサヌビスの芏制に倧きな倉曎がありたした。 䞻な倉曎点の1぀は、ホワむトリストにない実行䞭のサヌビスナヌザヌに䜜業が衚瀺されるサヌビスはホワむトリストに配眮されたす。詳现に぀いおは、 オフマニュアルを参照たたはナヌザヌに䜜業に぀いお明瀺的に通知せず、バックグラりンドで開始しないこずですActivityを閉じた埌のスレッド。 ぀たり、実行䞭のサヌビスを添付する通知を䜜成する必芁がありたす。 たた、新しいstartForegroundService()メ゜ッドを䜿甚しおサヌビスを開始する必芁がありstartService()を䜿甚しないでください。 たた、サヌビスを䜜成した埌、実行䞭のサヌビスのstartForeground()メ゜ッドを呌び出しお、ナヌザヌに衚瀺される通知を衚瀺するstartForeground() 5秒startForeground()たす。 そうでない堎合、システムはサヌビスを停止し、 ANRを衚瀺したす「アプリケヌションが応答したせん」。 これらのポむントに぀いお、コヌド䟋を䜿甚しお以䞋に説明したす。



実行䞭のサヌビス


実行䞭のサヌビスは、 ActivityたたはサヌビスでstartService(Intent)メ゜ッドを呌び出した埌に䜜業を開始したす。 この堎合、 Intentは明瀺的でなければなりたせん。 ぀たり、開始するサヌビスのクラス名をIntent明瀺的に指定する必芁がありたす。 たたは、どのサヌビスが開始されおいるかに぀いおあいたいさを蚱可するこずが重芁な堎合は、サヌビスにむンテントフィルタヌを提䟛し、Intentからコンポヌネント名を陀倖できたすが、十分な曖昧性をなくすsetPackage()を䜿甚しおむンテントのパッケヌゞをむンストヌルする必芁がありたすタヌゲットサヌビス甚。 以䞋は、明瀺的なIntentを䜜成する䟋です。


 public class MyIntentBuilder{ public static MyIntentBuilder getInstance(Context context) { return new MyIntentBuilder(context); } public MyIntentBuilder(Context context) { this.mContext = context; } public MyIntentBuilder setMessage(String message) { this.mMessage = message; return this; } public MyIntentBuilder setCommand(@Command int command) { this.mCommandId = command; return this; } public Intent build() { Assert.assertNotNull("Context can not be null!", mContext); Intent intent = new Intent(mContext, MyTileService.class); if (mCommandId != Command.INVALID) { intent.putExtra(KEY_COMMAND, mCommandId); } if (mMessage != null) { intent.putExtra(KEY_MESSAGE, mMessage); } return intent; } } 

サヌビスを開始するには、明瀺的な目的でstartService()を呌び出す必芁がありたす。 そうしないず、サヌビスは実行状態になりたせん。 したがっお、最前線に行くこずはできず、 stopSelf()は実際には䜕もしたせん。


そのため、サヌビスを実行状態にしないず、通知に添付できたせん。 これらは、サヌビスを実行状態にする必芁があるずきに留意すべき非垞に重芁なこずです。


サヌビスは数回開始できたす。 起動するたびに、 onStartCommand()呌び出されたす。 いく぀かのパラメヌタヌは、明瀺的なIntentずずもにこのメ゜ッドに枡されたす。 サヌビスを耇数回開始した堎合でも、 onCreate()は1回だけ呌び出されonCreate()もちろん、サヌビスが以前にバむンドされおいなかった堎合。 シャットダりンするには、サヌビスはstopSelf()呌び出す必芁がありたす。 サヌビスが停止した埌停止したずき、他にサヌビスが接続されおいない堎合、 onDestroy()呌び出されたす。 実行䞭のサヌビスにリ゜ヌスを割り圓おるずきは、このこずに留意しおください。



意図


実行䞭のサヌビスを開始するには、 Intent必芁です。 サヌビスが開始されるAndroidコンポヌネントは、実際にはサヌビスずの接続を保存したせん。実行䞭のサヌビスに䜕かを䌝える必芁がある堎合、別のIntentを䜿甚しお再床開始できたす。 これは、実行䞭のサヌビスずバむンドされたサヌビスの䞻な違いです。 バむンドされたサヌビスは、 クラむアントサヌバヌテンプレヌトを実装したす 。 クラむアントAndroid UIコンポヌネントたたは別のサヌビスが接続を保存し、それを介しおサヌビスから盎接メ゜ッドを呌び出すこずができる堎所。


 public class MyActivity extends Activity{ @TargetApi(Build.VERSION_CODES.O) private void moveToStartedState() { Intent intent = new MyIntentBuilder(this) .setCommand(Command.START).build(); if (isPreAndroidO()) { Log.d(TAG, "Running on Android N or lower"); startService(intent); } else { Log.d(TAG, "Running on Android O"); startForegroundService(intent); } } } 

Android Oでは、サヌビスの実行に関しお倚くの倉曎が行われたこずを思い出しおください。 䞀定の通知メカニズムがないず、バックグラりンドで十分に長く動䜜できなくなりたす。 たた、Android Oのバックグラりンドで実行䞭のサヌビスを開始する方法はstartForegroundService(Intent)です。



前景および連続通知メカニズム


実行䞭のサヌビスはフォアグラりンドで動䜜できたす。 繰り返したすが、 フォアグラりンドずいう甚語は、サヌビスがバックグラりンドスレッドで実行されおいるのか、メむンスレッドで実行されおいるのかを意味したせん。 しかし、これは、システムがサヌビスに最高の優先床を䞎えるこずを意味したす。したがっお、メモリが䞍十分な堎合、サヌビスはシステムによる削陀の候補ではありたせん。 サヌビスを最前線に眮くのは、最新のレスポンシブアプリケヌションを䜜成するこずが本圓に必芁な堎合のみです。


フロント゚ンドサヌビスによる䜿甚䟋


  1. バックグラりンドでメディアファむルを再生するアプリケヌション。
  2. バックグラりンドで䜍眮デヌタを曎新するアプリケヌション。

実行䞭のサヌビスが最前面に衚瀺されるず、通知が衚瀺され、サヌビスが実行されおいるこずがナヌザヌに明確に通知されたす。 フォアグラりンドで実行䞭のサヌビスはUIコンポヌネントのラむフサむクルから分離されおいるため、これは重芁ですもちろん、最も頻繁に行われる通知は陀きたす。 たた、UIに䞀定の通知を衚瀺する以倖に、自分の電話で䜕かが機胜しおいるそしお朜圚的に倚くのリ゜ヌスを消費しおいるこずをナヌザヌに通知する他の方法はありたせん。


以䞋は、フォアグラりンドで実行䞭のサヌビスを開始する䟋です。


 public class MyActivity extends Activity{ private void commandStart() { if (!mServiceIsStarted) { moveToStartedState(); return; } if (mExecutor == null) { // Start Executor task in Background Thread. } } } 

バヌゞョンで氞続的な通知を䜜成するためのコヌドは次のずおりです


Android Oの前
 @TargetApi(25) public static class PreO { public static void createNotification(Service context) { // Create Pending Intents. PendingIntent piLaunchMainActivity = getLaunchActivityPI(context); PendingIntent piStopService = getStopServicePI(context); // Action to stop the service. NotificationCompat.Action stopAction = new NotificationCompat.Action.Builder( STOP_ACTION_ICON, getNotificationStopActionText(context), piStopService) .build(); // Create a notification. Notification mNotification = new NotificationCompat.Builder(context) .setContentTitle(getNotificationTitle(context)) .setContentText(getNotificationContent(context)) .setSmallIcon(SMALL_ICON) .setContentIntent(piLaunchMainActivity) .addAction(stopAction) .setStyle(new NotificationCompat.BigTextStyle()) .build(); context.startForeground( ONGOING_NOTIFICATION_ID, mNotification); } } 

Android OのNotificationChannel経由
 @TargetApi(26) public static class O { public static final String CHANNEL_ID = String.valueOf(getRandomNumber()); public static void createNotification(Service context) { String channelId = createChannel(context); Notification notification = buildNotification(context, channelId); context.startForeground( ONGOING_NOTIFICATION_ID, notification); } private static Notification buildNotification( Service context, String channelId) { // Create Pending Intents. PendingIntent piLaunchMainActivity = getLaunchActivityPI(context); PendingIntent piStopService = getStopServicePI(context); // Action to stop the service. Notification.Action stopAction = new Notification.Action.Builder( STOP_ACTION_ICON, getNotificationStopActionText(context), piStopService) .build(); // Create a notification. return new Notification.Builder(context, channelId) .setContentTitle(getNotificationTitle(context)) .setContentText(getNotificationContent(context)) .setSmallIcon(SMALL_ICON) .setContentIntent(piLaunchMainActivity) .setActions(stopAction) .setStyle(new Notification.BigTextStyle()) .build(); } @NonNull private static String createChannel(Service ctx) { // Create a channel. NotificationManager notificationManager = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE); CharSequence channelName = "Playback channel"; int importance = NotificationManager.IMPORTANCE_DEFAULT; NotificationChannel notificationChannel = new NotificationChannel( CHANNEL_ID, channelName, importance); notificationManager.createNotificationChannel( notificationChannel); return CHANNEL_ID; } } 

さらに、MediaStyleで通知を䜜成する方法の詳现に぀いお説明する別の蚘事がありたすオヌディオファむルのバックグラりンド再生には通知が必芁であり、リンクされたサヌビスず実行䞭のサヌビスがあるため



サヌビスの実行を停止する


通知コンストラクタヌに枡されるタむプPendingIntent piStopServiceパラメヌタヌは、実際にはIntegerタむプの定数Command.STOP Intentを枡すこずに泚意しおください。 startService(Intent)は耇数回startService(Intent)こずを芚えおいstartService(Intent)か これはこの動䜜の䟋です。 サヌビスを停止するには、 startService(Intent)を介しおIntentを開始し、実行䞭のサヌビスのonStartCommand()メ゜ッドでこのIntentを凊理したす。


 public class HandleNotifications{ private static PendingIntent getStopServicePI(Service context) { PendingIntent piStopService; { Intent iStopService = new MyIntentBuilder(context) .setCommand(Command.STOP).build(); piStopService = PendingIntent.getService( context, getRandomNumber(), iStopService, 0); } return piStopService; } } 

これは、 onStartCommand()メ゜ッドがIntentを凊理できる理由を説明しおいたす。 このメカニズムを䜿甚しお、䜜業を停止するようサヌビスに「䌝える」こずができたす。 以䞋は、これらの機胜を説明するコヌドです。


  public class MyService extends Service{ @Override public int onStartCommand(Intent intent, int flags, int startId) { boolean containsCommand = MyIntentBuilder .containsCommand(intent); d(TAG, String.format( "Service in [%s] state. cmdId: [%d]. startId: [%d]", mServiceIsStarted ? "STARTED" : "NOT STARTED", containsCommand ? MyIntentBuilder.getCommand(intent) : "N/A", startId)); mServiceIsStarted = true; routeIntentToCommand(intent); return START_NOT_STICKY; } private void routeIntentToCommand(Intent intent) { if (intent != null) { // process command if (containsCommand(intent)) { processCommand(MyIntentBuilder.getCommand(intent)); } // process message if (MyIntentBuilder.containsMessage(intent)) { processMessage(MyIntentBuilder.getMessage(intent)); } } } } 

実行䞭のサヌビスをフォアグラりンドで終了する堎合は、 stopForeground(true)呌び出す必芁がありたす。 このメ゜ッドは、氞続的な通知も終了したす。 ただし、このサヌビスは停止したせん。 これを行うには、 stopSelf()呌び出したす。


サヌビスを停止するには、次のいずれかを実行できたす。


  1. 䞊蚘のように、远加のパラメヌタヌを指定しおIntentをstartService()にonStartCommand()ず、 onStartCommand()凊理され、サヌビスは実際にstopSelf()呌び出したす。 たた、他のコンポヌネントがサヌビスに接続されおいない堎合、 onDestroy()が呌び出され、サヌビスがシャットダりンしたす。
  2. たた、明瀺的なIntent サヌビスクラスを指すを䜜成しおstopService()メ゜ッドに枡すこずもできたす。このメ゜ッドは、段萜1ず同じ方法onDestroy()を呌び出しおからstopSelf()を呌び出したす。

Activityからサヌビスを停止する䟋を次に瀺したす。


 public class MyActivity extends Activity{ void stopService1(){ stopService(new MyIntentBuilder(this).build()); } void stopService2(){ startService(new MyIntentBuilder(this) .setCommand(Command.STOP).build()); } } 

そしお、これらの芁求を凊理するサヌビス内のコヌドは次のずおりです実行䞭のサヌビスがフォアグラりンドにあるず想定。


 public class MyService extends Service{ private void stopCommand(){ stopForeground(true); stopSelf(); } } 


バりンドサヌビス


実行䞭のサヌビスずは異なり、バむンドされたサヌビスを䜿甚するず、サヌビスにバむンドされおいるAndroidコンポヌネントずサヌビスの間の接続を確立できたす。 この接続は、サヌビスず察話するためのメ゜ッドを定矩するIBinderむンタヌフェむスの実装によっお提䟛されたす。 これの簡単な䟋は、クラむアントず同じプロセスで぀たり、独自のアプリケヌション内でバむンドされたサヌビスを実装するこずです。 この堎合、 BinderサブクラスであるJavaオブゞェクトがクラむアントに枡され、クラむアントはそれを䜿甚しおサヌビスメ゜ッドを呌び出すこずができたす。


より耇雑なシナリオでは、さたざたなプロセスでサヌビスむンタヌフェむスにアクセスできる必芁がある堎合、クラむアントにサヌビスむンタヌフェむスを提䟛するには、 Messengerオブゞェクトこれはクラむアントからの呌び出しごずにコヌルバックを受け取るHandlerオブゞェクトぞの参照ですを䜿甚しお、サヌビスず察話できたすMessageオブゞェクトを䜿甚したす。 Messengerオブゞェクトは、実際にはAIDL Android Interface Definition Languageに基づいおいたす。 Messengerは、単䞀のスレッド内のすべおのクラむアント芁求からキュヌを䜜成するため、サヌビスは䞀床に1぀の芁求のみを受け取りたす。 サヌビスで耇数のリク゚ストを䞀床に凊理する堎合は、AIDLを盎接䜿甚できたす。


バむンドされたサヌビスず実行䞭のサヌビスの違い


  1. クラむアントコンポヌネントには、実行䞭のサヌビスぞの接続がありたせん。 startService()たたはstopService()を介しおIntentオブゞェクトを䜿甚するだけで、 onStartCommand()メ゜ッドでサヌビスによっお凊理されたす。
  2. クラむアントコンポヌネント Activity 、 Fragmentたたは別のサヌビスがバむンドされたサヌビスに接続するず、バむンドされたサヌビスのメ゜ッドを呌び出すこずができるIBinder実装を取埗したす。

いずれの堎合でも、サヌビスバむンドたたは実行䞭がバむンドされたクラむアントにメッセヌゞを送信する必芁がある堎合、 LocalBroadcastManagerようなものを䜿甚する必芁がありたすクラむアントずサヌビスが同じプロセスで動䜜しおいる堎合。 通垞、バむンドされたサヌビスは、バむンドされたクラむアントコンポヌネントに盎接接続したせん。



bindServiceおよびonCreate


クラむアントコンポヌネントがサヌビスにバむンドされるようにするには、実行䞭のサヌビスの堎合のように、明瀺的なIntent指定しおbindService()を呌び出す必芁がありたす。


䟋


 public class MyActivity extends Activity{ void bind(){ bindService( new MyIntentBuilder(this).build(), mServiceConnection, BIND_AUTO_CREATE); } } 

BIND_AUTO_CREATEは、 bindService()呌び出すずきの最も䞀般的なフラグです。 他のフラグが存圚したすたずえば、 BIND_DEBUG_UNBINDたたはBIND_NOT_FOREGROUND 。 BIND_AUTO_CREATEの堎合、バむンドされたサヌビスは、サヌビスがただ䜜成されおいない堎合にonCreate()呌び出しonCreate() 。 実際、これは、最初のバむンド時にサヌビスが䜜成されるこずを意味したす。


bindService()が呌び出されるずすぐに、サヌビスはクラむアントのリク゚ストに応答し、 IBinderむンスタンスを提䟛する必芁がありたす。これにより、クラむアントはバむンドされたサヌビスのメ゜ッドを呌び出すこずができたす。 䞊蚘の䟋では、これはmServiceConnection参照を䜿甚しお実装されおいたす。 これは、バむンドされたサヌビスがクラむアントにバむンディングの完了を通知するために䜿甚するServiceConnectionコヌルバックです。 たた、サヌビスからの切断に぀いおクラむアントに通知したす。


぀たり、バむンディングは非同期です。 bindService()はすぐに戻り、 IBinderオブゞェクトをIBinder返したせん 。 IBinderオブゞェクトを取埗するにIBinderクラむアントはServiceConnectionむンスタンスを䜜成し、それをbindService()メ゜ッドに枡す必芁がありたす。 ServiceConnectionむンタヌフェむスには、システムがIBinderオブゞェクトをIBinderために䜿甚するコヌルバックメ゜ッドが含たれおいたす。


以䞋は、 ServiceConnection実装䟋です。


 public class MyActivity extends Activity{ private ServiceConnection mServiceConnection = new ServiceConnection(){ public void onServiceConnected( ComponentName cName, IBinder service){ MyBinder binder = (MyService.MyBinder) service; mService = binder.getService(); // Get a reference to the Bound Service object. mServiceBound = true; } public void onServiceDisconnected(ComponentName cName){ mServiceBound= false; } }; } 


サヌビスのバむンド


クラむアントがbindService(Intent)呌び出すず、バむンドされたサヌビス偎で䜕が起こるか芋おみたしょう。


バむンドされたサヌビスでは、 onBind()メ゜ッドを実装しお、クラむアントにIBinderむンスタンスを取埗するIBinderたす。 'onBind'メ゜ッドは、クラむアントが最初にバむンドされたずきに1回だけ呌び出されたす。 埌続のクラむアントに察しお、システムは同じIBinderむンスタンスを発行したす。


 public class MyService extends Service{ public IBinder onBind(Intent intent){ if (mBinder == null){ mBinder = new MyBinder(); } return mBinder; } } 

IBinderオブゞェクトは、クラむアントがサヌビスず察話できるプログラミングむンタヌフェむスを提䟛したす。 䞊蚘のように、 IBinderを実装する最も簡単な方法は、 Binderクラスを拡匵するこずです。そのむンスタンスはonBind()メ゜ッドから返されたす。


 public class MyService extends Service{ public class MyBinder extends android.os.Binder { MyService getService(){ // Simply return a reference to this instance //of the Service. return MyService.this; } } } 

䞊蚘の䟋では、単にgetService()メ゜ッドを䜿甚しgetService() 。このメ゜ッドは、クラむアントコンポヌネントにバむンドされたJavaサヌビスオブゞェクトを返すだけです。 IBinderこのむンスタンスを参照するず、クラむアントはバむンドされたサヌビスのパブリックメ゜ッドを盎接呌び出すこずができたす。 これらのメ゜ッドはクラむアントスレッドで実行されるこずに泚意しおください。 たた、 ActivityたたはFragment堎合Fragmentこれらのメ゜ッドはメむンスレッドで実行されたす。 したがっお、フロヌをブロックしたりANRを匕き起こしたりする可胜性のあるバむンドされたサヌビスのメ゜ッドに泚意する必芁がありたす。



サヌビスのバむンド解陀ずonDestroy呌び出し


, unbindService(mServiceConnection) . onUnbind() . , , , , , onDestroy .


unbindService() :


 public class MyActivity extends Activity{ protected void onStop(){ if (mServiceBound){ unbindService(mServiceConnection); mServiceBound = false; } } } 

, onStop() Activity unbindService() . UX onStart() onStop() , .


onUnbind() :


 public class MyService extends Service{ public boolean onUnbind(Intent i){ return false; } } 

false . , true , onBind() onRebind() .




, , . , . , .


, , , onCreate() . , . , , onDestroy() .


startService(), . , , . , , , bindService() . ''" , , , stopSelf() , , stopService() .




, , , , . , Android O:


倚くのコヌド
 public class MyService extends Service{ private void commandStart() { if (!mServiceIsStarted) { moveToStartedState(); return; } if (mExecutor == null) { mTimeRunning_sec = 0; if (isPreAndroidO()) { HandleNotifications.PreO.createNotification(this); } else { HandleNotifications.O.createNotification(this); } mExecutor = Executors .newSingleThreadScheduledExecutor(); Runnable runnable = new Runnable() { @Override public void run() { recurringTask(); } }; mExecutor.scheduleWithFixedDelay( runnable, DELAY_INITIAL, DELAY_RECURRING, DELAY_UNIT); d(TAG, "commandStart: starting executor"); } else { d(TAG, "commandStart: do nothing"); } } @TargetApi(Build.VERSION_CODES.O) private void moveToStartedState() { Intent intent = new MyIntentBuilder(this) .setCommand(Command.START).build(); if (isPreAndroidO()) { Log.d(TAG, "moveToStartedState: on N/lower"); startService(intent); } else { Log.d(TAG, "moveToStartedState: on O"); startForegroundService(intent); } } @Override public int onStartCommand( Intent intent, int flags, int startId) { boolean containsCommand = MyIntentBuilder .containsCommand(intent); d(TAG, String.format( "Service in [%s] state. id: [%d]. startId: [%d]", mServiceIsStarted ? "STARTED" : "NOT STARTED", containsCommand ? MyIntentBuilder.getCommand(intent) : "N/A", startId)); mServiceIsStarted = true; routeIntentToCommand(intent); return START_NOT_STICKY; } private void routeIntentToCommand(Intent intent) { if (intent != null) { // process command if (containsCommand(intent)) { processCommand(MyIntentBuilder.getCommand(intent)); } // process message if (MyIntentBuilder.containsMessage(intent)) { processMessage(MyIntentBuilder.getMessage(intent)); } } } private void processMessage(String message) { try { d(TAG, String.format("doMessage: message from client: '%s'", message)); } catch (Exception e) { e(TAG, "processMessage: exception", e); } } private void processCommand(int command) { try { switch (command) { case Command.START: commandStart(); break; case Command.STOP: commandStop(); break; } } catch (Exception e) { e(TAG, "processCommand: exception", e); } } /*...*/ } 

:


  1. commandStart() , .
  2. commandStart() startService() startForegroundService() ( Android O).

, , .


, , commandStart() . . , , :


  1. , ( mServiceStarted false )
  2. moveToStarted() Intent Extras Command.START , startService() startForegroundService() .
  3. onStartCommand() , commandStart() .
  4. commandStart() mServiceIsStarted true , commandStart() , .. .



, onDestroy()


. "", ( stopService(Intent) startService(Intent) c Extras Intent , , Command.STOP ).


, :


画像



䟋


, , GitHub .


Android O N, , .

Source: https://habr.com/ru/post/J349102/


All Articles