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