• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
14 package android.support.v17.leanback.widget;
15 
16 import 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  */
22 public 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          */
onChanged()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          */
onItemRangeChanged(int positionStart, int itemCount)48         public void onItemRangeChanged(int positionStart, int itemCount) {
49             onChanged();
50         }
51 
52         /**
53          * Called when a range of items in the ObjectAdapter has changed. The
54          * basic ordering and structure of the ObjectAdapter has not changed.
55          *
56          * @param positionStart The position of the first item that changed.
57          * @param itemCount     The number of items changed.
58          * @param payload       Optional parameter, use null to identify a "full" update.
59          */
onItemRangeChanged(int positionStart, int itemCount, Object payload)60         public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
61             onChanged();
62         }
63 
64         /**
65          * Called when a range of items is inserted into the ObjectAdapter.
66          *
67          * @param positionStart The position of the first inserted item.
68          * @param itemCount     The number of items inserted.
69          */
onItemRangeInserted(int positionStart, int itemCount)70         public void onItemRangeInserted(int positionStart, int itemCount) {
71             onChanged();
72         }
73 
74         /**
75          * Called when an item is moved from one position to another position
76          *
77          * @param fromPosition Previous position of the item.
78          * @param toPosition   New position of the item.
79          */
onItemMoved(int fromPosition, int toPosition)80         public void onItemMoved(int fromPosition, int toPosition) {
81             onChanged();
82         }
83 
84         /**
85          * Called when a range of items is removed from the ObjectAdapter.
86          *
87          * @param positionStart The position of the first removed item.
88          * @param itemCount     The number of items removed.
89          */
onItemRangeRemoved(int positionStart, int itemCount)90         public void onItemRangeRemoved(int positionStart, int itemCount) {
91             onChanged();
92         }
93     }
94 
95     private static final class DataObservable extends Observable<DataObserver> {
96 
DataObservable()97         DataObservable() {
98         }
99 
notifyChanged()100         public void notifyChanged() {
101             for (int i = mObservers.size() - 1; i >= 0; i--) {
102                 mObservers.get(i).onChanged();
103             }
104         }
105 
notifyItemRangeChanged(int positionStart, int itemCount)106         public void notifyItemRangeChanged(int positionStart, int itemCount) {
107             for (int i = mObservers.size() - 1; i >= 0; i--) {
108                 mObservers.get(i).onItemRangeChanged(positionStart, itemCount);
109             }
110         }
111 
notifyItemRangeChanged(int positionStart, int itemCount, Object payload)112         public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
113             for (int i = mObservers.size() - 1; i >= 0; i--) {
114                 mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload);
115             }
116         }
117 
notifyItemRangeInserted(int positionStart, int itemCount)118         public void notifyItemRangeInserted(int positionStart, int itemCount) {
119             for (int i = mObservers.size() - 1; i >= 0; i--) {
120                 mObservers.get(i).onItemRangeInserted(positionStart, itemCount);
121             }
122         }
123 
notifyItemRangeRemoved(int positionStart, int itemCount)124         public void notifyItemRangeRemoved(int positionStart, int itemCount) {
125             for (int i = mObservers.size() - 1; i >= 0; i--) {
126                 mObservers.get(i).onItemRangeRemoved(positionStart, itemCount);
127             }
128         }
129 
notifyItemMoved(int positionStart, int toPosition)130         public void notifyItemMoved(int positionStart, int toPosition) {
131             for (int i = mObservers.size() - 1; i >= 0; i--) {
132                 mObservers.get(i).onItemMoved(positionStart, toPosition);
133             }
134         }
135     }
136 
137     private final DataObservable mObservable = new DataObservable();
138     private boolean mHasStableIds;
139     private PresenterSelector mPresenterSelector;
140 
141     /**
142      * Constructs an adapter with the given {@link PresenterSelector}.
143      */
ObjectAdapter(PresenterSelector presenterSelector)144     public ObjectAdapter(PresenterSelector presenterSelector) {
145         setPresenterSelector(presenterSelector);
146     }
147 
148     /**
149      * Constructs an adapter that uses the given {@link Presenter} for all items.
150      */
ObjectAdapter(Presenter presenter)151     public ObjectAdapter(Presenter presenter) {
152         setPresenterSelector(new SinglePresenterSelector(presenter));
153     }
154 
155     /**
156      * Constructs an adapter.
157      */
ObjectAdapter()158     public ObjectAdapter() {
159     }
160 
161     /**
162      * Sets the presenter selector.  May not be null.
163      */
setPresenterSelector(PresenterSelector presenterSelector)164     public final void setPresenterSelector(PresenterSelector presenterSelector) {
165         if (presenterSelector == null) {
166             throw new IllegalArgumentException("Presenter selector must not be null");
167         }
168         final boolean update = (mPresenterSelector != null);
169         final boolean selectorChanged = update && mPresenterSelector != presenterSelector;
170 
171         mPresenterSelector = presenterSelector;
172 
173         if (selectorChanged) {
174             onPresenterSelectorChanged();
175         }
176         if (update) {
177             notifyChanged();
178         }
179     }
180 
181     /**
182      * Called when {@link #setPresenterSelector(PresenterSelector)} is called
183      * and the PresenterSelector differs from the previous one.
184      */
onPresenterSelectorChanged()185     protected void onPresenterSelectorChanged() {
186     }
187 
188     /**
189      * Returns the presenter selector for this ObjectAdapter.
190      */
getPresenterSelector()191     public final PresenterSelector getPresenterSelector() {
192         return mPresenterSelector;
193     }
194 
195     /**
196      * Registers a DataObserver for data change notifications.
197      */
registerObserver(DataObserver observer)198     public final void registerObserver(DataObserver observer) {
199         mObservable.registerObserver(observer);
200     }
201 
202     /**
203      * Unregisters a DataObserver for data change notifications.
204      */
unregisterObserver(DataObserver observer)205     public final void unregisterObserver(DataObserver observer) {
206         mObservable.unregisterObserver(observer);
207     }
208 
209     /**
210      * Unregisters all DataObservers for this ObjectAdapter.
211      */
unregisterAllObservers()212     public final void unregisterAllObservers() {
213         mObservable.unregisterAll();
214     }
215 
216     /**
217      * Notifies UI that some items has changed.
218      *
219      * @param positionStart Starting position of the changed items.
220      * @param itemCount     Total number of items that changed.
221      */
notifyItemRangeChanged(int positionStart, int itemCount)222     public final void notifyItemRangeChanged(int positionStart, int itemCount) {
223         mObservable.notifyItemRangeChanged(positionStart, itemCount);
224     }
225 
226     /**
227      * Notifies UI that some items has changed.
228      *
229      * @param positionStart Starting position of the changed items.
230      * @param itemCount     Total number of items that changed.
231      * @param payload       Optional parameter, use null to identify a "full" update.
232      */
notifyItemRangeChanged(int positionStart, int itemCount, Object payload)233     public final void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
234         mObservable.notifyItemRangeChanged(positionStart, itemCount, payload);
235     }
236 
237     /**
238      * Notifies UI that new items has been inserted.
239      *
240      * @param positionStart Position where new items has been inserted.
241      * @param itemCount     Count of the new items has been inserted.
242      */
notifyItemRangeInserted(int positionStart, int itemCount)243     final protected void notifyItemRangeInserted(int positionStart, int itemCount) {
244         mObservable.notifyItemRangeInserted(positionStart, itemCount);
245     }
246 
247     /**
248      * Notifies UI that some items that has been removed.
249      *
250      * @param positionStart Starting position of the removed items.
251      * @param itemCount     Total number of items that has been removed.
252      */
notifyItemRangeRemoved(int positionStart, int itemCount)253     final protected void notifyItemRangeRemoved(int positionStart, int itemCount) {
254         mObservable.notifyItemRangeRemoved(positionStart, itemCount);
255     }
256 
257     /**
258      * Notifies UI that item at fromPosition has been moved to toPosition.
259      *
260      * @param fromPosition Previous position of the item.
261      * @param toPosition   New position of the item.
262      */
notifyItemMoved(int fromPosition, int toPosition)263     protected final void notifyItemMoved(int fromPosition, int toPosition) {
264         mObservable.notifyItemMoved(fromPosition, toPosition);
265     }
266 
267     /**
268      * Notifies UI that the underlying data has changed.
269      */
notifyChanged()270     final protected void notifyChanged() {
271         mObservable.notifyChanged();
272     }
273 
274     /**
275      * Returns true if the item ids are stable across changes to the
276      * underlying data.  When this is true, clients of the ObjectAdapter can use
277      * {@link #getId(int)} to correlate Objects across changes.
278      */
hasStableIds()279     public final boolean hasStableIds() {
280         return mHasStableIds;
281     }
282 
283     /**
284      * Sets whether the item ids are stable across changes to the underlying
285      * data.
286      */
setHasStableIds(boolean hasStableIds)287     public final void setHasStableIds(boolean hasStableIds) {
288         boolean changed = mHasStableIds != hasStableIds;
289         mHasStableIds = hasStableIds;
290 
291         if (changed) {
292             onHasStableIdsChanged();
293         }
294     }
295 
296     /**
297      * Called when {@link #setHasStableIds(boolean)} is called and the status
298      * of stable ids has changed.
299      */
onHasStableIdsChanged()300     protected void onHasStableIdsChanged() {
301     }
302 
303     /**
304      * Returns the {@link Presenter} for the given item from the adapter.
305      */
getPresenter(Object item)306     public final Presenter getPresenter(Object item) {
307         if (mPresenterSelector == null) {
308             throw new IllegalStateException("Presenter selector must not be null");
309         }
310         return mPresenterSelector.getPresenter(item);
311     }
312 
313     /**
314      * Returns the number of items in the adapter.
315      */
size()316     public abstract int size();
317 
318     /**
319      * Returns the item for the given position.
320      */
get(int position)321     public abstract Object get(int position);
322 
323     /**
324      * Returns the id for the given position.
325      */
getId(int position)326     public long getId(int position) {
327         return NO_ID;
328     }
329 
330     /**
331      * Returns true if the adapter pairs each underlying data change with a call to notify and
332      * false otherwise.
333      */
isImmediateNotifySupported()334     public boolean isImmediateNotifySupported() {
335         return false;
336     }
337 }
338