blob: c464814b5638ceb34b50f832cc2282d919e8afb8 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package android.support.v17.leanback.widget;
import android.database.Observable;
/**
* Base class adapter to be used in leanback activities. Provides access to a data model and is
* decoupled from the presentation of the items via {@link PresenterSelector}.
*/
public abstract class ObjectAdapter {
/** Indicates that an id has not been set. */
public static final int NO_ID = -1;
/**
* A DataObserver can be notified when an ObjectAdapter's underlying data
* changes. Separate methods provide notifications about different types of
* changes.
*/
public static abstract class DataObserver {
/**
* Called whenever the ObjectAdapter's data has changed in some manner
* outside of the set of changes covered by the other range-based change
* notification methods.
*/
public void onChanged() {
}
/**
* Called when a range of items in the ObjectAdapter has changed. The
* basic ordering and structure of the ObjectAdapter has not changed.
*
* @param positionStart The position of the first item that changed.
* @param itemCount The number of items changed.
*/
public void onItemRangeChanged(int positionStart, int itemCount) {
onChanged();
}
/**
* Called when a range of items is inserted into the ObjectAdapter.
*
* @param positionStart The position of the first inserted item.
* @param itemCount The number of items inserted.
*/
public void onItemRangeInserted(int positionStart, int itemCount) {
onChanged();
}
/**
* Called when a range of items is removed from the ObjectAdapter.
*
* @param positionStart The position of the first removed item.
* @param itemCount The number of items removed.
*/
public void onItemRangeRemoved(int positionStart, int itemCount) {
onChanged();
}
}
private static final class DataObservable extends Observable<DataObserver> {
public void notifyChanged() {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
public void notifyItemRangeChanged(int positionStart, int itemCount) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onItemRangeChanged(positionStart, itemCount);
}
}
public void notifyItemRangeInserted(int positionStart, int itemCount) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onItemRangeInserted(positionStart, itemCount);
}
}
public void notifyItemRangeRemoved(int positionStart, int itemCount) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onItemRangeRemoved(positionStart, itemCount);
}
}
}
private final DataObservable mObservable = new DataObservable();
private boolean mHasStableIds;
private PresenterSelector mPresenterSelector;
/**
* Constructs an adapter with the given {@link PresenterSelector}.
*/
public ObjectAdapter(PresenterSelector presenterSelector) {
setPresenterSelector(presenterSelector);
}
/**
* Constructs an adapter that uses the given {@link Presenter} for all items.
*/
public ObjectAdapter(Presenter presenter) {
setPresenterSelector(new SinglePresenterSelector(presenter));
}
/**
* Constructs an adapter.
*/
public ObjectAdapter() {
}
/**
* Sets the presenter selector. May not be null.
*/
public final void setPresenterSelector(PresenterSelector presenterSelector) {
if (presenterSelector == null) {
throw new IllegalArgumentException("Presenter selector must not be null");
}
final boolean update = (mPresenterSelector != null);
final boolean selectorChanged = update && mPresenterSelector != presenterSelector;
mPresenterSelector = presenterSelector;
if (selectorChanged) {
onPresenterSelectorChanged();
}
if (update) {
notifyChanged();
}
}
/**
* Called when {@link #setPresenterSelector(PresenterSelector)} is called
* and the PresenterSelector differs from the previous one.
*/
protected void onPresenterSelectorChanged() {
}
/**
* Returns the presenter selector for this ObjectAdapter.
*/
public final PresenterSelector getPresenterSelector() {
return mPresenterSelector;
}
/**
* Registers a DataObserver for data change notifications.
*/
public final void registerObserver(DataObserver observer) {
mObservable.registerObserver(observer);
}
/**
* Unregisters a DataObserver for data change notifications.
*/
public final void unregisterObserver(DataObserver observer) {
mObservable.unregisterObserver(observer);
}
/**
* Unregisters all DataObservers for this ObjectAdapter.
*/
public final void unregisterAllObservers() {
mObservable.unregisterAll();
}
final protected void notifyItemRangeChanged(int positionStart, int itemCount) {
mObservable.notifyItemRangeChanged(positionStart, itemCount);
}
final protected void notifyItemRangeInserted(int positionStart, int itemCount) {
mObservable.notifyItemRangeInserted(positionStart, itemCount);
}
final protected void notifyItemRangeRemoved(int positionStart, int itemCount) {
mObservable.notifyItemRangeRemoved(positionStart, itemCount);
}
final protected void notifyChanged() {
mObservable.notifyChanged();
}
/**
* Returns true if the item ids are stable across changes to the
* underlying data. When this is true, clients of the ObjectAdapter can use
* {@link #getId(int)} to correlate Objects across changes.
*/
public final boolean hasStableIds() {
return mHasStableIds;
}
/**
* Sets whether the item ids are stable across changes to the underlying
* data.
*/
public final void setHasStableIds(boolean hasStableIds) {
boolean changed = mHasStableIds != hasStableIds;
mHasStableIds = hasStableIds;
if (changed) {
onHasStableIdsChanged();
}
}
/**
* Called when {@link #setHasStableIds(boolean)} is called and the status
* of stable ids has changed.
*/
protected void onHasStableIdsChanged() {
}
/**
* Returns the {@link Presenter} for the given item from the adapter.
*/
public final Presenter getPresenter(Object item) {
if (mPresenterSelector == null) {
throw new IllegalStateException("Presenter selector must not be null");
}
return mPresenterSelector.getPresenter(item);
}
/**
* Returns the number of items in the adapter.
*/
public abstract int size();
/**
* Returns the item for the given position.
*/
public abstract Object get(int position);
/**
* Returns the id for the given position.
*/
public long getId(int position) {
return NO_ID;
}
/**
* Returns true if the adapter pairs each underlying data change with a call to notify and
* false otherwise.
*/
public boolean isImmediateNotifySupported() {
return false;
}
}