web-dev-qa-db-ja.com

AndroidデータバインディングObservableList動作の問題

_Android.databinding.ObservableList_の実際の存在理由をデータバインディング機能として見つけるのは難しいと思います。

最初は data binding を通じてリストを表示し、xmlを介してRecyclerViewにリストを追加するためのクールなツールのように見えました。そうするために、私は BindingAdapter を次のように作成しました:

_@BindingAdapter(value = {"items"}, requireAll = false)
public static void setMyAdapterItems(RecyclerView view, ObservableList <T> items) {
    if(items != null && (view.getAdapter() instanceof MyAdapter)) {
        ((GenericAdapter<T>) view.getAdapter()).setItems(items);
    }
}
_

このように、RecyclerViewに設定されたMyAdapterで属性_app:items_を使用して、その項目を更新できます。

これで、ObservableListの最も優れた機能は、OnListChangedCallbackを追加できることです。これにより、RecyclerViewで使用可能な同じイベントを処理して、リスト全体を実際に再読み込みせずに、アイテムを追加/移動/削除/変更できます。

したがって、私が実装しようと思ったロジックは、次のようなものです。

  1. 空のMyAdapterから始めます
  2. アイテムがAPIからフェッチされたら、ObservableArrayListをインスタンス化してそれらをラップし、bindingに渡します
  3. データバインディングによってBindingAdapterが呼び出され、アイテムがMyAdapterに渡されます
  4. MyAdapterが新しいアイテムを受け取ると、古いアイテムをクリアし、受け取ったOnListChangedCallbackObservableListを追加して、マイクロ変更を処理します
  5. ObservableListで何かが変更されると、MyAdapterは完全に更新されずにそれに応じて変更されます
  6. 同じ項目タイプの完全に異なるセットを表示する場合は、binding変数を再設定するだけでよいので、BindingAdapterが再度呼び出され、MyAdapter項目が完全に変更されます。

たとえば、「所有ゲーム」と「ウィッシュリストゲーム」の2つの異なるリストがあるGameタイプのアイテムを表示する場合、binding.setItems(whateverItems)を呼び出すだけで表示アイテムを完全に更新できますが、たとえば、「ウィッシュリストゲーム」をリスト内で移動して関連性で整理すると、各リスト内でマイクロ変更のみが実行され、全体が更新されることはありません。

BindingAdapterに1つの変更が加えられるたびにデータバインディングがObservableListを再実行するため、このアイデアは実現不可能であることがわかります。たとえば、次のような動作が見られます。

  1. 空のMyAdapterから始めます
  2. アイテムがAPIからフェッチされたら、ObservableArrayListをインスタンス化してそれらをラップし、bindingに渡します
  3. データバインディングによってBindingAdapterが呼び出され、アイテムがMyAdapterに渡されます
  4. MyAdapterが新しいアイテムを受け取ると、古いアイテムをクリアし、受け取ったOnListChangedCallbackObservableListを追加して、マイクロ変更を処理します
  5. ObservableListで何かが変更されると、BindingAdapterが再度呼び出されるため、MyAdapterはリスト全体を再度受け取り、完全に更新されます。

ObservableListがデータバインドされたxml内で使用できないようにするため、この動作は私にはかなり壊れているようです。この振る舞いが望ましい正当なケースを真剣に理解することはできません。

私はいくつかの例を調べました: here および this other SO question

最初のリンクでは、すべての例でObservableListを直接Adapterに使用しましたが、フォームxmlおよび実際のデータバインディングを渡さなくても、SO回答でリンクされたコードでは、開発者は基本的に同じことを行いました私はやろうとしました:

_if (this.items == items){
        return;
}
_

ObservableListの単純な変更のためにメソッドが呼び出されるすべてのケースを破棄するために、彼のAdapter.setItems(ObservableList<T> items)の先頭に。

この動作の必要性は何ですか?この動作が望ましいいくつかのケースは何でしょうか? ObservableListはデータバインディングで追加された機能であり、実際のデータバインディングで使用する場合を除いて本当に便利です。その場合、その動作から保護する必要があります。 Listデータタグとxmlの両方のシグネチャで単純なBindingAdapterとして宣言すると、ObservableList内のMyAdapterにキャストバックでき、正常に機能しますが、これはかなり悪いハックです。それがデータバインディングとは別の機能であり、すべての変更でバインディングをトリガーしない場合、私の意見でははるかに優れていたでしょう。

26
Onheiron

ドキュメントで提供されている例によると https://developer.Android.com/topic/libraries/data-binding/index.html#observable_collections ObservableListは、キー整数を使用してアイテムにアクセスするために使用されます、つまり:

_<data>
    <import type="Android.databinding.ObservableList"/>
    <import type="com.example.my.app.Fields"/>
    <variable name="user" type="ObservableList&lt;Object&gt;"/>
</data>
…
<TextView
   Android:text='@{user[Fields.LAST_NAME]}'
   Android:layout_width="wrap_content"
   Android:layout_height="wrap_content"/>
_

したがって、ObservableList内で何かが変更されると、BindingAdapterがトリガーされてUIが更新されます。 DataBindingが開発状態にある間、これがObservableListを使用する主な目的だと思います。おそらく将来的には、DataBindingはRecyclerViewで使用するための新しいSomeObservableListで更新される予定です。その間、機能する場合はif (this.items == items){return;}を使用するか、ObservableListを使用するロジックを再検討できます。

1
Sergey