Presenter.java revision a00bada00bff4a58436a39472ab14ccb7a8f619d
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.view.View; 17import android.view.ViewGroup; 18 19/** 20 * A Presenter is used to generate {@link View}s and bind Objects to them on 21 * demand. It is closely related to the concept of an {@link 22 * android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}, but is 23 * not position-based. The leanback framework implements the adapter concept using 24 * {@link ObjectAdapter} which refers to a Presenter (or {@link PresenterSelector}) instance. 25 * 26 * <p> 27 * Presenters should be stateless. Presenters typically extend {@link ViewHolder} to store all 28 * necessary view state information, such as references to child views to be used when 29 * binding to avoid expensive calls to {@link View#findViewById(int)}. 30 * </p> 31 * 32 * <p> 33 * A trivial Presenter that takes a string and renders it into a {@link 34 * android.widget.TextView TextView}: 35 * 36 * <pre class="prettyprint"> 37 * public class StringTextViewPresenter extends Presenter { 38 * // This class does not need a custom ViewHolder, since it does not use 39 * // a complex layout. 40 * 41 * {@literal @}Override 42 * public ViewHolder onCreateViewHolder(ViewGroup parent) { 43 * return new ViewHolder(new TextView(parent.getContext())); 44 * } 45 * 46 * {@literal @}Override 47 * public void onBindViewHolder(ViewHolder viewHolder, Object item) { 48 * String str = (String) item; 49 * TextView textView = (TextView) viewHolder.mView; 50 * 51 * textView.setText(item); 52 * } 53 * 54 * {@literal @}Override 55 * public void onUnbindViewHolder(ViewHolder viewHolder) { 56 * // Nothing to unbind for TextView, but if this viewHolder had 57 * // allocated bitmaps, they can be released here. 58 * } 59 * } 60 * </pre> 61 */ 62public abstract class Presenter { 63 /** 64 * ViewHolder can be subclassed and used to cache any view accessors needed 65 * to improve binding performance (for example, results of findViewById) 66 * without needing to subclass a View. 67 */ 68 public static class ViewHolder { 69 public final View view; 70 71 public ViewHolder(View view) { 72 this.view = view; 73 } 74 } 75 76 /** 77 * Creates a new {@link View}. 78 */ 79 public abstract ViewHolder onCreateViewHolder(ViewGroup parent); 80 81 /** 82 * Binds a {@link View} to an item. 83 */ 84 public abstract void onBindViewHolder(ViewHolder viewHolder, Object item); 85 86 /** 87 * Unbinds a {@link View} from an item. Any expensive references may be 88 * released here, and any fields that are not bound for every item should be 89 * cleared here. 90 */ 91 public abstract void onUnbindViewHolder(ViewHolder viewHolder); 92 93 /** 94 * Called when a view created by this presenter has been attached to a window. 95 * 96 * <p>This can be used as a reasonable signal that the view is about to be seen 97 * by the user. If the adapter previously freed any resources in 98 * {@link #onViewDetachedFromWindow(ViewHolder)} 99 * those resources should be restored here.</p> 100 * 101 * @param holder Holder of the view being attached 102 */ 103 public void onViewAttachedToWindow(ViewHolder holder) { 104 } 105 106 /** 107 * Called when a view created by this presenter has been detached from its window. 108 * 109 * <p>Becoming detached from the window is not necessarily a permanent condition; 110 * the consumer of an presenter's views may choose to cache views offscreen while they 111 * are not visible, attaching and detaching them as appropriate.</p> 112 * 113 * Any view property animations should be cancelled here or the view may fail 114 * to be recycled. 115 * 116 * @param holder Holder of the view being detached 117 */ 118 public void onViewDetachedFromWindow(ViewHolder holder) { 119 // If there are view property animations running then RecyclerView won't recycle. 120 cancelAnimationsRecursive(holder.view); 121 } 122 123 /** 124 * Utility method for removing all running animations on a view. 125 */ 126 protected static void cancelAnimationsRecursive(View view) { 127 if (view != null && view.hasTransientState()) { 128 view.animate().cancel(); 129 if (view instanceof ViewGroup) { 130 final int count = ((ViewGroup) view).getChildCount(); 131 for (int i = 0; view.hasTransientState() && i < count; i++) { 132 cancelAnimationsRecursive(((ViewGroup) view).getChildAt(i)); 133 } 134 } 135 } 136 } 137 138 /** 139 * Called to set a click listener for the given view holder. 140 * 141 * The default implementation sets the click listener on the root view in the view holder. 142 * If the root view isn't focusable this method should be overridden to set the listener 143 * on the appropriate focusable child view(s). 144 * 145 * @param holder The view holder containing the view(s) on which the listener should be set. 146 * @param listener The click listener to be set. 147 */ 148 public void setOnClickListener(ViewHolder holder, View.OnClickListener listener) { 149 holder.view.setOnClickListener(listener); 150 } 151} 152