ObjectAdapter.java revision 99ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0d
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 * Base class adapter to be used in 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 /** Indicates that an id has not been set. */ 25 public static final int NO_ID = -1; 26 27 /** 28 * A DataObserver can be notified when an ObjectAdapter's underlying data 29 * changes. Separate methods provide notifications about different types of 30 * changes. 31 */ 32 public static abstract class DataObserver { 33 /** 34 * Called whenever the ObjectAdapter's data has changed in some manner 35 * outside of the set of changes covered by the other range-based change 36 * notification methods. 37 */ 38 public void onChanged() { 39 } 40 41 /** 42 * Called when a range of items in the ObjectAdapter has changed. The 43 * basic ordering and structure of the ObjectAdapter has not changed. 44 * 45 * @param positionStart The position of the first item that changed. 46 * @param itemCount The number of items changed. 47 */ 48 public void onItemRangeChanged(int positionStart, int itemCount) { 49 onChanged(); 50 } 51 52 /** 53 * Called when a range of items is inserted into the ObjectAdapter. 54 * 55 * @param positionStart The position of the first inserted item. 56 * @param itemCount The number of items inserted. 57 */ 58 public void onItemRangeInserted(int positionStart, int itemCount) { 59 onChanged(); 60 } 61 62 /** 63 * Called when a range of items is removed from the ObjectAdapter. 64 * 65 * @param positionStart The position of the first removed item. 66 * @param itemCount The number of items removed. 67 */ 68 public void onItemRangeRemoved(int positionStart, int itemCount) { 69 onChanged(); 70 } 71 } 72 73 private static final class DataObservable extends Observable<DataObserver> { 74 75 DataObservable() { 76 } 77 78 public void notifyChanged() { 79 for (int i = mObservers.size() - 1; i >= 0; i--) { 80 mObservers.get(i).onChanged(); 81 } 82 } 83 84 public void notifyItemRangeChanged(int positionStart, int itemCount) { 85 for (int i = mObservers.size() - 1; i >= 0; i--) { 86 mObservers.get(i).onItemRangeChanged(positionStart, itemCount); 87 } 88 } 89 90 public void notifyItemRangeInserted(int positionStart, int itemCount) { 91 for (int i = mObservers.size() - 1; i >= 0; i--) { 92 mObservers.get(i).onItemRangeInserted(positionStart, itemCount); 93 } 94 } 95 96 public void notifyItemRangeRemoved(int positionStart, int itemCount) { 97 for (int i = mObservers.size() - 1; i >= 0; i--) { 98 mObservers.get(i).onItemRangeRemoved(positionStart, itemCount); 99 } 100 } 101 } 102 103 private final DataObservable mObservable = new DataObservable(); 104 private boolean mHasStableIds; 105 private PresenterSelector mPresenterSelector; 106 107 /** 108 * Constructs an adapter with the given {@link PresenterSelector}. 109 */ 110 public ObjectAdapter(PresenterSelector presenterSelector) { 111 setPresenterSelector(presenterSelector); 112 } 113 114 /** 115 * Constructs an adapter that uses the given {@link Presenter} for all items. 116 */ 117 public ObjectAdapter(Presenter presenter) { 118 setPresenterSelector(new SinglePresenterSelector(presenter)); 119 } 120 121 /** 122 * Constructs an adapter. 123 */ 124 public ObjectAdapter() { 125 } 126 127 /** 128 * Sets the presenter selector. May not be null. 129 */ 130 public final void setPresenterSelector(PresenterSelector presenterSelector) { 131 if (presenterSelector == null) { 132 throw new IllegalArgumentException("Presenter selector must not be null"); 133 } 134 final boolean update = (mPresenterSelector != null); 135 final boolean selectorChanged = update && mPresenterSelector != presenterSelector; 136 137 mPresenterSelector = presenterSelector; 138 139 if (selectorChanged) { 140 onPresenterSelectorChanged(); 141 } 142 if (update) { 143 notifyChanged(); 144 } 145 } 146 147 /** 148 * Called when {@link #setPresenterSelector(PresenterSelector)} is called 149 * and the PresenterSelector differs from the previous one. 150 */ 151 protected void onPresenterSelectorChanged() { 152 } 153 154 /** 155 * Returns the presenter selector for this ObjectAdapter. 156 */ 157 public final PresenterSelector getPresenterSelector() { 158 return mPresenterSelector; 159 } 160 161 /** 162 * Registers a DataObserver for data change notifications. 163 */ 164 public final void registerObserver(DataObserver observer) { 165 mObservable.registerObserver(observer); 166 } 167 168 /** 169 * Unregisters a DataObserver for data change notifications. 170 */ 171 public final void unregisterObserver(DataObserver observer) { 172 mObservable.unregisterObserver(observer); 173 } 174 175 /** 176 * Unregisters all DataObservers for this ObjectAdapter. 177 */ 178 public final void unregisterAllObservers() { 179 mObservable.unregisterAll(); 180 } 181 182 final protected void notifyItemRangeChanged(int positionStart, int itemCount) { 183 mObservable.notifyItemRangeChanged(positionStart, itemCount); 184 } 185 186 final protected void notifyItemRangeInserted(int positionStart, int itemCount) { 187 mObservable.notifyItemRangeInserted(positionStart, itemCount); 188 } 189 190 final protected void notifyItemRangeRemoved(int positionStart, int itemCount) { 191 mObservable.notifyItemRangeRemoved(positionStart, itemCount); 192 } 193 194 final protected void notifyChanged() { 195 mObservable.notifyChanged(); 196 } 197 198 /** 199 * Returns true if the item ids are stable across changes to the 200 * underlying data. When this is true, clients of the ObjectAdapter can use 201 * {@link #getId(int)} to correlate Objects across changes. 202 */ 203 public final boolean hasStableIds() { 204 return mHasStableIds; 205 } 206 207 /** 208 * Sets whether the item ids are stable across changes to the underlying 209 * data. 210 */ 211 public final void setHasStableIds(boolean hasStableIds) { 212 boolean changed = mHasStableIds != hasStableIds; 213 mHasStableIds = hasStableIds; 214 215 if (changed) { 216 onHasStableIdsChanged(); 217 } 218 } 219 220 /** 221 * Called when {@link #setHasStableIds(boolean)} is called and the status 222 * of stable ids has changed. 223 */ 224 protected void onHasStableIdsChanged() { 225 } 226 227 /** 228 * Returns the {@link Presenter} for the given item from the adapter. 229 */ 230 public final Presenter getPresenter(Object item) { 231 if (mPresenterSelector == null) { 232 throw new IllegalStateException("Presenter selector must not be null"); 233 } 234 return mPresenterSelector.getPresenter(item); 235 } 236 237 /** 238 * Returns the number of items in the adapter. 239 */ 240 public abstract int size(); 241 242 /** 243 * Returns the item for the given position. 244 */ 245 public abstract Object get(int position); 246 247 /** 248 * Returns the id for the given position. 249 */ 250 public long getId(int position) { 251 return NO_ID; 252 } 253 254 /** 255 * Returns true if the adapter pairs each underlying data change with a call to notify and 256 * false otherwise. 257 */ 258 public boolean isImmediateNotifySupported() { 259 return false; 260 } 261} 262