従来のコールバック
コールバックは、動的な呼び出しである、つまり、呼び出しは、コードの特定の役割を呼び出す場所を知らないだけで、呼び出しの契約を遵守するために、いくつかのケースでは、レイアウトを呼び出す必要がある、最も一般的なコールバックは、オブザーバパターンリスナーコールバックです。
  呼び出しの契約は、ここで、実際にはもう少し具体的には、インターフェイスであり、コールバックのプロセスは、インターフェイスの呼び出しクラスにまたはコールスタックにメソッドのパラメータを介して、特定の状況の実装では、インターフェイスが呼び出されるので、インターフェイスプログラミングに向いているので、インターフェイスの実装を知っている場所のインターフェイスパラメータの渡しだけですが、インターフェイスを呼び出す場所は、具体的なロジックの実装を認識していませんロジックの実装を知りません。
  一般的に使用されるオブジェクト指向の高級言語は、直接インターフェイスのデータ型を提供し、一般的に言えば、コールバックの定義は、関数またはメソッドのインターフェイス型です。
インターフェイスのコールバックのジレンマ
リファクタリングを行ったことのあるプログラマーは、最も忍耐強いプログラマー集団です。なぜなら、要求を満たす方法を見つけ出すだけでなく、コードをより読みやすく修正しやすくするために、ビジネスロジックに影響を与えずにコードの構造を変更する必要があるからです。ビジネスロジックに影響を与えずにコードを変更しやすくすることです。このためには、コードをより拡張しやすくする必要があり、拡張性は多くの場合インターフェースを使用することで実現されます。インターフェイス指向は、オブジェクト指向プログラミングのデフォルトの仕様ですが、リファクタリングは平和の世界、ビジネスすることができますし、多くの場合、インターフェイスの定義後に発生し、小麦を踏みにじる野生の馬のようになる可能性があります開発、ビジネス開発は、新しいシナリオを追加したり、新しい状態を追加する必要があります、それは新しいメソッドを追加するには、インターフェイスのインターフェイスになりますので、インターフェイスが劇的に拡大されます。インターフェイスの実装の要件のために、すべてのインターフェイスの実装クラスは、インターフェイスで定義されているすべてのメソッドを実装する必要があります。抽象クラスを使った方がいいという人もいます。実は、抽象クラスがそんなにうまく機能するなら、データ型としてのインターフェースは必要ないのです。抽象クラスを使うには、実装クラスが抽象クラスを継承する必要があり、ほとんどすべてのオブジェクト指向言語では、クラスは継承する親クラスを1つだけ持つことを強制されます。リファクタリングプロセスでは、実装クラスの継承構造は通常変更されませんが、元のクラスはインターフェイスで拡張されることがよくあります。
  インターフェイスの拡張の問題に加えて、インターフェイスの実装に起因する実際のクラスであるため、多くの場合、これらの実際のクラスが作成されたオブジェクトは、他のクラスへの直接または間接的な参照を持つことになり、これらのインターフェイスは、より長いライフサイクルをもたらし、任意の場所に渡される可能性があり、したがって、参照されるオブジェクトの内部ライフサイクルによっても、特にAndroidの大きなオブジェクトのContextシリーズのように長くなります。特に、AndroidのContextシリーズのような大きなオブジェクトは、コールバックオブジェクトによってライフサイクルが長くなると、メモリリークが発生します。
つのインターフェース・メソッド+複数の状態
状態変更シナリオは非常に一般的なコールバックシナリオであり、理論的にはどのようなコールバックシナリオも状態変更コールバックとして広く理解することができ、状態のないシナリオを1つの状態のみのシナリオに昇格させることができます。従来のインターフェイスのコールバックは、異なる状態のコールバックを区別するために複数のメソッドを使用します。例えば、マルチメディア再生の状態変化は、それぞれプレーヤーの状態変化を表すためにリスナーインターフェイスの複数のメソッドを使用します。このような設計は、前述のインターフェイス・コールバックのジレンマ、つまり、新しいステートの追加にはインターフェイスの変更が必要というジレンマにつながります。よりよい設計は、リスナー実装にインターフェイスメソッドのメソッドとしてステートを渡すことです。そうすれば、すべてのステートコールバックメソッドは同じメソッドに収束し、新しいステートを追加する必要があるときは、ステートフィールドに新しい定数を追加するだけでよくなり、新しいステートに関心のない実装は追加を意識することがなくなります。
外部クラスへの参照を実装したインターフェース
オブジェクト指向プログラミングでは、内部クラスは、一般的に外部クラスへの参照を保持することを余儀なくされ、アウターなどのコードがない場合でも:thisは、内部クラスによって生成されるバイトコードは、内部クラスは、外部クラスへの参照であるプロパティを持っています。外部クラスへの参照のインターフェイスの実装は、一般的に別のクラスまたは静的内部クラスとして内部クラスを定義することによって解決され、参照プロパティをnullに設定するには、対応する場所で、セットまたはコンストラクタのパスを介して外部クラスを使用する必要性、または参照プロパティは、WeakReference型として定義されています。
  Lifecycleフレームワークは、イベントの登録や配信において、実際にActivity/Fragmentを必要としますが、LifecycleはActivity/Fragmentへの強い参照を保持しておらず、nullを設定する場所がありません。LifecycleOwnerの参照はWeakReference型で、このLifecycleOwnerの実装クラスはActivity/Fragmentです。
