diff options
author | Samuel Holland <samuel@sholland.org> | 2017-08-07 19:46:19 -0500 |
---|---|---|
committer | Samuel Holland <samuel@sholland.org> | 2017-08-07 19:46:19 -0500 |
commit | 7d3e79684204e8df60eaf8d3985c22317f6594ef (patch) | |
tree | 642a162ba30bd2b4a0a0be556addfc68f2e767b9 /app/src/main/java/com/wireguard | |
parent | 2df899eae52591ff46819c960e129a2c698b201e (diff) |
ObservableArrayMapAdapter: Copy ObservableListAdapter
Since the conversion to a sequential list (to implement ListAdapter)
depends on the implementation detail that ObservableArrayMap is backed
by an array, we can't use the ObservableMap interface here.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'app/src/main/java/com/wireguard')
-rw-r--r-- | app/src/main/java/com/wireguard/android/BindingAdapters.java | 27 | ||||
-rw-r--r-- | app/src/main/java/com/wireguard/android/ObservableArrayMapAdapter.java | 84 |
2 files changed, 111 insertions, 0 deletions
diff --git a/app/src/main/java/com/wireguard/android/BindingAdapters.java b/app/src/main/java/com/wireguard/android/BindingAdapters.java index aa5b8c1e..77c6f657 100644 --- a/app/src/main/java/com/wireguard/android/BindingAdapters.java +++ b/app/src/main/java/com/wireguard/android/BindingAdapters.java @@ -1,6 +1,7 @@ package com.wireguard.android; import android.databinding.BindingAdapter; +import android.databinding.ObservableArrayMap; import android.databinding.ObservableList; import android.widget.ListView; @@ -10,6 +11,32 @@ import android.widget.ListView; public final class BindingAdapters { @BindingAdapter({"items", "layout"}) + public static <K, V> void arrayMapBinding(ListView view, ObservableArrayMap<K, V> oldMap, + int oldLayoutId, ObservableArrayMap<K, V> newMap, + int newLayoutId) { + // Remove any existing binding when there is no new map. + if (newMap == null) { + view.setAdapter(null); + return; + } + // The ListAdapter interface is not generic, so this cannot be checked. + @SuppressWarnings("unchecked") + ObservableArrayMapAdapter<K, V> adapter = + (ObservableArrayMapAdapter<K, V>) view.getAdapter(); + // If the layout changes, any existing adapter must be replaced. + if (newLayoutId != oldLayoutId) + adapter = null; + // Add a new binding if there was none, or if it must be replaced due to a layout change. + if (adapter == null) { + adapter = new ObservableArrayMapAdapter<>(view.getContext(), newLayoutId, newMap); + view.setAdapter(adapter); + } else if (newMap != oldMap) { + // Changing the list only requires modifying the existing adapter. + adapter.setMap(newMap); + } + } + + @BindingAdapter({"items", "layout"}) public static <T> void listBinding(ListView view, ObservableList<T> oldList, int oldLayoutId, ObservableList<T> newList, int newLayoutId) { // Remove any existing binding when there is no new list. diff --git a/app/src/main/java/com/wireguard/android/ObservableArrayMapAdapter.java b/app/src/main/java/com/wireguard/android/ObservableArrayMapAdapter.java new file mode 100644 index 00000000..d2a5a4cc --- /dev/null +++ b/app/src/main/java/com/wireguard/android/ObservableArrayMapAdapter.java @@ -0,0 +1,84 @@ +package com.wireguard.android; + +import android.content.Context; +import android.databinding.DataBindingUtil; +import android.databinding.ObservableArrayMap; +import android.databinding.ObservableMap; +import android.databinding.ViewDataBinding; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ListAdapter; + +import java.lang.ref.WeakReference; + +/** + * A generic ListAdapter backed by an ObservableMap. + */ + +class ObservableArrayMapAdapter<K, V> extends BaseAdapter implements ListAdapter { + private final int layoutId; + private final LayoutInflater layoutInflater; + private ObservableArrayMap<K, V> map; + private final OnMapChangedCallback<K, V> callback = new OnMapChangedCallback<>(this); + + ObservableArrayMapAdapter(Context context, int layoutId, ObservableArrayMap<K, V> map) { + this.layoutInflater = LayoutInflater.from(context); + this.layoutId = layoutId; + setMap(map); + } + + @Override + public int getCount() { + return map != null ? map.size() : 0; + } + + @Override + public V getItem(int position) { + return map != null ? map.get(map.keyAt(position)) : null; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + ViewDataBinding binding = DataBindingUtil.getBinding(convertView); + if (binding == null) + binding = DataBindingUtil.inflate(layoutInflater, layoutId, parent, false); + binding.setVariable(BR.item, getItem(position)); + binding.executePendingBindings(); + return binding.getRoot(); + } + + public void setMap(ObservableArrayMap<K, V> newMap) { + if (map != null) + map.removeOnMapChangedCallback(callback); + map = newMap; + if (map != null) { + map.addOnMapChangedCallback(callback); + } + } + + private static class OnMapChangedCallback<K, V> + extends ObservableMap.OnMapChangedCallback<ObservableMap<K, V>, K, V> { + + private final WeakReference<ObservableArrayMapAdapter<K, V>> weakAdapter; + + private OnMapChangedCallback(ObservableArrayMapAdapter<K, V> adapter) { + weakAdapter = new WeakReference<>(adapter); + } + + @Override + public void onMapChanged(ObservableMap<K, V> sender, K key) { + final ObservableArrayMapAdapter<K, V> adapter = weakAdapter.get(); + if (adapter != null) + adapter.notifyDataSetChanged(); + else + sender.removeOnMapChangedCallback(this); + } + } +} |