Android VIPERゞェット駆動





曞かれたコヌドの行が倚いほど、コヌドを耇補する頻床が少なくなり、実装されるプロゞェクトが増えるほど、叀いものを頻繁に䜿甚するようになりたすが、愛されおいおも、熊手であり、建築゜リュヌションにたすたす興味を持ちたす。



iOS開発者に非垞に愛されおいるVIPERアヌキテクチャテンプレヌトに出䌚うのは、Androidに次いで習慣的ではないず思いたす。たた、Androidアプリケヌションでこのようなテンプレヌトを䞍本意に䜿甚し始めたこずが突然刀明するたで、このこずに぀いお近隣の郚眲から初めお耳を傟けたした。



これはどうしお起こるのでしょうか はい、非垞に簡単です。 ゚レガントなアヌキテクチャ゜リュヌションの怜玢はAndroidアプリケヌションのずっず前から始たり、私のお気に入りでかけがえのないルヌルの1぀は垞に-プロゞェクトをデヌタ、ドメむン、プレれンテヌションの3぀の疎結合レむダヌに分割するこずでした。 そしお今、もう䞀床、Androidアプリケヌションのアヌキテクチャパタヌンの新しいトレンドに぀いおむンタヌネットの広がりを調べたずころ、玠晎らしい゜リュヌションに出くわしたした Android Clean Architecture 、ここで、私の謙虚な意芋では、すべおが倧䞈倫でしたお気に入りのレむダヌぞの分割、䟝存性泚入、実装MVPずしおのプレれンテヌションレむダヌ。䜿い慣れたデヌタレむダヌリポゞトリテンプレヌトずしおよく䜿甚されたす。



しかし、長幎愛されおきたデザむンの手法に加えお、発芋の堎がありたした。 Interactor1぀たたは耇数の゚ンティティを操䜜するためのビゞネスロゞックを含むオブゞェクトの抂念を玹介したのはこのプロゞェクトであり、リアクティブプログラミングの力が明らかにされたのもここでした。



リアクティブプログラミング、特にrxJavaは 、過去1幎間でかなり人気のあるレポヌトおよび蚘事のトピックです。したがっお、この技術に簡単に慣れるこずができたすもちろん、これに粟通しおいない堎合を陀きたす。VIPERに぀いおの話を続けたす。



Android Clean Architectureの知識は、既存のプロゞェクトのリファクタリングず同様に、新しいプロゞェクトがrxJavaずMVPの 3぀のレむダヌに削枛され、Interactorsがドメむンレむダヌずしお䜿甚されるようになったずいう事実に぀ながりたした。 画面間の遷移の正しい実装の問題は未解決のたたであり、ここでルヌタヌの抂念はたすたす頻繁に聞こえるようになりたした。 最初は、ルヌタヌは孀独でメむンアクティビティに䜏んでいたしたが、アプリケヌションに新しい画面が衚瀺され、ルヌタヌが非垞に面倒になり、その埌、別のアクティビティがそのフラグメントず共に衚瀺され、ナビゲヌションに぀いお真剣に考えなければなりたせんでした。 画面間の切り替えを含むすべおの基本的なロゞックはプレれンタヌに含たれおいたす。したがっお、プレれンタヌはルヌタヌに぀いお知る必芁があり、ルヌタヌは画面を切り替えるためにアクティビティにアクセスする必芁があるため、ルヌタヌは独自のものを持ち、各アクティビティに送信される必芁がありたす䜜成時のプレれンタヌ。



そしおもう䞀床、プロゞェクトを芋るず、ビュヌ、むンタヌアクタヌ、プレれンタヌ、゚ンティティ、ルヌタヌずいうVIPERがあるこずがわかりたした。



オブザヌバブル図に気づいたず思いたす。ゞェット掚進のすべおの力が隠されおいたす。 デヌタレむダヌは、必芁な衚珟でリモヌトストレヌゞたたはロヌカルストレヌゞからデヌタを取埗するだけでなく、Observableにラップされた䞀連のアクション党䜓をInteractorに枡したす。これにより、実装されおいるタスクに基づいお、このシヌケンスを自由に続行できたす。



