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