ObjectAdapter.java revision b3451baf39c3b17972e7826baee90be4b1cd2626
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14package android.support.v17.leanback.widget; 15 16import android.database.Observable; 17 18/** 19 * Adapter for leanback activities. Provides access to a data model and is 20 * decoupled from the presentation of the items via {@link PresenterSelector}. 21 */ 22public abstract class ObjectAdapter { 23 24 public static final int NO_ID = -1; 25 26 /** 27 * A DataObserver can be notified when an ObjectAdapter's underlying data 28 * changes. Separate methods provide notifications about different types of 29 * changes. 30 */ 31 public static abstract class DataObserver { 32 /** 33 * Called whenever the ObjectAdapter's data has changed in some manner 34 * outside of the set of changes covered by the other range based change 35 * notification methods. 36 */ 37 public void onChanged() { 38 } 39 40 /** 41 * Called when a range of items in the ObjectAdapter has changed. The 42 * basic ordering and structure of the ObjectAdapter has not changed. 43 * 44 * @param positionStart The position of the first item that changed. 45 * @param itemCount The number of items changed. 46 */ 47 public void onItemRangeChanged(int positionStart, int itemCount) { 48 onChanged(); 49 } 50 51 /** 52 * Called when a range of items is inserted into the ObjectAdapter. 53 * 54 * @param positionStart The position of the first inserted item. 55 * @param itemCount The number of items inserted. 56 */ 57 public void onItemRangeInserted(int positionStart, int itemCount) { 58 onChanged(); 59 } 60 61 /** 62 * Called when a range of items is removed from the ObjectAdapter. 63 * 64 * @param positionStart The position of the first removed item. 65 * @param itemCount The number of items removed. 66 */ 67 public void onItemRangeRemoved(int positionStart, int itemCount) { 68 onChanged(); 69 } 70 } 71 72 private static final class DataObservable extends Observable<DataObserver> { 73 74 public void notifyChanged() { 75 for (int i = mObservers.size() - 1; i >= 0; i--) { 76 mObservers.get(i).onChanged(); 77 } 78 } 79 80 public void notifyItemRangeChanged(int positionStart, int itemCount) { 81 for (int i = mObservers.size() - 1; i >= 0; i--) { 82 mObservers.get(i).onItemRangeChanged(positionStart, itemCount); 83 } 84 } 85 86 public void notifyItemRangeInserted(int positionStart, int itemCount) { 87 for (int i = mObservers.size() - 1; i >= 0; i--) { 88 mObservers.get(i).onItemRangeInserted(positionStart, itemCount); 89 } 90 } 91 92 public void notifyItemRangeRemoved(int positionStart, int itemCount) { 93 for (int i = mObservers.size() - 1; i >= 0; i--) { 94 mObservers.get(i).onItemRangeRemoved(positionStart, itemCount); 95 } 96 } 97 } 98 99 private final DataObservable mObservable = new DataObservable(); 100 private boolean mHasStableIds; 101 private PresenterSelector mPresenterSelector; 102 103 /** 104 * Construct an adapter with the given {@link PresenterSelector}. 105 */ 106 public ObjectAdapter(PresenterSelector presenterSelector) { 107 setPresenterSelector(presenterSelector); 108 } 109 110 /** 111 * Construct an adapter that uses the given {@link Presenter} for all items. 112 */ 113 public ObjectAdapter(Presenter presenter) { 114 setPresenterSelector(new SinglePresenterSelector(presenter)); 115 } 116 117 /** 118 * Construct an adapter. 119 */ 120 public ObjectAdapter() { 121 } 122 123 /** 124 * Set the presenter selector. May not be null. 125 */ 126 public final void setPresenterSelector(PresenterSelector presenterSelector) { 127 if (presenterSelector == null) { 128 throw new IllegalArgumentException("Presenter selector must not be null"); 129 } 130 final boolean update = (mPresenterSelector != null); 131 final boolean selectorChanged = update && mPresenterSelector != presenterSelector; 132 133 mPresenterSelector = presenterSelector; 134 135 if (selectorChanged) { 136 onPresenterSelectorChanged(); 137 } 138 if (update) { 139 notifyChanged(); 140 } 141 } 142 143 /** 144 * Called when {@link #setPresenterSelector(PresenterSelector)} is called 145 * and the PresenterSelector differs from the previous one. 146 */ 147 protected void onPresenterSelectorChanged() { 148 } 149 150 /** 151 * Returns the presenter selector; 152 */ 153 public final PresenterSelector getPresenterSelector() { 154 return mPresenterSelector; 155 } 156 157 /** 158 * Register a DataObserver for data change notifications. 159 */ 160 public final void registerObserver(DataObserver observer) { 161 mObservable.registerObserver(observer); 162 } 163 164 /** 165 * Unregister a DataObserver for data change notifications. 166 */ 167 public final void unregisterObserver(DataObserver observer) { 168 mObservable.unregisterObserver(observer); 169 } 170 171 /** 172 * Unregister all DataObservers for this ObservableList. 173 */ 174 public final void unregisterAllObservers() { 175 mObservable.unregisterAll(); 176 } 177 178 final protected void notifyItemRangeChanged(int positionStart, int itemCount) { 179 mObservable.notifyItemRangeChanged(positionStart, itemCount); 180 } 181 182 final protected void notifyItemRangeInserted(int positionStart, int itemCount) { 183 mObservable.notifyItemRangeInserted(positionStart, itemCount); 184 } 185 186 final protected void notifyItemRangeRemoved(int positionStart, int itemCount) { 187 mObservable.notifyItemRangeRemoved(positionStart, itemCount); 188 } 189 190 final protected void notifyChanged() { 191 mObservable.notifyChanged(); 192 } 193 194 /** 195 * Indicates whether the item ids are stable across changes to the 196 * underlying data. When this is true, client of Adapter can use 197 * {@link #getId(int)} to correlate objects across changes. 198 */ 199 public final boolean hasStableIds() { 200 return mHasStableIds; 201 } 202 203 /** 204 * Sets whether the item ids are stable across changes to the underlying 205 * data. 206 */ 207 public final void setHasStableIds(boolean hasStableIds) { 208 boolean changed = mHasStableIds != hasStableIds; 209 mHasStableIds = hasStableIds; 210 211 if (changed) { 212 onHasStableIdsChanged(); 213 } 214 } 215 216 /** 217 * Called when {@link #setHasStableIds(boolean)} is called and the status 218 * of stable ids has changed. 219 */ 220 protected void onHasStableIdsChanged() { 221 } 222 223 /** 224 * Returns the {@link Presenter} for the given item from the adapter. 225 */ 226 public final Presenter getPresenter(Object item) { 227 if (mPresenterSelector == null) { 228 throw new IllegalStateException("Presenter selector must not be null"); 229 } 230 return mPresenterSelector.getPresenter(item); 231 } 232 233 /** 234 * Returns the number of items in the adapter. 235 */ 236 public abstract int size(); 237 238 /** 239 * Returns the item for the given position. 240 */ 241 public abstract Object get(int position); 242 243 /** 244 * Returns id for the given position. 245 */ 246 public long getId(int position) { 247 return NO_ID; 248 } 249} 250