ObjectAdapter.java revision 13d1515a1edd63f26ad7f3c9c7471d0969900190
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 class DataObservable extends Observable<DataObserver> {
73        public boolean hasObservers() {
74            return !mObservers.isEmpty();
75        }
76
77        public void notifyChanged() {
78            for (int i = mObservers.size() - 1; i >= 0; i--) {
79                mObservers.get(i).onChanged();
80            }
81        }
82
83        public void notifyItemRangeChanged(int positionStart, int itemCount) {
84            for (int i = mObservers.size() - 1; i >= 0; i--) {
85                mObservers.get(i).onItemRangeChanged(positionStart, itemCount);
86            }
87        }
88
89        public void notifyItemRangeInserted(int positionStart, int itemCount) {
90            for (int i = mObservers.size() - 1; i >= 0; i--) {
91                mObservers.get(i).onItemRangeInserted(positionStart, itemCount);
92            }
93        }
94
95        public void notifyItemRangeRemoved(int positionStart, int itemCount) {
96            for (int i = mObservers.size() - 1; i >= 0; i--) {
97                mObservers.get(i).onItemRangeRemoved(positionStart, itemCount);
98            }
99        }
100    }
101
102    private final DataObservable mObservable = new DataObservable();
103    private boolean mHasStableIds;
104    private PresenterSelector mPresenterSelector;
105
106    /**
107     * Construct an adapter with the given {@link PresenterSelector}.
108     */
109    public ObjectAdapter(PresenterSelector presenterSelector) {
110        setPresenterSelector(presenterSelector);
111    }
112
113    /**
114     * Construct an adapter that uses the given {@link Presenter} for all items.
115     */
116    public ObjectAdapter(Presenter presenter) {
117        setPresenterSelector(new SinglePresenterSelector(presenter));
118    }
119
120    /**
121     * Construct an adapter.
122     */
123    public ObjectAdapter() {
124    }
125
126    /**
127     * Set the presenter selector.  May not be null.
128     */
129    public void setPresenterSelector(PresenterSelector presenterSelector) {
130        if (presenterSelector == null) {
131            throw new IllegalArgumentException("Presenter selector must not be null");
132        }
133        final boolean update = (mPresenterSelector != null);
134        mPresenterSelector = presenterSelector;
135        if (update) {
136            notifyChanged();
137        }
138    }
139
140    /**
141     * Returns the presenter selector;
142     */
143    public PresenterSelector getPresenterSelector() {
144        return mPresenterSelector;
145    }
146
147    /**
148     * Register a DataObserver for data change notifications.
149     */
150    public void registerObserver(DataObserver observer) {
151        mObservable.registerObserver(observer);
152    }
153
154    /**
155     * Unregister a DataObserver for data change notifications.
156     */
157    public void unregisterObserver(DataObserver observer) {
158        mObservable.unregisterObserver(observer);
159    }
160
161    /**
162     * Unregister all DataObservers for this ObservableList.
163     */
164    public void unregisterAllObservers() {
165        mObservable.unregisterAll();
166    }
167
168    final protected void notifyItemRangeChanged(int positionStart, int itemCount) {
169        mObservable.notifyItemRangeChanged(positionStart, itemCount);
170    }
171
172    final protected void notifyItemRangeInserted(int positionStart, int itemCount) {
173        mObservable.notifyItemRangeInserted(positionStart, itemCount);
174    }
175
176    final protected void notifyItemRangeRemoved(int positionStart, int itemCount) {
177        mObservable.notifyItemRangeRemoved(positionStart, itemCount);
178    }
179
180    final protected void notifyChanged() {
181        mObservable.notifyChanged();
182    }
183
184    /**
185     * Indicates whether the item ids are stable across changes to the
186     * underlying data.  When this is true, client of Adapter can use
187     * {@link #getId(int)} to correlate objects across changes.
188     */
189    public boolean hasStableIds() {
190        return mHasStableIds;
191    }
192
193    /**
194     * Sets whether the item ids are stable across changes to the underlying
195     * data.
196     */
197    public void setHasStableIds(boolean hasStableIds) {
198        mHasStableIds = hasStableIds;
199    }
200
201    /**
202     * Returns the {@link Presenter} for the given item from the adapter.
203     */
204    public Presenter getPresenter(Object item) {
205        if (mPresenterSelector == null) {
206            throw new IllegalStateException("Presenter selector must not be null");
207        }
208        return mPresenterSelector.getPresenter(item);
209    }
210
211    /**
212     * Returns the number of items in the adapter.
213     */
214    public abstract int size();
215
216    /**
217     * Returns the item for the given position.
218     */
219    public abstract Object get(int position);
220
221    /**
222     * Returns id for the given position.
223     */
224    public long getId(int position) {
225        return NO_ID;
226    }
227}
228