From c73287f64bc575672aed325cc029b26b1cf72202 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 6 Jan 2018 03:58:43 -0600 Subject: [PATCH] databinding: Add an adapter for the KeyedObservableList This adapter actually finally implements stable IDs correctly. Signed-off-by: Samuel Holland --- .../KeyedObservableListAdapter.java | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 app/src/main/java/com/wireguard/android/databinding/KeyedObservableListAdapter.java diff --git a/app/src/main/java/com/wireguard/android/databinding/KeyedObservableListAdapter.java b/app/src/main/java/com/wireguard/android/databinding/KeyedObservableListAdapter.java new file mode 100644 index 00000000..d1d377aa --- /dev/null +++ b/app/src/main/java/com/wireguard/android/databinding/KeyedObservableListAdapter.java @@ -0,0 +1,127 @@ +package com.wireguard.android.databinding; + +import android.content.Context; +import android.databinding.DataBindingUtil; +import android.databinding.ObservableList; +import android.databinding.ViewDataBinding; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import com.wireguard.android.BR; +import com.wireguard.android.util.Keyed; +import com.wireguard.android.util.KeyedObservableList; + +import java.lang.ref.WeakReference; + +/** + * A generic {@code ListAdapter} backed by a {@code KeyedObservableList}. + */ + +class KeyedObservableListAdapter> extends BaseAdapter { + private final OnListChangedCallback callback = new OnListChangedCallback<>(this); + private final int layoutId; + private final LayoutInflater layoutInflater; + private KeyedObservableList list; + + KeyedObservableListAdapter(final Context context, final int layoutId, + final KeyedObservableList list) { + this.layoutId = layoutId; + layoutInflater = LayoutInflater.from(context); + setList(list); + } + + @Override + public int getCount() { + return list != null ? list.size() : 0; + } + + @Override + public E getItem(final int position) { + if (list == null || position < 0 || position >= list.size()) + return null; + return list.get(position); + } + + @Override + public long getItemId(final int position) { + final K key = getKey(position); + return key != null ? key.hashCode() : -1; + } + + private K getKey(final int position) { + final E item = getItem(position); + return item != null ? item.getKey() : null; + } + + @Override + public View getView(final int position, final View convertView, final ViewGroup parent) { + ViewDataBinding binding = DataBindingUtil.getBinding(convertView); + if (binding == null) + binding = DataBindingUtil.inflate(layoutInflater, layoutId, parent, false); + binding.setVariable(BR.collection, list); + binding.setVariable(BR.key, getKey(position)); + binding.setVariable(BR.item, getItem(position)); + binding.executePendingBindings(); + return binding.getRoot(); + } + + @Override + public boolean hasStableIds() { + return true; + } + + void setList(final KeyedObservableList newList) { + if (list != null) + list.removeOnListChangedCallback(callback); + list = newList; + if (list != null) { + list.addOnListChangedCallback(callback); + } + notifyDataSetChanged(); + } + + private static final class OnListChangedCallback> + extends ObservableList.OnListChangedCallback> { + + private final WeakReference> weakAdapter; + + private OnListChangedCallback(final KeyedObservableListAdapter adapter) { + weakAdapter = new WeakReference<>(adapter); + } + + @Override + public void onChanged(final ObservableList sender) { + final KeyedObservableListAdapter adapter = weakAdapter.get(); + if (adapter != null) + adapter.notifyDataSetChanged(); + else + sender.removeOnListChangedCallback(this); + } + + @Override + public void onItemRangeChanged(final ObservableList sender, final int positionStart, + final int itemCount) { + onChanged(sender); + } + + @Override + public void onItemRangeInserted(final ObservableList sender, final int positionStart, + final int itemCount) { + onChanged(sender); + } + + @Override + public void onItemRangeMoved(final ObservableList sender, final int fromPosition, + final int toPosition, final int itemCount) { + onChanged(sender); + } + + @Override + public void onItemRangeRemoved(final ObservableList sender, final int positionStart, + final int itemCount) { + onChanged(sender); + } + } +}