Nazmul Idrisã®èšäºãDeep Dive into Android Servicesãã®ç¿»èš³ã èè
ã®å
ã®ååãæ®ããŸããããããã¯ã没å
¥ãã§ã¯ãªããç¥äººãã§ããå¯èœæ§ãé«ãã§ãã ãã®ããã¹ãã¯ãåå¿è
ã®éçºè
ã«åœ¹ç«ã€ãšæããŸãã èšäºã¯å®å
šã«è£å®ããŸãã AndroidãµãŒãã¹ã®ããã¥ã¡ã³ã ã ãã®èšäºã§ã¯ãå®è¡äžã®ãµãŒãã¹ããã³ãã€ã³ãããããµãŒãã¹ãšã®å¯Ÿè©±ã®æ©èœã«ã€ããŠèª¬æããŸãã èšäºã®ãã©ã¹ã¯ãAndroid Oã§ãµãŒãã¹ãæäœããéã®å€æŽãèæ
®ã«å
¥ããŠããããšã§ããæ確ã«ããããã«ããªãªãžãã«ãšæ¯èŒããŠå°ããªå€æŽãè¿œå ãããŠããŸãã
ã¯ããã«
ææ°ã®Androidã¢ããªã±ãŒã·ã§ã³ã®ã»ãšãã©ã¯ãããã¯ã°ã©ãŠã³ãã§ããã€ãã®ã¿ã¹ã¯ãå®è¡ããŸãã ã€ãŸããã¿ã¹ã¯ã¯ãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ã€ã¹ã¹ã¬ããïŒUIã¹ã¬ããïŒã§ã¯ãªãããã¯ã°ã©ãŠã³ãã¹ã¬ããã§å®è¡ãããŸãã
ã¢ããªã±ãŒã·ã§ã³ã®ç¹å®ã®Activity
Thread
ïŒã¹ã¬ããïŒãŸãã¯Executor
ïŒã¹ã¬ããå¶åŸ¡ã©ãããŒïŒãäœæãããšãäºæããªãçµæãçããå¯èœæ§ããããŸãã ããšãã°ãç»é¢ã®åããç°¡åã«å€æŽãããšã Activity
ãåäœæãããå€ãActivity
ã¢ã¿ãããããã¹ã¬ããã«ã¯çµæãè¿ãå ŽæããªããªããŸãã
ãããåŠçããã«ã¯ã AsyncTask
䜿çšã§ããŸãã ããããã¢ããªã±ãŒã·ã§ã³ãActivity
ããã ãã§ãªããéç¥ãŸãã¯å¥ã®ã³ã³ããŒãã³ãããããã®ããã¯ã°ã©ãŠã³ãã¹ã¬ãããéå§ããå¿
èŠãããå Žåã¯ã©ãã§ããããã
ãã®å ŽåããµãŒãã¹ã¯é©åãªAndroidã³ã³ããŒãã³ãã§ãããã¹ã¬ããã®ã©ã€ããµã€ã¯ã«ããã®ã©ã€ããµã€ã¯ã«ã«é¢é£ä»ããããã倱ãããããšã¯ãããŸããã
ãµãŒãã¹ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ã¡ã€ã³ã¹ã¬ããã§å®è¡ãããç®ã«èŠããã€ã³ã¿ãŒãã§ã€ã¹ã®ãªãAndroidã¢ããªã±ãŒã·ã§ã³ã®ã³ã³ããŒãã³ãã§ãã ãµãŒãã¹ã¯ãããã§ã¹ãã§å®£èšããå¿
èŠããããŸãã ããã¯ã°ã©ãŠã³ãã¹ã¬ããã§ãµãŒãã¹ãå®è¡ããå¿
èŠãããå Žåã¯ãèªåã§å®è£
ããå¿
èŠããããŸãã
èæ¯ãšåæ¯ãšããçšèªã¯ãªãŒããŒããŒããããŠããã以äžã«é©çšã§ããŸãã
- Androidã³ã³ããŒãã³ãã®ã©ã€ããµã€ã¯ã«
- æµã
ãã®èšäºã§ã¯ãããã©ã«ãã§ã ããã¯ã°ã©ãŠã³ããšãã©ã¢ã°ã©ãŠã³ããšããçšèªã¯ã©ã€ããµã€ã¯ã«ãæããšæ³å®ããŸãã ãã ããã¹ã¬ããã«é¢ããŠã¯ã ããã¯ã°ã©ãŠã³ãã¹ã¬ãããŸãã¯ãã©ã¢ã°ã©ãŠã³ãã¹ã¬ãã ã«ã€ããŠæ瀺çã«èª¬æããŸã ã
IntentService
ãšåŒã°ããAndroidãµãŒãã¹ã®ãµãã¯ã©ã¹ãããã IntentService
ã«ããã¯ã°ã©ãŠã³ãã¹ã¬ããã§ã¿ã¹ã¯ãå®è¡ããŸãã ãã ãããã®èšäºã§ã¯ãã®ãããªãµãŒãã¹ã«ã€ããŠã¯èª¬æããŸããã
Androidã³ã³ããŒãã³ãã¹ããªãŒã ããµãŒãã¹ãã©ã€ããµã€ã¯ã«
äžæ©åŸéããŠããµãŒãã¹ãè¡ãã¹ãããšã®ããäžè¬çãªå³ãèŠãŠã¿ãŸãããã Thread
ãExecutor
ãªã©ã®ããã¯ã°ã©ãŠã³ãã¹ã¬ããã§å®è¡ãããã³ãŒãã¯ãå®éã«ã¯Androidã³ã³ããŒãã³ãã®ã©ã€ããµã€ã¯ã«ãšã¯é¢ä¿ãããŸããã Activity
ã«ã€ããŠè©±ããŠããå ŽåããŠãŒã¶ãŒã®æäœã«åºã¥ããç¹å®ã®éå§ç¹ãšåæ¢ç¹ããããŸãã ãã ãã Activity
ãããã®éå§ç¹ãšçµäºç¹ã¯ãå¿
ãããThread
ãŸãã¯Executor
ã©ã€ããµã€ã¯ã«ã«é¢é£ããŠActivity
ããã§Activity
ãŸããã
以äžã¯ããã®ã¬ã³ããã£ãŒãã®äž»èŠãªæç¹ã®èª¬æã§ãã ãããã®ãã€ã³ãã®è©³çŽ°ïŒããã³èª¬æïŒã¯ãèšäºã®æ®ãã®éšåã§æäŸãããŸãã
onCreate()
ãµãŒãã¹ã¡ãœããã¯ãäœææã«ïŒéå§ãŸãã¯ãã€ã³ãã«ãã£ãŠonCreate()
ããŸãã
ãã®åŸããã°ãããããšããµãŒãã¹ã¯Thread
ãŸãã¯Executor
éå§ããŸãã Thread
å®äºãããšã stopSelf()
ã¡ãœãããåŒã³åºãããšãã§ããããã«ããµãŒãã¹ã«stopSelf()
ãŸãã ããã¯ããªãäžè¬çãªãµãŒãã¹å®è£
ãã¿ãŒã³ã§ãã
Thread
ãŸãã¯Executor
èšè¿°ããã³ãŒãã¯ãããã¯ã°ã©ãŠã³ãã¹ã¬ããã®éå§ãŸãã¯åæ¢ã«ã€ããŠãµãŒãã¹ã«éç¥ããå¿
èŠããããŸãã
- ã¹ã¬ãããéå§ããããšã
startService()
åŒã³åºããŠãµãŒãã¹ã®åæç¶æ
ãèšå®ããå¿
èŠãããstartService()
- ã¹ã¬ãããçµäºãããããµãŒãã¹ã§
stopSelf()
ãåŒã³åºãå¿
èŠããããŸãã
onDestroy()
ãµãŒãã¹ã¡ãœããã¯ããµãŒãã¹ã«ã·ã£ããããŠã³ããæéãéç¥ããå Žåã«ã®ã¿ãã·ã¹ãã ã«ãã£ãŠåŒã³åºãããŸãã ãµãŒãã¹ã¯ã Thread
ãŸãã¯Executor
ã³ãŒãã§äœãèµ·ããããç¥ããŸãã-ããã¯ããªãã®è²¬ä»»ã®ç¯å²ã§ãã ãããã£ãŠãããã°ã©ãã®ã¿ã¹ã¯ã¯ãäœæ¥ã®éå§ãšå®äºã«ã€ããŠãµãŒãã¹ã«éç¥ããŸãã
ãµãŒãã¹ã¯ã runningãštiedã® 2ã€ã®ã¿ã€ãã«åããããŸãã ããã«ããµãŒãã¹ãå®è¡äžã§ããããã€ã³ããèš±å¯ãããŠããå ŽåããããŸãã åã±ãŒã¹ãæ€èšããŸãã
- ã©ã³ãã³ã°ãµãŒãã¹
- ææºãµãŒãã¹
- ãã€ã³ãããããµãŒãã¹ãšå®è¡äžã®ãµãŒãã¹
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)
ã§ãã
åæ¯ããã³é£ç¶éç¥ã¡ã«ããºã
å®è¡äžã®ãµãŒãã¹ã¯ãã©ã¢ã°ã©ãŠã³ãã§åäœã§ããŸãã ç¹°ãè¿ããŸããã ãã©ã¢ã°ã©ãŠã³ããšããçšèªã¯ããµãŒãã¹ãããã¯ã°ã©ãŠã³ãã¹ã¬ããã§å®è¡ãããŠããã®ããã¡ã€ã³ã¹ã¬ããã§å®è¡ãããŠããã®ããæå³ããŸããã ããããããã¯ãã·ã¹ãã ããµãŒãã¹ã«æé«ã®åªå
床ãäžããããšãæå³ããŸãããããã£ãŠãã¡ã¢ãªãäžååãªå ŽåããµãŒãã¹ã¯ã·ã¹ãã ã«ããåé€ã®åè£ã§ã¯ãããŸããã ãµãŒãã¹ãæåç·ã«çœ®ãã®ã¯ãææ°ã®ã¬ã¹ãã³ã·ãã¢ããªã±ãŒã·ã§ã³ãäœæããããšãæ¬åœã«å¿
èŠãªå Žåã®ã¿ã§ãã
ããã³ããšã³ããµãŒãã¹ã«ãã䜿çšäŸïŒ
- ããã¯ã°ã©ãŠã³ãã§ã¡ãã£ã¢ãã¡ã€ã«ãåçããã¢ããªã±ãŒã·ã§ã³ã
- ããã¯ã°ã©ãŠã³ãã§äœçœ®ããŒã¿ãæŽæ°ããã¢ããªã±ãŒã·ã§ã³ã
å®è¡äžã®ãµãŒãã¹ãæåé¢ã«è¡šç€ºããããšãéç¥ã衚瀺ããããµãŒãã¹ãå®è¡ãããŠããããšããŠãŒã¶ãŒã«æ確ã«éç¥ãããŸãã ãã©ã¢ã°ã©ãŠã³ãã§å®è¡äžã®ãµãŒãã¹ã¯UIã³ã³ããŒãã³ãã®ã©ã€ããµã€ã¯ã«ããåé¢ãããŠãããããããã¯éèŠã§ãïŒãã¡ãããæãé »ç¹ã«è¡ãããéç¥ã¯é€ããŸãïŒã ãŸããUIã«äžå®ã®éç¥ã衚瀺ãã以å€ã«ãèªåã®é»è©±ã§äœããæ©èœããŠããïŒãããŠæœåšçã«å€ãã®ãªãœãŒã¹ãæ¶è²»ããŠããïŒããšããŠãŒã¶ãŒã«éç¥ããä»ã®æ¹æ³ã¯ãããŸããã
以äžã¯ããã©ã¢ã°ã©ãŠã³ãã§å®è¡äžã®ãµãŒãã¹ãéå§ããäŸã§ãã
public class MyActivity extends Activity{ private void commandStart() { if (!mServiceIsStarted) { moveToStartedState(); return; } if (mExecutor == null) {
ããŒãžã§ã³ã§æ°žç¶çãªéç¥ãäœæããããã®ã³ãŒãã¯æ¬¡ã®ãšããã§ã
Android Oã®å @TargetApi(25) public static class PreO { public static void createNotification(Service context) {
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) {
ããã«ã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) {
å®è¡äžã®ãµãŒãã¹ããã©ã¢ã°ã©ãŠã³ãã§çµäºããå Žåã¯ã stopForeground(true)
åŒã³åºãå¿
èŠããããŸãã ãã®ã¡ãœããã¯ãæ°žç¶çãªéç¥ãçµäºããŸãã ãã ãããã®ãµãŒãã¹ã¯åæ¢ããŸããã ãããè¡ãã«ã¯ã stopSelf()
åŒã³åºããŸãã
ãµãŒãã¹ãåæ¢ããã«ã¯ã次ã®ãããããå®è¡ã§ããŸãã
- äžèšã®ããã«ãè¿œå ã®ãã©ã¡ãŒã¿ãŒãæå®ããŠ
Intent
ãstartService()
ã«onStartCommand()
ãšã onStartCommand()
åŠçããããµãŒãã¹ã¯å®éã«stopSelf()
åŒã³åºããŸãã ãŸããä»ã®ã³ã³ããŒãã³ãããµãŒãã¹ã«æ¥ç¶ãããŠããªãå Žåã onDestroy()
ãåŒã³åºããããµãŒãã¹ãã·ã£ããããŠã³ããŸãã - ãŸããæ瀺çãª
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ãçŽæ¥äœ¿çšã§ããŸãã
ãã€ã³ãããããµãŒãã¹ãšå®è¡äžã®ãµãŒãã¹ã®éãïŒ
- ã¯ã©ã€ã¢ã³ãã³ã³ããŒãã³ãã«ã¯ãå®è¡äžã®ãµãŒãã¹ãžã®æ¥ç¶ããããŸããã
startService()
ãŸãã¯stopService()
ãä»ããŠIntent
ãªããžã§ã¯ãã䜿çšããã ãã§ã onStartCommand()
ã¡ãœããã§ãµãŒãã¹ã«ãã£ãŠåŠçãããŸãã - ã¯ã©ã€ã¢ã³ãã³ã³ããŒãã³ãïŒ
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();
ãµãŒãã¹ã®ãã€ã³ã
ã¯ã©ã€ã¢ã³ãã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(){
äžèšã®äŸã§ã¯ãåã«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) {
:
commandStart()
, .commandStart()
startService()
startForegroundService()
( Android O).
, , .
, , commandStart()
. . , , :
- , (
mServiceStarted
false
) moveToStarted()
Intent
Extras Command.START
, startService()
startForegroundService()
.onStartCommand()
, commandStart()
.commandStart()
mServiceIsStarted
true
, commandStart()
, .. .
, onDestroy()
. "", ( stopService(Intent)
startService(Intent)
c Extras Intent
, , Command.STOP
).
, :
äŸ
, , GitHub .
Android O N, , .