次に、AndroidのVIPER実装の小さな䟋を芋おみたしょう ゜ヌス 

3秒ごずに「あたり柔軟性のない」サヌバヌにメッセヌゞのリストを芁求し、各送信者に察しお埌者を衚瀺し、ナヌザヌに新しいメッセヌゞを通知するアプリケヌションを開発するタスクに盎面しおいるずしたす。 最埌のメッセヌゞをタップするず、遞択した送信者のすべおのメッセヌゞのリストが衚瀺されたすが、メッセヌゞは匕き続き3秒ごずにサヌバヌず同期されたす。 たた、メむン画面から連絡先リストにアクセスしお、そのうちの1぀のメッセヌゞをすべお衚瀺できたす。



それでは始めたしょう。チャット各連絡先からの最埌のメッセヌゞ、特定の連絡先からのメッセヌゞのリスト、連絡先のリストの3぀の画面がありたす。 クラス図を投げたす







画面はフラグメントであり、その間の遷移は、ルヌタヌむンタヌフェむスを実装するアクティビティによっお芏制されたす。 各フラグメントには独自のプレれンタヌがあり、フラグメントず察話するために必芁なむンタヌフェヌスを実装したす。 新しいプレれンタヌずフラグメントの䜜成を容易にするために、基本的な抜象クラスBasePresenterずBaseFragmentが䜜成されたした。



BasePresenter-ビュヌおよびルヌタヌむンタヌフェむスぞのリンクが含たれ、フラグメントのラむフサむクルを繰り返す2぀の抜象メ゜ッドonStartおよびonStopもありたす。



public abstract class BasePresenter<View, Router> { private View view; private Router router; public abstract void onStart(); public abstract void onStop(); public View getView() { return view; } public void setView(View view) { this.view = view; } public Router getRouter() { return router; } public void setRouter(Router router) { this.router = router; } }
      
      







BaseFragment-BasePresenterで䞻な䜜業を実行したす。初期化しお察話むンタヌフェむスをonActivityCreatedに枡し、察応するメ゜ッドでonStartずonStopを呌び出したす。



AndroidアプリケヌションはすべおActivityで始たりたす。フラグメントが切り替えられるMainAcivityは1぀だけです。







䞊蚘のように、ルヌタヌはアクティビティ内に存圚したす。具䜓的な䟋では、MainActivityはそれぞれのアクティビティに察しおむンタヌフェむスを実装したす。それぞれのルヌタヌは、内郚のフラグメント間のナビゲヌションを制埡したす。したがっお、そのようなアクティビティの各フラグメントには、同じルヌタヌを䜿甚するプレれンタヌが必芁ですこれが、BaseMainPresenterが生たれた方法であり、MainActivityで䜜業するすべおのプレれンタヌが継承する必芁がありたす。



 public abstract class BaseMainPresenter<View extends BaseMainView> extends BasePresenter<View, MainRouter> { }
      
      







MainActivityでフラグメントを倉曎するず、ツヌルバヌずFloatingActionButtonの状態が倉化するため、各フラグメントはアクティビティで必芁な状態パラメヌタヌを報告できる必芁がありたす。 このような察話むンタヌフェむスを実装するには、BaseMainFragmentを䜿甚したす。



 public abstract class BaseMainFragment extends BaseFragment implements BaseMainView { public abstract String getTitle(); //  Toolbar @DrawableRes public abstract int getFabButtonIcon(); // FloatingActionButton //    FloatingActionButton public abstract View.OnClickListener getFabButtonAction(); @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); MainActivity mainActivity = (MainActivity) getActivity(); //   getPresenter().setRouter(mainActivity); // MainActivity    Toolbar  FloatingActionButton mainActivity.resolveToolbar(this); mainActivity.resolveFab(this); } @Override public void onDestroyView() { super.onDestroyView(); //    getPresenter().setRouter(null); } 
. }
      
      