LiveData簡単な使用法
import android.annotation.SuppressLint
import android.os.Bundle
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class LiveDataDemoActivity: AppCompatActivity() {
 @SuppressLint("SetTextI18n")
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 val contentView = LinearLayout(this)
 contentView.orientation = LinearLayout.VERTICAL
 val status = MutableLiveData<Int>()
 status.value = 10
 val text = TextView(this)
 text.text = "status = ${status.value}"
 contentView.addView(text)
 val btn1 = Button(this)
 status.observe(this, Observer {
 text.text = "status = ${status.value}"
 })
 btn1.setOnClickListener {
 GlobalScope.launch {
 delay(1000L)
 status.postValue(status.value!! + 10)
 }
 }
 btn1.text = "add 10"
 contentView.addView(btn1)
 val btn2 = Button(this)
 btn2.setOnClickListener {
 GlobalScope.launch {
 delay(2000L)
 status.postValue(status.value!! + 20)
 }
 }
 btn2.text = "add 20"
 contentView.addView(btn2)
 setContentView(contentView)
 }
}
このデモでは、ボタンがクリックされると、n msの遅延の後にLiveDataの値が変更され、LiveDataのObserverが変更された状態を受け取ります。
LiveDataソース コード解析
LiveDataが特に使いやすいのは、公開するインターフェースが少ないからです。通常使用されるインターフェイスは、setValue、getValue、postValue、observerの4つだけです。 これらの4つのメソッドの呼び出し順序に従って、ソースコードを見ることができます。最初はobserverメソッドで、そのシグネチャは
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
つまり、このメソッドはメインスレッドで呼び出す必要があり、入力されるパラメータはそれぞれLifecycleOwnerとObserverオブジェクトです。Lifecycleフレームワークのソースコード解析では、LifecycleOwnerがライフサイクルオーナーであり、getLifecycleメソッドを1つだけ持つインターフェースであることが分かっています。戻り値はLifecycleRegistryオブジェクトで、このLifecycleRegistryはアクティビティ/フラグメント参照を保持するWeakReferenceを持ちます。このオブザーバーメソッドの実装も比較的シンプルで、全体的なロジックはLifecycleのオブザーバーメソッドに似ています。ここでは、LifecycleBoundObserverを使用して、オブザーバーをLifecycleコールバックにバインドします。
  LifecycleBoundObserver は ObserverWrapper を継承し、 GenericLifecycleObserver インターフェースを実装しています。LifecycleBoundObserverは、 GenericLifecycleObserverのonStateChangedメソッドを実装しており、 ライフサイクルがDESTROYEDに達したかどうかを判定し、現在のオブザーバーをリスナー・リストから削除します。booleanパラメータを渡します、この値は、shouldBeActiveメソッドによって返されます、shouldBeActiveメソッドは、現在の状態がSTARTEDであるかどうか、およびその次の状態を決定することです、ここでは、LiveDataは、アクティブな状態でのみ状態の変更を通知すると言うことです、そして、このアクティブな状態は、[STARTED]です。activeStateChangedメソッドはdispatchingValueメソッドを呼び出してLiveDataの値変更を通知します。dispatchingValueメソッドはconsiderNotifyメソッドを呼び出して通知メソッドonChangedを呼び出し、considerNotifyメソッドでは、通知メソッドによって通知されます。considerNotifyメソッドの中でonChangedメソッドはいくつかの状態判定を行います。まず状態がアクティブかどうか、次に状態オブザーバのmLastVersionがmVersionより小さいかどうかです。mLastVerisionは通知が行われるたびにmVersionを保存するもの、つまりmLastVersionは最後の修正通知のバージョン番号ですが、mVersionはsetValueで1だけインクリメントされ、postValueでは実際にsetValueメソッドを呼び出して値を更新します。 mLastVersionはmVersionよりも小さくする必要があり、これは実際には値の各修正を1回だけ通知する必要があることを示しています。mLastVersionはmVersionより小さくする必要があります。Lifecycleの状態が変化した場合、その値を通知する必要があります。つまり、ステートがactiveでないときは、値が変更されてもonChangedは通知されませんが、今回は、ステートがactiveに戻ったときに通知メソッドがコールバックされます。setValueメソッドを見てみましょう。setValueメソッドでは、まずメインスレッドで呼び出されたかどうかを判断します。setValueメソッドでは、まずメインスレッドで呼び出されたかどうかを判断し、更新された値をmData変数に格納し、dispatchValueメソッドを呼び出してオブザーバのリスナーメソッドに通知します(これはLifecycle通知と同じです)。次に postValue メソッドです。
protected void postValue(T value) {
 boolean postTask;
 synchronized (mDataLock) {
 postTask = mPendingData == NOT_SET;
 mPendingData = value;
 }
 if (!postTask) {
 return;
 }
 ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
 }
要約すると
LiveDataは一般的なデータクラスのオブザーバー・パターンを提供し、変更観測のためのデータのタイプは何でもよく、組み込みのライフサイクル・リスナーは、LiveDataがアクティブとみなす状態でのみ、オブザーバーへの変更コールバックの値になります。これはGoogleのAndroidの仕様とも一致しており、Activity/Fragmentがアクティブなときにのみデータの変更を通知し、UIの更新をトリガーします。また、LiveDataはコールバック・インターフェースではなく変数の形になっており、このLiveData変数は任意の深さだけでなく、任意のクロススレッドに渡すためにビジネスに従うことができるので、LiveData内部で決定されたonChangedコールバックはメインスレッドに投稿されました。





