フローとは
フローとは文字通り「流れ」を意味し、水の流れのようにタスクが段階的に分割されて処理されることを意味します。山から水を汲む必要がある仕事があると想像してください。何をする必要があるでしょうか?
- 竿を担ぎ、山道を何十キロも歩いて水を持ち帰ります。シンプルで大雑把ではありますが、何十マイルも歩いて水が枯れていることに気付いたら、その旅は無駄だったということもあり得ます。
- 自宅から水源まで水道管を設置すれば、自宅で水道管を開いて水を飲むことができます。蛇口をひねっても水が出ない場合は、シンクに水がないことがわかり、無駄に蛇口を蛇口に回す必要はありません。
これは、実際には、現在主流の 2 つのプログラミングのアイデア、レスポンシブとノンレスポンシブに拡張されます。
いわゆる応答性とは、データ ソースがサブスクリプションとモニタリングを通じてデータを配信するのを待つことです。その利点は、データ ソース ロジックから簡単に切り離すことができ、データ ソースを渡す前にデータ フローを自由に変更できることです。たとえば、上記の例で、レモン味の水を飲みたい場合は、蛇口にレモン味のパイプを接続すれば間違いありません。従来の解決策では、水源にレモンエッセンスを加える必要がありましたが、現時点では、他の人がスイカ味の水を飲みたい場合は飲むことができません。
なぜ流れるのか
Flow が登場する前は、RXjava が常に一般的に使用されていたフロー記述方法でした。では、RXjava と比較した Flow の利点は何でしょうか? ChatGpt は次の点を信じています。
- より軽量: Flow は Kotlin 標準ライブラリの一部であり、追加の依存ライブラリを導入する必要はありませんが、RxJava は RxJava コア ライブラリと関連する演算子ライブラリを導入する必要があるため、プロジェクトの複雑さと量が増加します。
- よりシンプル: フローは Kotlin コルーチンに基づいて実装されており、コルーチンのシンタックス シュガーを使用すると、コードがよりシンプルで読みやすくなり、RxJava よりもシンプルになります。
- より柔軟: Flow はバックプレッシャー処理と、同時に同じデータ ストリームにサブスクライブする複数のサブスクライバをサポートしますが、RxJava は複数のサブスクライバを処理する
share()
ためにreplay()
や などの演算子を使用する必要があります。 - より安全: フローはコルーチンのコンテキストで実行できるため、RxJava での一般的なスレッドの安全性の問題やメモリ リークを回避できます。
- より予測可能: Flow は Kotlin のタイプ セーフティ機能を使用して、型の不一致や null ポインター例外などの問題をより簡単に回避します。
実際、開発者として最も重視しているのはシンプルさです。使用法が簡単であればあるほど、学習コストが低くなり、間違いや予期せぬ問題が発生する可能性が低くなります。
その他の Android 開発学習ノートについては、ここをクリックして無料で入手してください
従来のソリューション、RXjava、Flow の直感的な比較
最も一般的に使用される例として、サブスレッドのネットワーク リクエストを考えてから、データをメイン スレッドに返して UI をロードしてみましょう。
従来のソリューション
OkHttpUtils.sendGetRequest("http://example.com", new OkHttpUtils.CallbackListener() {
@Override
public void onSuccess(String response) {
// 在主线程中处理请求成功的结果
textView.setText(response);
}
@Override
public void onFailure(IOException e) {
// 在主线程中处理请求失败的结果
e.printStackTrace();
Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
}
});
ネットワークリクエストを開始してリスナーを登録し、リクエスト結果が返されたときに結果をコールバックします。この時点でネットワーク リクエストが成功した後に 2 番目のインターフェイスをリクエストする必要がある場合は、次のように別のコールバックをネストする必要があります。
OkHttpUtils.sendGetRequest("http://example.com", new OkHttpUtils.CallbackListener() {
@Override
public void onSuccess(String response) {
// 在主线程中处理请求成功的结果
OkHttpUtils.sendGetRequest("http://example2.com", new OkHttpUtils.CallbackListener() {
@Override
public void onSuccess(String response) {
// 在主线程中处理请求成功的结果
textView.setText(response);
}
@Override
public void onFailure(IOException e) {
// 在主线程中处理请求失败的结果
e.printStackTrace();
Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onFailure(IOException e) {
// 在主线程中处理请求失败的结果
e.printStackTrace();
Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
}
});
2 つのレベルがあると、完全に「コールバック地獄」に陥ってしまい、ロジックが直感的に理解することがますます困難になることがわかります。さらに致命的なのは、この方法は拡張できないことです。たとえば、別のユーザーが最初のリクエストが成功した後にバブルをポップアップさせたいと考えていますが、2 番目のユーザーはバブルは必要ないと言いました。このように、パラメーターを追加して if-else 判定を記述するだけです。このままでは、このメソッドは急速に拡張して再利用できなくなり、CV1.0、2.0バージョンが「デビュー」し始め、最終的にはこのクラスは維持されなくなります。
RXjava ソリューション
RxJavaUtils.sendGetRequest("http://example.com")
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
// 在这里可以做一些准备工作,比如显示进度条等
}
@Override
public void onNext(String response) {
// 在主线程中处理请求成功的结果
textView.setText(response);
}
@Override
public void onError(Throwable e) {
// 在主线程中处理请求失败的结果
e.printStackTrace();
Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT
})