
ãã®å³ã§ã¯ãæ°Žæ·±ã®å€ä»£ã®äœæ°ã®ã¹ã±ã«ãã³ãäžéšã®å€§éœåžã®ã¡ãããããã§ã¯ãªããããã¯éåžžã«ãªã¢ã«ãªAndroidã¢ããªã±ãŒã·ã§ã³ã®ç»é¢äžã®é·ç§»ã®ãããã§ãã ããããè€éã§ã¯ãããŸãããå®è£
ã«æåããå°ããªã©ã€ãã©ãªã®åœ¢ã§ãœãªã¥ãŒã·ã§ã³ãèšèšããããšãã§ããŸãããããã«ã€ããŠã¯èšäºã§èª¬æããŸãã
ååã«é¢ãã質åãäºåã«åé¿ããããã«ãç§ã¯æ確ã«ããŸãïŒCiceroneïŒ "chi-che-ro-not" ïŒã¯ã€ã¿ãªã¢èªãèµ·æºãšããå€ãèšèã§ããå€åœäººåãã¬ã€ãããæå³ããŸãã
ç§ãã¡ã®ãããžã§ã¯ãã§ã¯ãããžãã¯ããã£ã¹ãã¬ã€ããåé¢ã§ããããã«ããã¢ãŒããã¯ãã£ã®ã¢ãããŒããå³å®ããããšããŠããŸãã
ç§ã¯ãã®ç¹ã§MVPã奜ãã®ã§ãããã¹ãå
šäœã§ããã¬ãŒã³ã¿ãŒããšããèšèããã䜿ãããŸãããããã§çŽ¹ä»ãããœãªã¥ãŒã·ã§ã³ã¯ãã¢ãŒããã¯ãã£ã®éžæãå¶éãããã®ã§ã¯ãªãããšã«æ³šæããŠãã ããïŒã¯ã©ã·ãã¯ã¢ãããŒãã§ã¯ããããŠãããã§ããCiceroneã¯å©çãäžããŸãïŒïŒã
ããã²ãŒã·ã§ã³ã¯ããžãã¹ããžãã¯ã«è¿ãããããã¬ãŒã³ã¿ãŒã«ç§»è¡ã®è²¬ä»»ãå²ãåœãŠãããšã奜ã¿ãŸãã ããããAndroidã§ã¯ããã¹ãŠãããã»ã©ã¹ã ãŒãºã§ã¯ãããŸãããã¢ã¯ãã£ããã£éã®ç§»è¡ããã©ã°ã¡ã³ãã®åãæ¿ããã³ã³ããå
ã®ãã¥ãŒã®å€æŽ
- ã³ã³ããã¹ãã«äŸåããã«è¡ãããšã¯ã§ããŸãããã³ã³ããã¹ãã¯ããžãã¯å±€ã«è»¢éããããªãããããã©ãããã©ãŒã ã«ãªã³ã¯ããã ãã¹ããè€éã«ãªãã ã¡ã¢ãªãªãŒã¯ã®ãªã¹ã¯ããããŸã ïŒãªã³ã¯ã®ã¯ãªã¢ãå¿ããå ŽåïŒã
- ã³ã³ããã®ã©ã€ããµã€ã¯ã«ãèæ
®ããå¿
èŠããããŸãïŒããšãã°ã java.lang.IllegalStateExceptionïŒ Fragmentsã®onSaveInstanceStateã®åŸã«ãã®ã¢ã¯ã·ã§ã³ãå®è¡ã§ããŸãã ïŒã
ãããã£ãŠãCiceroneã«å®è£
ããããœãªã¥ãŒã·ã§ã³ããããŸããã
æ§é ããå§ãã䟡å€ããããšæããŸãã
æ§é

å³ã«ã¯4ã€ã®ãšã³ãã£ãã£ããããŸãã
- ã³ãã³ãã¯ãããã²ãŒã¿ãŒãå®è¡ããæãåçŽãªããã²ãŒã·ã§ã³ã³ãã³ãã§ãã
- ããã²ãŒã¿ãŒ-ã³ã³ãããŒå
ã®ãç»é¢ã®åãæ¿ããã®çŽæ¥å®è£
ã
- ã«ãŒã¿ãŒã¯ãé«ã¬ãã«ã®ãã¬ãŒã³ã¿ãŒããã²ãŒã·ã§ã³åŒã³åºããã³ãã³ãã»ããã«å€æããã¯ã©ã¹ã§ãã
- CommandBuffer-åŒã³åºãããããã²ãŒã·ã§ã³ã³ãã³ãã®å®å
šæ§ãæ
åœããŸããåŒã³åºãæã«ç§»è¡ããå¯èœæ§ããªãå Žåã
次ã«ãããããã«ã€ããŠè©³ãã説æããŸãã
玹ä»ã³ãã³ã
é·ç§»ãããïŒæåã®ç»åã®ããã«éåžžã«è€éãªãã®ã§ãïŒã¯ã4ã€ã®åºæ¬çãªé·ç§»ã䜿çšããŠå®è£
ã§ããããããçµã¿åãããŠå¿
èŠãªåäœãåŸãããããšã«æ°ä»ããŸããã
é²ã

