ItemBridgeAdapter.java revision 62d36d44e03a3dd0632b156615b04563c62e83c1
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.support.v7.widget.RecyclerView; 17import android.support.v17.leanback.R; 18import android.util.Log; 19import android.view.View; 20import android.view.ViewGroup; 21 22import java.util.ArrayList; 23 24/** 25 * Bridge from Presenter to RecyclerView.Adapter. Public to allow use by third 26 * party presenters. 27 */ 28public class ItemBridgeAdapter extends RecyclerView.Adapter { 29 private static final String TAG = "ItemBridgeAdapter"; 30 private static final boolean DEBUG = false; 31 32 /** 33 * Interface for listening to view holder operations. 34 */ 35 public static class AdapterListener { 36 public void onAddPresenter(Presenter presenter) { 37 } 38 public void onCreate(ViewHolder viewHolder) { 39 } 40 public void onBind(ViewHolder viewHolder) { 41 } 42 public void onUnbind(ViewHolder viewHolder) { 43 } 44 public void onAttachedToWindow(ViewHolder viewHolder) { 45 } 46 public void onDetachedFromWindow(ViewHolder viewHolder) { 47 } 48 } 49 50 private ObjectAdapter mAdapter; 51 private PresenterSelector mPresenterSelector; 52 private FocusHighlight mFocusHighlight; 53 private AdapterListener mAdapterListener; 54 private ArrayList<Presenter> mPresenters = new ArrayList<Presenter>(); 55 56 final class OnFocusChangeListener implements View.OnFocusChangeListener { 57 View.OnFocusChangeListener mChainedListener; 58 59 @Override 60 public void onFocusChange(View view, boolean hasFocus) { 61 if (DEBUG) Log.v(TAG, "onFocusChange " + hasFocus + " " + view 62 + " mFocusHighlight" + mFocusHighlight); 63 if (mFocusHighlight != null) { 64 mFocusHighlight.onItemFocused(view, hasFocus); 65 } 66 if (mChainedListener != null) { 67 mChainedListener.onFocusChange(view, hasFocus); 68 } 69 } 70 } 71 72 public class ViewHolder extends RecyclerView.ViewHolder { 73 final Presenter mPresenter; 74 final Presenter.ViewHolder mHolder; 75 final OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener(); 76 Object mItem; 77 Object mExtraObject; 78 79 /** 80 * Get {@link Presenter}. 81 */ 82 public final Presenter getPresenter() { 83 return mPresenter; 84 } 85 86 /** 87 * Get {@link Presenter.ViewHolder}. 88 */ 89 public final Presenter.ViewHolder getViewHolder() { 90 return mHolder; 91 } 92 93 /** 94 * Get currently bound object. 95 */ 96 public final Object getItem() { 97 return mItem; 98 } 99 100 /** 101 * Get extra object associated with the view. Developer can attach 102 * any customized UI object in addition to {@link Presenter.ViewHolder}. 103 * A typical use case is attaching an animator object. 104 */ 105 public final Object getExtraObject() { 106 return mExtraObject; 107 } 108 109 /** 110 * Set extra object associated with the view. Developer can attach 111 * any customized UI object in addition to {@link Presenter.ViewHolder}. 112 * A typical use case is attaching an animator object. 113 */ 114 public void setExtraObject(Object object) { 115 mExtraObject = object; 116 } 117 118 ViewHolder(Presenter presenter, Presenter.ViewHolder holder) { 119 super(holder.view); 120 mPresenter = presenter; 121 mHolder = holder; 122 } 123 } 124 125 private ObjectAdapter.DataObserver mDataObserver = new ObjectAdapter.DataObserver() { 126 @Override 127 public void onChanged() { 128 ItemBridgeAdapter.this.notifyDataSetChanged(); 129 } 130 @Override 131 public void onItemRangeChanged(int positionStart, int itemCount) { 132 ItemBridgeAdapter.this.notifyItemRangeChanged(positionStart, itemCount); 133 } 134 @Override 135 public void onItemRangeInserted(int positionStart, int itemCount) { 136 ItemBridgeAdapter.this.notifyItemRangeInserted(positionStart, itemCount); 137 } 138 @Override 139 public void onItemRangeRemoved(int positionStart, int itemCount) { 140 ItemBridgeAdapter.this.notifyItemRangeRemoved(positionStart, itemCount); 141 } 142 }; 143 144 public ItemBridgeAdapter(ObjectAdapter adapter, PresenterSelector presenterSelector) { 145 setAdapter(adapter); 146 mPresenterSelector = presenterSelector; 147 } 148 149 public ItemBridgeAdapter() { 150 } 151 152 public void setAdapter(ObjectAdapter adapter) { 153 if (mAdapter != null) { 154 mAdapter.unregisterObserver(mDataObserver); 155 } 156 mAdapter = adapter; 157 if (mAdapter == null) { 158 return; 159 } 160 161 mAdapter.registerObserver(mDataObserver); 162 if (hasStableIds() != mAdapter.hasStableIds()) { 163 setHasStableIds(mAdapter.hasStableIds()); 164 } 165 } 166 167 void setFocusHighlight(FocusHighlight listener) { 168 mFocusHighlight = listener; 169 if (DEBUG) Log.v(TAG, "setFocusHighlight " + mFocusHighlight); 170 } 171 172 public void clear() { 173 setAdapter(null); 174 } 175 176 @Override 177 public int getItemCount() { 178 return mAdapter.size(); 179 } 180 181 @Override 182 public int getItemViewType(int position) { 183 PresenterSelector presenterSelector = mPresenterSelector != null ? 184 mPresenterSelector : mAdapter.getPresenterSelector(); 185 Object item = mAdapter.get(position); 186 Presenter presenter = presenterSelector.getPresenter(item); 187 int type = mPresenters.indexOf(presenter); 188 if (type < 0) { 189 mPresenters.add(presenter); 190 type = mPresenters.indexOf(presenter); 191 if (mAdapterListener != null) { 192 mAdapterListener.onAddPresenter(presenter); 193 } 194 } 195 return type; 196 } 197 198 /** 199 * {@link View.OnFocusChangeListener} that assigned in 200 * {@link Presenter#onCreateViewHolder(ViewGroup)} may be chained, user should never change 201 * {@link View.OnFocusChangeListener} after that. 202 */ 203 @Override 204 public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 205 if (DEBUG) Log.v(TAG, "onCreateViewHolder viewType " + viewType); 206 Presenter presenter = mPresenters.get(viewType); 207 ViewHolder viewHolder = new ViewHolder(presenter, presenter.onCreateViewHolder(parent)); 208 if (mAdapterListener != null) { 209 mAdapterListener.onCreate(viewHolder); 210 } 211 View view = viewHolder.mHolder.view; 212 if (view != null) { 213 viewHolder.mFocusChangeListener.mChainedListener = view.getOnFocusChangeListener(); 214 view.setOnFocusChangeListener(viewHolder.mFocusChangeListener); 215 } 216 return viewHolder; 217 } 218 219 public void setAdapterListener(AdapterListener listener) { 220 mAdapterListener = listener; 221 } 222 223 @Override 224 public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 225 if (DEBUG) Log.v(TAG, "onBindViewHolder position " + position); 226 ViewHolder viewHolder = (ViewHolder) holder; 227 viewHolder.mItem = mAdapter.get(position); 228 229 viewHolder.mPresenter.onBindViewHolder(viewHolder.mHolder, viewHolder.mItem); 230 231 if (mAdapterListener != null) { 232 mAdapterListener.onBind(viewHolder); 233 } 234 } 235 236 @Override 237 public void onViewRecycled(RecyclerView.ViewHolder holder) { 238 ViewHolder viewHolder = (ViewHolder) holder; 239 viewHolder.mPresenter.onUnbindViewHolder(viewHolder.mHolder); 240 241 viewHolder.mItem = null; 242 243 if (mAdapterListener != null) { 244 mAdapterListener.onUnbind(viewHolder); 245 } 246 } 247 248 @Override 249 public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { 250 ViewHolder viewHolder = (ViewHolder) holder; 251 if (mAdapterListener != null) { 252 mAdapterListener.onAttachedToWindow(viewHolder); 253 } 254 viewHolder.mPresenter.onViewAttachedToWindow(viewHolder.mHolder); 255 } 256 257 @Override 258 public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) { 259 ViewHolder viewHolder = (ViewHolder) holder; 260 viewHolder.mPresenter.onViewDetachedFromWindow(viewHolder.mHolder); 261 if (mAdapterListener != null) { 262 mAdapterListener.onDetachedFromWindow(viewHolder); 263 } 264 } 265 266 @Override 267 public long getItemId(int position) { 268 return mAdapter.getId(position); 269 } 270 271} 272