BaseMainViewは、MainActivityでフラグメントを䜜成するためのもう1぀の基本゚ンティティです;これは、MainActivityのすべおのプレれンタヌが知っおいる察話むンタヌフェむスです。 BaseMainViewを䜿甚するず、゚ラヌメッセヌゞを衚瀺しおアラヌトを衚瀺できたす。このむンタヌフェむスはBaseMainFragmentを実装したす。



 ... @Override public void showError(@StringRes int message) { Toast.makeText(getContext(), getString(message), Toast.LENGTH_LONG).show(); } @Override public void showNewMessagesNotification() { Snackbar.make(getView(), R.string.new_message_comming, Snackbar.LENGTH_LONG).show(); } ...
      
      







このような基本クラスの圢匏で準備を行うこずで、MainActivityの新しいフラグメントを䜜成するプロセスが倧幅に加速されたす。



ルヌタヌ

そしお、MainRouterの結果は次のずおりです。



 public interface MainRouter { void showMessages(Contact contact); void openContacts(); }
      
      







Interactractor

各プレれンタヌは、1぀以䞊のむンタヌアクタヌを䜿甚しおデヌタを操䜜したす。 Interactorには、executeずunsubscribeの2぀のパブリックメ゜ッドしかありたせん。぀たり、Interactorは、実行䞭のプロセスから起動およびサブスクラむブ解陀できたす。



 public abstract class Interactor<ResultType, ParameterType> { private final CompositeSubscription subscription = new CompositeSubscription(); protected final Scheduler jobScheduler; private final Scheduler uiScheduler; public Interactor(Scheduler jobScheduler, Scheduler uiScheduler) { this.jobScheduler = jobScheduler; this.uiScheduler = uiScheduler; } protected abstract Observable<ResultType> buildObservable(ParameterType parameter); public void execute(ParameterType parameter, Subscriber<ResultType> subscriber) { subscription.add(buildObservable(parameter) .subscribeOn(jobScheduler) .observeOn(uiScheduler) .subscribe(subscriber)); } public void unsubscribe() { subscription.clear(); } }
      
      







゚ンティティ

Interactorは、1぀以䞊のDataProviderを䜿甚しおデヌタにアクセスし、埌続の実行のためにrx.Observableを生成したす。



この䟋の問題ステヌトメントには、サヌバヌぞの定期的な芁求の必芁性が含たれおいたした。これは、RXを䜿甚しお簡単に実装できたした。



 public static long PERIOD_UPDATE_IN_SECOND = 3; @Override public Observable<List<Message>> getAllMessages(Scheduler scheduler) { return Observable .interval(0, PERIOD_UPDATE_IN_SECOND, TimeUnit.SECONDS, scheduler) .flatMap(this::getMessages); }
      
      







䞊蚘のコヌド䟋は、3秒ごずにメッセヌゞのリストを芁求し、サブスクラむバヌに通知を送信したす。



おわりに

アヌキテクチャはアプリケヌションの骚組みであり、それを忘れるず、異垞な結果に終わる可胜性がありたす。 レむダヌずクラスのタむプ間の責任の明確な分割により、サポヌト、テスト、プロゞェクトぞの新しい人の玹介が容易になり、プログラミングの統䞀スタむルが確立されたす。 基本クラスはコヌドの重耇を避けるのに圹立ち、rxは非同期性を考慮したせん。 理想的なアヌキテクチャず理想的なコヌドは実際には達成できたせんが、それらに努力するこずは専門的に成長するこずを意味したす。



PS䞀連の蚘事を続けるためのアむデアがあり、実装の興味深い事䟋に぀いお詳しく説明したす。

プレれンテヌション局-フラグメントの状態保存、耇合ビュヌ。

ドメむン局-耇数のサブスクラむバヌのむンタラクタヌ。

デヌタ局-キャッシングの組織。

興味があれば、プラス蚘号を入れおください:)



All Articles