Presenter.java revision 08c56822b71ab0aa0b9bb03e5fd45e28f6e358b8
1ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist/* 2ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * Copyright (C) 2014 The Android Open Source Project 3ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 4ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * in compliance with the License. You may obtain a copy of the License at 6ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 7ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * http://www.apache.org/licenses/LICENSE-2.0 8ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 9ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * Unless required by applicable law or agreed to in writing, software distributed under the License 10ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * or implied. See the License for the specific language governing permissions and limitations under 12ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * the License. 13ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist */ 14ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpackage android.support.v17.leanback.widget; 15ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 16ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport android.view.View; 17ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport android.view.ViewGroup; 18ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 19ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.HashMap; 20ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Map; 21ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 22ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist/** 23ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * A Presenter is used to generate {@link View}s and bind Objects to them on 24ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * demand. It is closely related to the concept of an {@link 25ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}, but is 26ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * not position-based. The leanback framework implements the adapter concept using 27ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * {@link ObjectAdapter} which refers to a Presenter (or {@link PresenterSelector}) instance. 28ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 29ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * <p> 30ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * Presenters should be stateless. Presenters typically extend {@link ViewHolder} to store all 31ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * necessary view state information, such as references to child views to be used when 32ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * binding to avoid expensive calls to {@link View#findViewById(int)}. 33ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * </p> 34ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 35ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * <p> 36ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * A trivial Presenter that takes a string and renders it into a {@link 37ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * android.widget.TextView TextView}: 38ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 39ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * <pre class="prettyprint"> 40ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * public class StringTextViewPresenter extends Presenter { 41ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * // This class does not need a custom ViewHolder, since it does not use 42ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * // a complex layout. 43ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 44ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * {@literal @}Override 45ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * public ViewHolder onCreateViewHolder(ViewGroup parent) { 46ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * return new ViewHolder(new TextView(parent.getContext())); 47ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * } 48ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 49ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * {@literal @}Override 50ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * public void onBindViewHolder(ViewHolder viewHolder, Object item) { 51ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * String str = (String) item; 52ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * TextView textView = (TextView) viewHolder.mView; 53ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 54ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * textView.setText(item); 55ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * } 56ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 57ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * {@literal @}Override 58ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * public void onUnbindViewHolder(ViewHolder viewHolder) { 59ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * // Nothing to unbind for TextView, but if this viewHolder had 60ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * // allocated bitmaps, they can be released here. 61ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * } 62ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * } 63ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * </pre> 64ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * In addition to view creation and binding, Presenter allows dynamic interface (facet) to 65ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * be added: {@link #setFacet(Class, Object)}. Supported facets: 66ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * <li> {@link ItemAlignmentFacet} is used by {@link HorizontalGridView} and 67ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * {@link VerticalGridView} to customize child alignment. 68ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist */ 69ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpublic abstract class Presenter implements FacetProvider { 70ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist /** 71ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * ViewHolder can be subclassed and used to cache any view accessors needed 72ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * to improve binding performance (for example, results of findViewById) 73ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * without needing to subclass a View. 74ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist */ 75ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public static class ViewHolder implements FacetProvider { 76ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public final View view; 77ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private Map<Class, Object> mFacets; 78ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 79ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public ViewHolder(View view) { 80ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist this.view = view; 81ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 82ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 83ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 84ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public final Object getFacet(Class<?> facetClass) { 85ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (mFacets == null) { 86ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return null; 87ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 88ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mFacets.get(facetClass); 89ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 90ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 91ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist /** 92ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * Sets dynamic implemented facet in addition to basic ViewHolder functions. 93ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * @param facetClass Facet classes to query, can be class of {@link ItemAlignmentFacet}. 94ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * @param facetImpl Facet implementation. 95ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist */ 96ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public final void setFacet(Class<?> facetClass, Object facetImpl) { 97ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (mFacets == null) { 98ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mFacets = new HashMap<Class, Object>(); 99ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 100ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mFacets.put(facetClass, facetImpl); 101ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 102ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 103ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 104ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private Map<Class, Object> mFacets; 105ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 106ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist /** 107ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * Creates a new {@link View}. 108ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist */ 109ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public abstract ViewHolder onCreateViewHolder(ViewGroup parent); 110ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 111ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist /** 112ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * Binds a {@link View} to an item. 113ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist */ 114ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public abstract void onBindViewHolder(ViewHolder viewHolder, Object item); 115ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 116ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist /** 117ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * Unbinds a {@link View} from an item. Any expensive references may be 118ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * released here, and any fields that are not bound for every item should be 119ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * cleared here. 120ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist */ 121ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public abstract void onUnbindViewHolder(ViewHolder viewHolder); 122ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 123ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist /** 124ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * Called when a view created by this presenter has been attached to a window. 125ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 126ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * <p>This can be used as a reasonable signal that the view is about to be seen 127ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * by the user. If the adapter previously freed any resources in 128ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * {@link #onViewDetachedFromWindow(ViewHolder)} 129ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * those resources should be restored here.</p> 130ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 131ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * @param holder Holder of the view being attached 132ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist */ 133ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void onViewAttachedToWindow(ViewHolder holder) { 134ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 135ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 136ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist /** 137ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * Called when a view created by this presenter has been detached from its window. 138ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 139ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * <p>Becoming detached from the window is not necessarily a permanent condition; 140ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * the consumer of an presenter's views may choose to cache views offscreen while they 141ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * are not visible, attaching and detaching them as appropriate.</p> 142ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 143ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * Any view property animations should be cancelled here or the view may fail 144ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * to be recycled. 145ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 146ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * @param holder Holder of the view being detached 147ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist */ 148ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void onViewDetachedFromWindow(ViewHolder holder) { 149ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist // If there are view property animations running then RecyclerView won't recycle. 150ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist cancelAnimationsRecursive(holder.view); 151ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 152ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 153ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist /** 154ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * Utility method for removing all running animations on a view. 155ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist */ 156ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist protected static void cancelAnimationsRecursive(View view) { 157ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (view != null && view.hasTransientState()) { 158ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist view.animate().cancel(); 159ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (view instanceof ViewGroup) { 160ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist final int count = ((ViewGroup) view).getChildCount(); 161ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (int i = 0; view.hasTransientState() && i < count; i++) { 162ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist cancelAnimationsRecursive(((ViewGroup) view).getChildAt(i)); 163ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 164ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 165ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 166ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 167ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 168ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist /** 169ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * Called to set a click listener for the given view holder. 170ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 171ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * The default implementation sets the click listener on the root view in the view holder. 172ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * If the root view isn't focusable this method should be overridden to set the listener 173ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * on the appropriate focusable child view(s). 174ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 175ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * @param holder The view holder containing the view(s) on which the listener should be set. 176ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * @param listener The click listener to be set. 177ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist */ 178ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void setOnClickListener(ViewHolder holder, View.OnClickListener listener) { 179ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist holder.view.setOnClickListener(listener); 180ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 181ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 182ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 183ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public final Object getFacet(Class<?> facetClass) { 184ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (mFacets == null) { 185ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return null; 186 } 187 return mFacets.get(facetClass); 188 } 189 190 /** 191 * Sets dynamic implemented facet in addition to basic Presenter functions. 192 * @param facetClass Facet classes to query, can be class of {@link ItemAlignmentFacet}. 193 * @param facetImpl Facet implementation. 194 */ 195 public final void setFacet(Class<?> facetClass, Object facetImpl) { 196 if (mFacets == null) { 197 mFacets = new HashMap<Class, Object>(); 198 } 199 mFacets.put(facetClass, facetImpl); 200 } 201} 202