1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.support.car.ui; 17 18 import android.content.Context; 19 import android.database.Cursor; 20 import android.database.DataSetObserver; 21 import android.provider.BaseColumns; 22 import android.support.v7.widget.RecyclerView; 23 24 /** 25 * Adapter that exposes data from a Cursor to a {@link RecyclerView} widget. 26 * The Cursor must include an Id column or this class will not work. 27 */ 28 public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> 29 extends RecyclerView.Adapter<VH> { 30 31 protected Context mContext; 32 protected Cursor mCursor; 33 protected int mRowIdColumn; 34 35 public CursorRecyclerViewAdapter(Context context, Cursor cursor) { 36 mContext = context; 37 mCursor = cursor; 38 mRowIdColumn = -1; 39 if (mCursor != null) { 40 mRowIdColumn = getRowIdColumnIndex(mCursor); 41 mCursor.registerDataSetObserver(mDataSetObserver); 42 } 43 } 44 45 public Cursor getCursor() { 46 return mCursor; 47 } 48 49 @Override 50 public int getItemCount() { 51 if (mCursor != null) { 52 return mCursor.getCount(); 53 } 54 return 0; 55 } 56 57 @Override 58 public long getItemId(int position) { 59 if (mCursor != null && mCursor.moveToPosition(position)) { 60 return mCursor.getLong(mRowIdColumn); 61 } 62 return 0; 63 } 64 65 public void onBindViewHolder(VH viewHolder, Cursor cursor) {} 66 67 @Override 68 public void onBindViewHolder(VH viewHolder, int position) { 69 if (!mCursor.moveToPosition(position)) { 70 throw new IllegalStateException("can't move cursor to position " + position); 71 } 72 onBindViewHolder(viewHolder, mCursor); 73 } 74 75 /** 76 * Change the underlying cursor to a new cursor. If there is an existing cursor it will 77 * be closed. 78 * 79 * @param cursor The new cursor to be used. 80 */ 81 public void changeCursor(Cursor cursor) { 82 Cursor old = swapCursor(cursor); 83 if (old != null) { 84 old.close(); 85 } 86 } 87 88 /** 89 * Swap in a new Cursor, returning the old Cursor. Unlike changeCursor(android.database.Cursor), 90 * the returned old Cursor is not closed. 91 * 92 * @param newCursor The new cursor to be used. 93 */ 94 public Cursor swapCursor(Cursor newCursor) { 95 if (newCursor == mCursor) { 96 return null; 97 } 98 99 Cursor oldCursor = mCursor; 100 if (oldCursor != null) { 101 if (mDataSetObserver != null) { 102 oldCursor.unregisterDataSetObserver(mDataSetObserver); 103 } 104 } 105 106 mCursor = newCursor; 107 if (mCursor != null) { 108 if (mDataSetObserver != null) { 109 mCursor.registerDataSetObserver(mDataSetObserver); 110 } 111 mRowIdColumn = getRowIdColumnIndex(mCursor); 112 notifyDataSetChanged(); 113 } else { 114 mRowIdColumn = -1; 115 notifyDataSetChanged(); 116 } 117 return oldCursor; 118 } 119 120 protected int getRowIdColumnIndex(Cursor cursor) { 121 return cursor.getColumnIndex(BaseColumns._ID); 122 } 123 124 protected DataSetObserver mDataSetObserver = new DataSetObserver() { 125 @Override 126 public void onChanged() { 127 super.onChanged(); 128 notifyDataSetChanged(); 129 } 130 131 @Override 132 public void onInvalidated() { 133 super.onInvalidated(); 134 mCursor = null; 135 notifyDataSetChanged(); 136 } 137 }; 138 } 139