Devグループで紹介しました。彼はライブラリについてだけでなく、サンプルアプリケーションや、彼がお決まりのコードの使用を減らしてライフサイクルイベントを処理するのに活用しているヘルパークラスについてもディスカッションしました。(0:00)この講演はSquareが開発した2つのライブラリ、FlowとMortarについてのものです。私はこれらを約1年前、Jellyで働いていた時に使い始めました。初めに、なぜ私がこのライブラリを使い始めたのか、どのようにそれを導入したのかについてお話しします。簡単なFlowの概要として、フラグメントを、通常のビューと比較してお話します。それから、FlowとMortarについての詳細な話を少しします。突っ込んで、ライブラリのコンポーネントについて、何が興味深くて、どのように動いているのかをお見せします。最後に、このライブラリには含まれてはいませんが、このライブラリがプロジェクトを構築する上で役立ついくつかの事柄をお伝えします。社のオリジナルのアプリ、JellyはQ&Aアプリです。私はFlowとMortarを使用して、当時のエンジニアとそのアプリを制作しました。それから、私たちは次期バージョンであるSuperの計画に入り、より面白みのあるアプリを求め作り始めました。私たちはフラグメントと少数のアクティビティを使用することに戻ることもできましたが、すでに約1か月間、FlowとMortarを使用していたのと、それらが提供してくれたビュー同士の分離性の方を私は気に入ってしまいました。(2:10)フラグメントを扱う多くの場合、ビューロジックとビジネスロジックをコード内に混在させがちです。数年前、私はあるアプリの速度を改善するために、いくつかのアクティビティをフラグメントに書き換えました。アクティビティが作成されるときの負荷をなくして、スレッドビューからのトランジションを高速に行うことを望んでいました。それから詳細ビューや、マップのビューにも着手して、階層化されたフラグメントを使い始めました。Androidのフラグメントのライフサイクルは、アクティビティのライフサイクルよりも多くのステップがあり複雑なので、私たちはいくつかの箇所でつまづきました。フラグメントマネージャはフラグメントの順序を扱うのを手伝ってくれるでしょう。私たちが追加したフラグメントが、その順序通りに正しく表示されないこともあるので、それらを調整しなければなりません。(3:37)Flowはスクリーンの記述と、ナビゲーションのためにバックスタックを扱う方法を提供してくれます。フラグメントでは、あなたのフラグメントを管理するためにFragmentManagerを使用します。ここでは、Flowがあなたのスクリーンを管理し、どのスクリーンが表示されるべきかを決定します。Flowはまた、スクリーンのヒストリーも管理し、もしアプリがバックグラウンドになった場合にも状態を持続させます。あなたのアプリに戻るとすぐに、Flowはきれいに、そのヒストリーとスクリーンを再構築してくれるでしょう。単一のフローにはサブフローを含めることができます。あなたが階層化されたフラグメントを扱えるのと同様に、階層化されたフローを扱うことができるのです。メインのフローと、そこに編集のフローとログインのフローがあるようなケースに利用する場合、これらはしっかりと分離され、お互いに影響することはありません。メイン以外の場所にフローがある状態で、私たちはきちんとその状態を管理することができます。(5:05)Mortarとは、コンテキストのgetSystemServiceと統合された、アプリケーションライフサイクルの上を覆うものです。これは依存性の注入において非常に素晴らしい働きをします。MortarはMortarScopeを使用し、必ずしもDaggerやその他のシステムと一緒に動作する必要はありません。私のケースでは、プレゼンター、ビューなどの全てに、依存性を与えるために、Daggerの持つ依存性注入をMortarと一緒に利用しています。すべての処理がひとつのアクティビティの中にある場合、いくつかのあなたのクラスは永続した状態である必要があるかもしれません。BundleServiceは、私がアプリケーション中のアクティビティのBundleを、コンテキストにアクセス可能なクラスに対して開放するために追加したものです。その他のMortarの魅力は、Presenter、ViewPresenterです。これらは、Bundlerと統合され、あなたのあらゆるビューデータの永続性を扱います。のちほど、どのようにしてスクリーンの中で状態を保持するのか、そしてフローの中の様々なスクリーンに、それらを保持したり注入するのかの例を紹介します。(6:46)併せて、FlowとMortarは全てのスクリーンにPathクラスを継承させるでしょう。各スクリーンはそれぞれのモジュールを持っています。詳細ビューへ移動する場合、そのスクリーンにユーザーIDを渡すことができます。そのユーザーIDは、スクリーン内に存在し、プレゼンターに注入されたモジュールを提供することができます。このように、もしそのアプリケーションがバックグラウンド状態にある場合は、onSaveInstanceStateの中でBundleに書き込まれます。私たちはIDを保存するだけでいいのです。あなたのスクリーンが次に再生成された時は、同じIDがまだスクリーン内にあり、プレゼンターに再注入させることが可能です。これはModel-View-Presenterのコンセプトに見事につながります。プレゼンターは異なる目���のために相互にやりとりができ、一方でとても上手に分離されています。この例では、チャットリストのスクリーンとそのビューがあります。モジュールはビューを追加して、また、自身をルートモジュールに追加しています。chats.getAll();}}}ビューでは、プレゼンターのインスタンスがあります。onDetachedfromWindowでは、プレゼンターがビューが作成されたことを知らせるためにコールバックを提供します。プレゼンター側では、注入されたチャット情報に基づいてビューをすぐに設定することができます。これはonLoadの関数です。ビューでは、1つのアイテム上でクリックハンドラーも用意されています。次のスクリーンへ遷移するためにFlowを使用してプレゼンターに対してコールバックします。ここでは、先に指定されたIDのポジションを使用します。(9:45)さあ、では実際に、どのようにセットアップしましょうか?MortarScopeはgetSystemService中に用意されています。そこには、Daggerの注入のためのサービスがあります。@Providesは最初に、ActionBarの中身のいくつかを内包します。GSONシリアライゼーションのように中の物を公開することもできます。以上がセットアップの大半です。アプリケーションクラスとして必要なものは他にはありません。(11:01)少しコードをアクティビティへ移動させました。MortarScope上に追加されたクラスへパーシスタンスバンドルを提供する場所です。メソッドはFlowがセットアップされる場所であり、そして永続性を得るためにスタックされたあなたのビューのヒストリーと、いくつかのアクティビティのライフサイクルイベントに関連性を持たせるためにflowDelegateを統合する場所でもあります。パスコンテナもまた、ここでセットアップされ、トランジションを処理する包括的なコンテナです。後ほどそのトランジションが実際には提供されていないのをお見せします。どんなUIアニメーションを実装するかはあなた次第なので、あなたが望むようにアニメーションをセットアップすることで、かなりの独自性を得られます。this);)}onResume、onSaveInstanceState、onDestroyのために、flowDelegateをコールすることができます。下では、dispatchが、containerにビューを追加して、一番上のアクションバーをセットアップすることができます。ひとつの列挙する点は、アクティビティが一つだけしかないことです。プレゼンターは何が表示されるかをコントールします。アクションバーにアクセスする注入可能な方法としては、actionBarOwnerがあります。これは、バンドラーと似ていて、生成後にライフサイクルにフックするものです。プレゼンターはアクションバーや、タイトル、ボタンなど、特定のスクリーンにとって必要な変更を行うために、このactionBarOwnerを注入します。(13:32)Flowはあなたのナビゲーションを実行するのと、スクリーンのヒストリーをトラッキングし続けることに関与しています。Flowがこれを行うには、いくつかの方法があります。setメソッドがあります。あなたがこのスタック上に存在しないスクリーンに移動したい場合、それが一番上に追加されます。ヒストリーのどこかにすでに存在していたら、元に戻ってください。それより上の全てのスクリーンは取り出され、それが最新の画面になります。History.singleを使うことで、完全にあなたのヒストリーを再構築することもできます。バックボタンを操作する限りは、Flowはアクティビティーの中にいくつかのインテグレーションが存在します。ユーザーはビューにいくつかのアクションを実行するので、もしあなたがそれを自分でトリガーしたい場合は、Flow.goBackを使えばいいのです。(15:14)先ほど私が述べたように、スクリーントランジションはあっても、アニメーションはありません。それらを実装するためには、FlowのPathContainerが継承される必要があり、performTraversalメソッドが実装されていなければなりません。このひとかたまりのコードでは、performTraversalメソッドは現在のスクリーンをみて、アニメーションを実行します。最後に、古いビューを実際に削除しますので、そこで新しいものを追加します。アニメーション後、グラフからだけではなくコンテナーからも古いスクリーンを削除します。この方法では、あなたの各スクリーンは必要な限りコンテキストオブジェクト内に留まります。それぞれのスクリーンは、そのモジュール内のオブジェクトグラフに追加するものを提供することができ、あなたがそこから離れ、スクリーンを削除するとすぐに、そのコンテキストは破棄されます。そのモジュールが提供するものはもはや何もなくなりました。メモリはクリーンなままです。(16:44)私はFlowヒストリーを、意図していたのとは違う使い方をしているかもしれません。Flowヒストリーは、状態を把握します。スクリーンヒストリーの中に保持されたあなたのスクリーン内に特定の値を格納することができます。それらは、パーセラーを経由する時に、バンドルに永続化されます。Parcelerを使用しています。私は自分のオブジェクトに変換します。何か複雑なものを、バンドルに書き込むことができるシンプルなJSONストリングに変換することができます。それはあなたがflowをコンポーズする際に役立ちます。このコンポーズが状態をもっているからです。ヒストリー内で何かのために呼び出されます。(19:47)一番上位のレベルでは、あなたのアプリケーションはひとつのフローの中にあります。そのフローはMainFlowに継承されていて、あなたがどのように遷移したかのヒストリーを持っています。最初の画面を開くと、それはProfileScreenでしょう。あなたが編集を行う時、あなたはComposeFlowへ下がって行きます。そこには、ComposeStateが追加してあります。そこからあなたは、ComposeScreenとRefineScreenへ行くことができます。graphに追加した時のままの状態を保っています。それを説明するために、ここに実際のComposeFlowの画面があります。上にComposeStateオブジェクトがあります。これはあなたがflowを入力する度に作成されるものです。プレゼンターでは、最初の因数として注入されます。これは、包括的なflow内の特定のflowの状態の把握をとても簡単にします。同じflowを複数の場所に注入することができます。(21:46)あなたは、ただ1つのアクティビティー内に存在し、Flowを通してあなたのトランジションと、またMortarを通してあなたの依存性注入を処理するだけで、より簡単にライフサイクルを作成することができます。多くの場合、あなたはライフサイクルイベントにアクセスすることが必要になるでしょう。これはFlowとMortar内には実際にはありません。シングルサインオンするために他のサービスと統合したい場合、もしくはあなたが自分のカメラインテグレーションを使用している場合は、ライフサイクルイベントが必要になるでしょう。簡単なルートはあなたのアクティビティをプレゼンターに注入し、コールバックを送るでしょうが、しかしそれはあまり美しくはありません。私が見つけたひとつの良い方法は、ライフサイクルマネージャを使用するものです。アクティビティはLifecycleOwnerのインスタンスを一つ持ち、このインスタンスは、onResume、onPause、onActivityResultイベントにフックします。プレゼンターの中では、あなたはLifecycleOwnerのインスタンスを取得し、それらをレジスターすることができます。して、インデックスはViewPresenterをあなたに提供し、ActivityLifecycleListenerを実装します。して、多くの異なるイベントが存在するので、あなたに必要なのはonActivityResultだけかもしれません。いうわけで、私たちはインターフェースを含める為に、LifecycleViewPresenterをサブクラスにします。こちらの例では、ViewCycleOwnerはプレゼンター内にフックされています。私たちはonLoadで登録を行い、onExitScopeで登録解除を行います。私はまた、CameraCaptureViewでこれを使用しています。その状態は時々、構築される必要があります。アプリケーションを一時停止していてもカメラが作動している場合は、他のアプリのためにカメラをブロックしてください。私がプレゼンターの中のカメラをまたアクティベートする必要があるかどうかを知らせてく���る状態オブジェクトがあります。(25:02)MortarとDaggerの組み合わせは、私たちに良い依存性注入をしてくれます。私たちはそれを活用したいですし、実際に全てのセッテイングを注入します。セッティングマネージャの代わりに、私たちは必要に応じて、プレゼンターへ個々のセッティングを注入することができます。extendsするStringLocalSettingSettingsModuleと一緒に、SettingsModuleを追加しています。“config”のアノテーションと、providesConfigも追加します。これらのセッティングはSharedPreferencesに置かれます。"config");}}SettingsModuleは、私のルートモジュールに追加され、そこで私の場合は、ApplicationModuleを呼び出します。1つのマネージャを渡すのではなく、“config”アノテーションを介して、自分のローカルストリングセッティングに注入することができます。これらは私がgetす���度に提供されるので、私は常に最新のものを取得することができます。takeViewを通知を提供するために呼び出します。別のヘルパーは、私が構築した処理済みの注入Mortarです。Knifeも使います。反復コードの使用はより少ないです。(27:40)良い点、悪い点はなんでしょうか?私は、新しいマテリアルスタイルのビューのアニメーションのサポートが存在しないことに気が付きました。私はたったひとつのアクティビティしか持たないし、その為、それを自分自身で構築しないといけないかもしれません。Flowによって与えられる柔軟性と、アニメーションは間違いなく実現可能です。FlowもMortarも今でも活発に変わり続けています。これはプロジェクトを前に進める、良いことと言えます。活発な開発は、人々が今でもプロジェクトについて考え、取り組んでいることを示しています。良くない傾向は、新しくリリースされたバージョンのライブラリは、多くのAPIの非互換な変更をもたらしていることです。慣れ親しんだ仕組みから新しい仕組みに移行することは大変なことです。私たちが今日見てきた全てのものは、最新のテンプレートアプリケーションをベースにしています。多くの場合は仕組みはほぼ同じでネーミングのみが変わることがほとんどです。私がしようとし続けていることは、プレゼンターをどのようにテストするかについて習得することです。中心部分はすでに上手に分離されています。スクリーンやビューの中のパスプレゼンターの周辺でのMortarの依存性注入はとても簡単です。私はこれらすべてが本当に優れた利便性だと思います。短いREADMEファイルと、少しの解説コードが入ったレポジトリーがあります。私たちがただ最初からアプリを再起動することができる時に、なぜ状態の永続性の実装にそんなに多くの時間を費やすのですか?もしあなたのアプリがバックグラウンドで停止している場合には価値があることは理解できます。私はあなたのアプリケーションの前の状態を再構築すべき例をいくつも思いつきます。誰かがSuper内に新しいポストを作成するflowを構築する段階にいる時、もし彼らがブラウザーでリンクを探す場合、アプリはバックグラウンドになります。あなたは彼らがアプリに戻ってきた時、彼らがそのポストに実際にそのリンクが追加されたかを確かめられるように状態を確認してもらいたいでしょう。私が開発したどんなアプリで、私はいつもこれを再構築します。あなたが再構築したい理由の1つは、データインプットです。何かをタイピングするのをやめるとしましょう、そして他の何かを開きます。あなたがアプリに戻ってきた時、あなたのテキストがまだそこにあるのは親切なことです。状態を保存する場合の別のシチュエーションは、あなたが電話に出る時や、オーディオブックを聞く時でしょう。腕の良いデベロッパー達により開発された良いゲームはたくさんあります。彼らはライフサイクルを理解していません。あなたは他のことをするためにゲームを中断した時、すぐに気がつきます。あなたはゲームを再スタートしなければなりません。これは大きな違いになります。Q:電話が掛かってきたときにどれくらいの頻度でアプリが停止するか、何かデータや考えはありますか?私はただ電話のようなものでアプリが停止するとは考えません。あなたの携帯電話は多分十分なRAMを持っていないのでしょう、だからバックグラウンドにある全てのアプリが起動した時に停止してしまうのです。あなたが高性能な携帯電話を持っていれば、それに気がつかないでしょう。低級の携帯電話の場合は、これは本当にたいしたことですよ。高性能携帯電話では、OpenGLゲームをする時は、私は他のアプリケーションを停止しなければいけません、しかし他にはほぼありません。携帯電話を横にした時、アクティビティーは停止します。アウトステート上のあなたのバンドルを保存しない場合、onCreateの中にそれが再構築されます。あなたは全てのビューを失うことになります。MortarとFlowは永続性を使用して仕事をするのに役立ちます。簡単にあなたのスクリーンを再構築できるのです。これはまた、あなたのアプリケーションを設計するための違う方法でもあります。ロジック内に分離があるのと同様、親切なビュー同士の分離と、プレゼンターがあります。あなたはおそらく元に戻したいと思うでしょう。リストから詳細ページに遷移した場合、あなたがアプリに戻ってきた時に同じ場所にリストをつくりたいと思うでしょう。1つだけFlow上にサンプルコードがありました。同様に、2つが含まれていました。1つはDagger用に、もう1つはDagger2用です。これはビューの構造自体を変えようとしているので、新しく始めるプロジェクトにとってはとても魅力的だと思いました。私はプロジェクトをゼロから始めましたが、あなたのプロジェクトがどれくらいの規模によるかによります。あなたのビューを書き換えるなら、あなたのビューがどのように構成されているか次第で、簡単にも難しくもなるでしょう。このプロジェクトを利用することにも、とても価値があります。プロジェクトを進める複数の人がいて、さらに多くの人がこれを取り入れます。自分一人で挑戦することには価値はありません。あなたがすでに、かなり進んだ開発サイクルの中にいるとしたら、あなたの製品をスイッチすることが本当に有益かは私にはわかりません。Androidのライフサイクルメソッドを扱い、それを簡単にしようとするライブラリが存在します。一つはRoboBindingです。あなたは、FlowとMortarに大きく依存して、多くの将来の可能性を失っているように見えます。それはなにか特定のソリューションを採用するときに必ず起こると思っています。私はまだ古いバージョンを使っていて、APIが変わってしまいました。これはプロジェクトを進めるためには一仕事ですが、結局はやる必要があります。私はオリジナルのJellyアプリにとって、これらのライブラリを使うことはとても良いと思うし、魅力的に見えるので、私たちはこれらの使用をやめられません。間違いなく、最新バージョンでクラス、メソッド、ネーミングがたくさん変わったことによる影響で、いくつかの技術的な負債は貯まってはいます。このアプローチがなぜフラグメントよりも優れているのか、もう少し教えて下さい。MVCの代わりとして、MVPがあること、また、Daggerがコードをより抽象化することは知っています。私が指摘した理由の一つが、あなたが、階層化されたフラグメントを持っていて、自分でそれを管理しなければいけない状況についてです。この解決法は私が過去に陥った問題を考えると、とても魅力的です。私はほとんどステート周りの問題に出会っていませんし、それ以来アプリケーションの作り直しもしていません。現在、みなさんはアクティビティとフラグメントを利用することに慣れています。高速なデバイスにおいて、それらを処理する際の負荷はそれほど悪いものとは言えないでしょう。Squareはフラグメントが好きではなく、彼らはそのフレームワークに由来するUIを使いません。彼らは、彼らのやり方でするのが好きなだけで、そして素晴らしいプロジェクトを持っています。もこのアプローチはとても革新的に見えます。テストを簡単にするためには、フラグメントから、カスタムのビューに移行することを決めなければなりません。問題の一部はフラグメントからテストすることから始まっていて、カスタムのビューをテストすることはとても簡単です。私たちのアプリケーションでは少なくとも30%のクラッシュが、バックグラウンドでタスクを終了したことで起こっていました。フラグメントの中にいると、アプリはクラッシュしますが、ビューの中ではきっとそうはなりません。はい、それはきっとあなたが普段書くものだろうと思います。スクリーンの一番上に、あなたのあらゆるレイヤーファイルを含めるでしょう。それは階層が増えるのを制御します。Flowレポジトリからは削除されました。今サンプルプロジェクトの一部になっています。レイアウト用xmlファイルなのです。RoboBindingsはMortarに対して、代わりとなるライブラリと言われています。他にあるとは思いません。ビューへのすべてのコールバックを扱い、とても急進的で、妨げとなりません。その上で、あなたはアプリケーションを設計しないとなりません。あなたが、プレゼンターに、シングルトンスコープとしてマークされたDaggerモジュールを持っているのを見ました。いいえ、それはスクリーンがなくなった時に消えます。はい、あなたのビューはフラグメントを内部に持つことが出来ました。あなたがアプリケーションを書き換えていて、それが、フラグメントの中にある時、あなたは、引き続き、これに切り替えて、あなたのフラグメントにラップされたビューを持つようなことができます。その他のレイヤーファイルであなたがしてきたことと、一緒だろうと思います。私は実際にはタブレット向けに開発を行ったり、このライブラリを使用したことはありません。どのようにレイアウトファイル構築して、異なるリソースフォルダーに含めたかによって、異なる働きをしてしまうことはないと思います。スクリーンは特定のレイアウトに対してアノテートされているので、どんなデバイスの上なのかを反映したビューを生成するでしょう。それらへのサポートも存在します。通常のビュープレゼンターの他に、ポップアッププレゼンターがあります。私たちは、それをナビゲーションの行き来とまったく同様に使います。subscription。