ForwardïŒString screenKeyãObject transitionDataïŒ -æ°ããç»é¢ã«ç§»è¡ããçŸåšã®ç»é¢ã®ãã§ãŒã³ã«è¿œå ããã³ãã³ãã
screenKey-åç»é¢ã®äžæã®ããŒã
transitionData-æ°ããç»é¢ã«å¿
èŠãªããŒã¿ã
æåRã¯ã«ãŒãç»é¢ã瀺ãããã®æ©èœã¯ããã®ç»é¢ãçµäºãããšãã¢ããªã±ãŒã·ã§ã³ãçµäºããããšã§ãã
æ»ã

æ»ãïŒïŒ -æåŸã®ã¢ã¯ãã£ããªç»é¢ããã§ãŒã³ããåé€ããåã®ç»é¢ã«æ»ãã³ãã³ãã ã«ãŒãç»é¢ã§åŒã³åºããããšãã¢ããªã±ãŒã·ã§ã³ã¯çµäºããããšãæåŸ
ãããŠããŸãã
æ»ã

BackToïŒString screenKeyïŒ -ããŒãæå®ããã ãã§ããã§ãŒã³å
ã®ä»»æã®ç»é¢ã«æ»ãããšãã§ããã³ãã³ãã åãããŒãæã€ãã§ãŒã³ã«2ã€ã®ç»é¢ãããå ŽåãæåŸã®ç»é¢ïŒæããæ£ãããç»é¢ïŒãéžæãããŸãã
æå®ãããç»é¢ãèŠã€ãããªãå ŽåããŸãã¯ããŒãã©ã¡ãŒã¿ã«nullãæž¡ãããå Žåãã«ãŒãç»é¢ãžã®ç§»è¡ãå®è¡ãããããšã«æ³šæããŠãã ããã
å®éã«ã¯ããã®ã³ãã³ãã¯éåžžã«äŸ¿å©ã§ãã ããšãã°ãæ¿èªã®å ŽåïŒ2ã€ã®ç»é¢ã é»è©±-> SMSããããŠèªèšŒãéå§ããããã®ãžã®ã¢ã¯ã»ã¹ã
亀æ

ReplaceïŒString screenKeyãObject transitionDataïŒ -ã¢ã¯ãã£ããªç»é¢ãæ°ããç»é¢ã«çœ®ãæããã³ãã³ãã
誰ããé£ç¶ããŠBackããã³Forwardã³ãã³ããåŒã³åºãããšã§ãã®çµæãéæã§ããããšã«å察ãããããããŸãããããã®åŸãã«ãŒãç»é¢ã§ã¢ããªã±ãŒã·ã§ã³ãçµäºããŸãïŒ
以äžã§ãïŒ å®éã«ãããã®4ã€ã®ããŒã ã¯ã移è¡ãæ§ç¯ããã®ã«ååã§ãã ããããããã²ãŒã·ã§ã³ã«é©çšãããªãå¥ã®ããŒã ããããŸãããå®éã«ã¯éåžžã«åœ¹ç«ã¡ãŸãã
ã·ã¹ãã ã¡ãã»ãŒãž

SystemMessageïŒæååã¡ãã»ãŒãžïŒ -ã·ã¹ãã ã¡ãã»ãŒãžïŒã¢ã©ãŒããããŒã¹ããã¹ããã¯ãªã©ïŒã衚瀺ããã³ãã³ãã
ç»é¢ãçµäºããŠããŠãŒã¶ãŒã«ã¡ãã»ãŒãžã衚瀺ããå¿
èŠãããå ŽåããããŸãã ããšãã°ãè¡ã£ãå€æŽãä¿åãããšããŸãã ããããç§ãã¡ãæ»ãã¹ã¯ãªãŒã³ã¯ãä»ã®èª°ãã®ããžãã¯ãç¥ãå¿
èŠããªãã®ã§ããã®ãããªã¡ãã»ãŒãžã®è¡šç€ºãå¥ã®ã³ãã³ãã«å
¥ããŸãã ãšãŠã䟿å©ã§ãïŒ
ãã¹ãŠã®ã³ãã³ãã«ã¯ãã³ãã³ãããŒã«ãŒã€ã³ã¿ãŒãã§ã€ã¹ãä»ããŠããŸãã äœããã®çç±ã§æ°ããããŒã ãå¿
èŠãªå Žåã¯ãããŒã ãäœæããã ãã§ãå¶éã¯ãããŸããïŒ
ããã²ãŒã¿ãŒ
ããŒã èªäœã¯åãæ¿ãç»é¢ãå®è£
ããããããã®ç§»è¡ã«ã€ããŠã®ã¿èª¬æããŸãã Navigatorãå®è£
ãæ
åœããŸãã
public interface Navigator { void applyCommand(Command command); }
ã¿ã¹ã¯ã«å¿ããŠãNavigatorã¯ããŸããŸãªæ¹æ³ã§å®è£
ãããŸãããåžžã«åãæ¿ãå¯èœãªç»é¢ã®ã³ã³ãããé
眮ãããå Žæã«ãªããŸãã
- ãã©ã°ã¡ã³ããåãæ¿ããã¢ã¯ãã£ããã£ã
- ãã¹ããããïŒåïŒãã©ã°ã¡ã³ããåãæ¿ãããã©ã°ã¡ã³ãå
ã
- ...ããªãã®ãªãã·ã§ã³ã
倧éšåã®Androidã¢ããªã±ãŒã·ã§ã³ã§ã¯ãããã²ãŒã·ã§ã³ã¯åãã¿ã€ãã®ã³ãŒããèšè¿°ããªãããã«ã¢ã¯ãã£ããã£å
ã®ãã©ã°ã¡ã³ãã®åãæ¿ãã«äŸåããŠãããããã©ã€ãã©ãªã«ã¯ãæ瀺ãããã³ãã³ããå®è£
ããæ¢è£œã®FragmentNavigatorïŒããã³SupportFragmentsã®SupportFragmentNavigatorïŒãæ¢ã«ãããŸãã
ååãªïŒ
1ïŒã³ã³ããIDãšFragmentManagerãã³ã³ã¹ãã©ã¯ã¿ã«æž¡ããŸãã
2ïŒã¢ããªã±ãŒã·ã§ã³ãçµäºããã·ã¹ãã ã¡ãã»ãŒãžã衚瀺ããããã®ã¡ãœãããå®è£
ããŸãã
3ïŒscreenKeyã«ãããã©ã°ã¡ã³ãã®äœæãå®è£
ããŸãã
ãã詳现ãªäŸã«ã€ããŠã¯ããµã³ãã«ã¢ããªã±ãŒã·ã§ã³ãã芧ã«ãªãããšããå§ãããŸãã
ã¢ããªã±ãŒã·ã§ã³ã«ããã²ãŒã¿ã1ã€ããå¿
èŠã¯ãããŸããã äŸïŒã¡ãªã¿ã«å®éã«ãïŒïŒã¢ã¯ãã£ããã£ã«ã¯BottomBarããããããã¯åžžã«ãŠãŒã¶ãŒãå©çšã§ããŸãã ãã ããåã¿ãã«ã¯ç¬èªã®ããã²ãŒã·ã§ã³ããããBottomBarã§ã¿ããåãæ¿ãããšãã«ä¿åãããŸãã
ããã¯ãã¿ããåãæ¿ããActivityå
ã®åäžã®ããã²ãŒã¿ãŒãšãåFragmentã¿ãå
ã®ããŒã«ã«ããã²ãŒã¿ãŒã«ãã£ãŠè§£æ±ºãããŸãã
ãããã£ãŠãåã
ã®ãã¬ãŒã³ã¿ãŒã¯ãèªåãããå ŽæïŒã¿ãã®ãã§ãŒã³å
ãŸãã¯å¥ã®ã¢ã¯ãã£ããã£å
ïŒã«ææãããŸããã 圌ã«æ£ããã«ãŒã¿ãŒãæäŸããã ãã§ååã§ãã 1ã€ã®ã«ãŒã¿ãŒã¯ãåžžã«1ã€ã®ããã²ãŒã¿ãŒã«ã®ã¿é¢é£ä»ããããŸãã ããã«ã€ããŠããå°ãã
ã«ãŒã¿ãŒ
åè¿°ã®ããã«ã ã³ãã³ããçµã¿åãã㊠ãä»»æã®é·ç§»ãå®è£
ã§ããŸãã ãããã«ãŒã¿ãŒã®æ©èœã§ãã
ããšãã°ããã¬ãŒã³ã¿ãŒã«äœããã®ã€ãã³ãã®ã¿ã¹ã¯ãããå ŽåïŒ
1ïŒãã§ãŒã³å
šäœãã«ãŒãç»é¢ã«æããŸãã
2ïŒã«ãŒãç»é¢ãæ°ãããã®ã«çœ®ãæããŸãã
3ïŒããã§ãã·ã¹ãã ã¡ãã»ãŒãžã衚瀺ããŸãã
ãã®åŸãRouteBufferã«ã¡ãœãããè¿œå ãããå®è¡ã®ããã«3ã€ã®ã³ãã³ãã®ã·ãŒã±ã³ã¹ãCommandBufferã«æž¡ãããŸãã
public void navigateToNewRootWithMessage(String screenKey, Object data, String message) { executeCommand(new BackTo(null)); executeCommand(new Replace(screenKey, data)); executeCommand(new SystemMessage(screenKey, data)); }
ãã¬ãŒã³ã¿ãŒèªèº«ããããã®ã¡ãœãããåŒã³åºããå Žåãæåã®BackToïŒïŒã³ãã³ãã®åŸãããã¯ç Žæ£ããïŒæ£ç¢ºã«ã¯ããã§ã¯ãããŸããããæ¬è³ªãäŒããŸãïŒãäœæ¥ãæ£ããå®äºããŸããã§ããã
ã©ã€ãã©ãªã«ã¯æ¢è£œã®ã«ãŒã¿ãŒããããããã©ã«ãã§äœ¿çšãããæãå¿
èŠãªé·ç§»ããããŸãããããã²ãŒã¿ãŒãšåæ§ã«ãç¬èªã®å®è£
ã®äœæãçŠæ¢ãããã®ã¯ãããŸããã
navigateToïŒïŒ -æ°ããç»é¢ã«ç§»è¡ããŸãã
newScreenChainïŒïŒ -ãã§ãŒã³ãã«ãŒãç»é¢ã«ãªã»ããããæ°ããç»é¢ãéããŸãã
newRootScreenïŒïŒ -ãã§ãŒã³ããªã»ããããã«ãŒãç»é¢ã眮ãæããŸãã
replaceScreenïŒïŒ -çŸåšã®ç»é¢ã眮ãæããŸãã
backToïŒïŒ -ãã§ãŒã³å
ã®ä»»æã®ç»é¢ã«æ»ããŸãã
exitïŒïŒ -ç»é¢ãçµäºããŸãã
exitWithMessageïŒïŒ -ç»é¢ãçµäºããŠã¡ãã»ãŒãžã衚瀺ããŸãã
showSystemMessageïŒïŒ -ã·ã¹ãã ã¡ãã»ãŒãžã衚瀺ããŸãã
CommandBuffer
CommandBuffer-Navigatorã«ããã²ãŒã·ã§ã³ã³ãã³ããé
ä¿¡ãã圹å²ãæ
ãã¯ã©ã¹ã ããã²ãŒã¿ãŒã€ã³ã¹ã¿ã³ã¹ãžã®åç
§ãCommandBufferã«æ ŒçŽãããã®ã¯è«ççã§ãã NavigatorHolderã€ã³ã¿ãŒãã§ãŒã¹ãä»ããŠããã«å°éããŸãã
public interface NavigatorHolder { void setNavigator(Navigator navigator); void removeNavigator(); }
ãŸããã³ãã³ããCommandBufferã§åä¿¡ãããçŸåšããã²ãŒã¿ã«å«ãŸããŠããªãå Žåããããã¯ãã¥ãŒã«ä¿åãããæ°ããããã²ãŒã¿ãã€ã³ã¹ããŒã«ããããšããã«å®è¡ãããŸãã CommandBufferã®ãããã§ã圌ã¯ã©ã€ããµã€ã¯ã«ã®ãã¹ãŠã®åé¡ã解決ããããšãã§ããŸããã
ã¢ã¯ãã£ããã£ã®å
·äœäŸïŒ
@Override protected void onResume() { super.onResume(); SampleApplication.INSTANCE.getNavigatorHolder().setNavigator(navigator); } @Override protected void onPause() { SampleApplication.INSTANCE.getNavigatorHolder().removeNavigator(); super.onPause(); }
ãªãæ£ç¢ºã«onResumeãšonPauseãªã®ãïŒ ãã©ã°ã¡ã³ãã®å®å
šãªãã©ã³ã¶ã¯ã·ã§ã³ããã³ã·ã¹ãã ã¡ãã»ãŒãžã®ã¢ã©ãŒããšããŠã®è¡šç€ºã
çè«ããå®è·µãžã ã·ã»ãã³ã®äœ¿çšæ¹æ³
MainActivityã®ãã©ã°ã¡ã³ãã«ããã²ãŒã·ã§ã³ãå®è£
ãããšããŸãã
build.gradleã«äŸåé¢ä¿ãè¿œå ããŸã
repositories { maven { url 'https://dl.bintray.com/terrakok/terramaven/' } } dependencies { //Cicerone compile 'ru.terrakok.cicerone:cicerone:1.0' }
SampleApplicationã¯ã©ã¹ã§ãå®æããã«ãŒã¿ãŒãåæåããŸã
public class SampleApplication extends Application { public static SampleApplication INSTANCE; private Cicerone<Router> cicerone; @Override public void onCreate() { super.onCreate(); INSTANCE = this; cicerone = Cicerone.create(); } public NavigatorHolder getNavigatorHolder() { return cicerone.getNavigatorHolder(); } public Router getRouter() { return cicerone.getRouter(); } }
MainActivityã§ãããã²ãŒã¿ãŒãäœæããŸãã
private Navigator navigator = new SupportFragmentNavigator(getSupportFragmentManager(), R.id.main_container) { @Override protected Fragment createFragment(String screenKey, Object data) { switch(screenKey) { case LIST_SCREEN: return ListFragment.getNewInstance(data); case DETAILS_SCREEN: return DetailsFragment.getNewInstance(data); default: throw new RuntimeException(âUnknown screen key!â); } } @Override protected void showSystemMessage(String message) { Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show(); } @Override protected void exit() { finish(); } }; @Override protected void onResume() { super.onResume(); SampleApplication.INSTANCE.getNavigatorHolder().setNavigator(navigator); } @Override protected void onPause() { super.onPause(); SampleApplication.INSTANCE.getNavigatorHolder().removeNavigator(); }
ããã§ãã¢ããªã±ãŒã·ã§ã³å
ã®ã©ãããã§ãïŒçæ³çã«ã¯ãã¬ãŒã³ã¿ãŒããïŒãã«ãŒã¿ãŒã®ã¡ãœãããåŒã³åºãããšãã§ããŸãã
SampleApplication.INSTANCE.getRouter().backTo(...);
ç¹æ®ãªã±ãŒã¹ãšãã®è§£æ±ºç
åäžã®ã¢ã¯ãã£ããã£ïŒ
ããïŒ ãã ããã¢ã¯ãã£ããã£ã¯ç»é¢ãšããŠã§ã¯ãªããã³ã³ãããšããŠã®ã¿èæ
®ããŸãã åç
§ïŒã«ãŒã¿ãŒã¯Applicationã¯ã©ã¹ã§äœæãããŠãããããããã¢ã¯ãã£ããã£ããå¥ã®ã¢ã¯ãã£ããã£ã«åãæ¿ãããšãã¢ã¯ãã£ããªããã²ãŒã¿ãåã«å€æŽããããããã¢ããªã±ãŒã·ã§ã³ãç¬ç«ããã¢ã¯ãã£ããã£ã«åå²ããããšã¯å¯èœã§ãã ãã¡ããããã®å Žåãç»é¢ã®ãã§ãŒã³ã¯å¥ã
ã®ã¢ã¯ãã£ããã£ã«çµã³ä»ããããBackToïŒïŒã³ãã³ãã¯1ã€ã®ã¢ã¯ãã£ããã£ã®ã³ã³ããã¹ãã§ã®ã¿æ©èœããããšãç解ããå¿
èŠããããŸãã
ãã¹ããããããã²ãŒã·ã§ã³
äžèšã®äŸãæããŸããããããäžåºŠç¹°ãè¿ããŸãã
ã¿ãä»ãã®ã¢ã¯ãã£ããã£ããããŸãã ã¿ã¹ã¯ã¯ãã¿ããå€æŽããããšãã«æ®ãåã¿ãå
ã®ç»é¢ã®ç¬ç«ãããã§ãŒã³ãæã€ããšã§ãã
ããã¯ãã°ããŒãã«ãšããŒã«ã«ã®2çš®é¡ã®ããã²ãŒã·ã§ã³ã«ãã£ãŠè§£æ±ºãããŸãã
GlobalRouterã¯ãActivityããã²ãŒã¿ãŒã«é¢é£ä»ããããã¢ããªã±ãŒã·ã§ã³ã«ãŒã¿ãŒã§ãã
ã¿ãã®ã¯ãªãã¯ãåŠçãããã¬ãŒã³ã¿ãŒã¯ãGlobalRouterããã³ãã³ããåŒã³åºããŸãã
LocalRouter-åãã©ã°ã¡ã³ãã³ã³ããå
ã®ã«ãŒã¿ãŒã LocalRouterã®ããã²ãŒã¿ãŒã¯ããã©ã°ã¡ã³ãã³ã³ãããŒèªäœãå®è£
ããŸãã
ã¿ãå
ã®ããŒã«ã«ãã§ãŒã³ã«é¢é£ãããã¬ãŒã³ã¿ãŒã¯ãããã²ãŒã·ã§ã³ã®ããã«LocalRouterãååŸããŸãã
æ¥ç¶ã¯ã©ãã§ããïŒ ãã©ã°ã¡ã³ãã³ã³ãããŒã¯ã°ããŒãã«ããã²ãŒã¿ãŒã«ã¢ã¯ã»ã¹ã§ããŸãïŒ ã¿ãå
ã®ããŒã«ã«ãã§ãŒã³ãçµäºããBackïŒïŒã³ãã³ããåŒã³åºãããç¬éã«ãFragmentã¯ãããã°ããŒãã«ããã²ãŒã¿ãŒã«æž¡ããŸãã
ãã³ãïŒDagger 2ã䜿çšããŠã³ã³ããŒãã³ãéã®äŸåé¢ä¿ãæ§æãããã®CustomScopesã䜿çšããŠã©ã€ããµã€ã¯ã«ã管çããŸãã
æ»ãã·ã¹ãã ãã¿ã³ã¯ã©ãã§ããïŒ
ãã®åé¡ã¯ãã©ã€ãã©ãªã§ã¯ç¹ã«å¯ŸåŠãããŠããŸããã [æ»ã]ãã¿ã³ãæŒãããšã¯ããŠãŒã¶ãŒã®æäœãšããŠç解ãããåã«ã€ãã³ããšããŠãã¬ãŒã³ã¿ãŒã«éä¿¡ãããå¿
èŠããããŸãã
ãããããããŒãŸãã¯ã³ã³ãã¯ã¿ãŒã¯ãããŸããïŒ
ä»ã®ãœãªã¥ãŒã·ã§ã³ãæ€èšããŸããããäž»ãªã¿ã¹ã¯ã®1ã€ã¯æãæšæºçãªã¢ãããŒãã䜿çšããFragmentManagerãšBackStackã§å¥ã®ãã¬ãŒã ã¯ãŒã¯ãäœæããããšã§ã¯ãªãã£ããããããããæŸæ£ããŸããã
第äžã«ãæ°ããéçºè
ããµãŒãããŒãã£ã®ãã¬ãŒã ã¯ãŒã¯ãå匷ããå¿
èŠãªãããããžã§ã¯ãã«ãã°ããæ¥ç¶ã§ããããã«ããŸãã
第äºã«ãè€éãªãµãŒãããŒãã£ã®ãœãªã¥ãŒã·ã§ã³ã«å®å
šã«äŸåããå¿
èŠããªãããããµããŒããå°é£ã§ãã
ãŸãšã
Ciceroneã©ã€ãã©ãªïŒ
- ãã©ã°ã¡ã³ãã«çµã³ä»ããããŠããªã;
- ãã¬ãŒã ã¯ãŒã¯ã§ã¯ãããŸããã
- çãé話ãæäŸããŸãã
- ç°¡åã«æ¡åŒµã§ããŸãã
- ãã¹ãã«é©åã
- ã©ã€ããµã€ã¯ã«ããç¬ç«ããŠããŸãïŒ
Github
Ciceroneã¯ãAndroidã¢ããªã®ããã²ãŒã·ã§ã³ãç°¡åã«ãã軜éã©ã€ãã©ãªã§ãã
