CursorObjectAdapter.java revision b3451baf39c3b17972e7826baee90be4b1cd2626
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.database.Cursor; 17import android.support.v17.leanback.database.CursorMapper; 18import android.util.LruCache; 19 20/** 21 * Adapter implemented with a {@link Cursor}. 22 */ 23public class CursorObjectAdapter extends ObjectAdapter { 24 private static final int CACHE_SIZE = 100; 25 private Cursor mCursor; 26 private CursorMapper mMapper; 27 private final LruCache<Integer, Object> mItemCache = new LruCache<Integer, Object>(CACHE_SIZE); 28 29 public CursorObjectAdapter(PresenterSelector presenterSelector) { 30 super(presenterSelector); 31 } 32 33 public CursorObjectAdapter(Presenter presenter) { 34 super(presenter); 35 } 36 37 public CursorObjectAdapter() { 38 super(); 39 } 40 41 /** 42 * Change the underlying cursor to a new cursor. If there is 43 * an existing cursor it will be closed. 44 * 45 * @param cursor The new cursor to be used. 46 */ 47 public void changeCursor(Cursor cursor) { 48 if (cursor == mCursor) { 49 return; 50 } 51 if (mCursor != null) { 52 mCursor.close(); 53 } 54 mCursor = cursor; 55 mItemCache.trimToSize(0); 56 onCursorChanged(); 57 } 58 59 /** 60 * Swap in a new Cursor, returning the old Cursor. Unlike changeCursor(Cursor), 61 * the returned old Cursor is not closed. 62 * 63 * @param cursor The new cursor to be used. 64 */ 65 public Cursor swapCursor(Cursor cursor) { 66 if (cursor == mCursor) { 67 return mCursor; 68 } 69 Cursor oldCursor = mCursor; 70 mCursor = cursor; 71 mItemCache.trimToSize(0); 72 onCursorChanged(); 73 return oldCursor; 74 } 75 76 /** 77 * Called whenever the cursor changes. 78 */ 79 protected void onCursorChanged() { 80 notifyChanged(); 81 } 82 83 /** 84 * Gets the {@link Cursor} backing the adapter. 85 */ 86 public final Cursor getCursor() { 87 return mCursor; 88 } 89 90 /** 91 * Sets the {@link CursorMapper} used to convert {@link Cursor} rows into 92 * Objects. 93 */ 94 public final void setMapper(CursorMapper mapper) { 95 boolean changed = mMapper != mapper; 96 mMapper = mapper; 97 98 if (changed) { 99 onMapperChanged(); 100 } 101 } 102 103 /** 104 * Called when {@link #setMapper(CursorMapper)} is called and a different 105 * mapper is provided. 106 */ 107 protected void onMapperChanged() { 108 } 109 110 /** 111 * Gets the {@link CursorMapper} used to convert {@link Cursor} rows into 112 * Objects. 113 */ 114 public final CursorMapper getMapper() { 115 return mMapper; 116 } 117 118 @Override 119 public int size() { 120 if (mCursor == null) { 121 return 0; 122 } 123 return mCursor.getCount(); 124 } 125 126 @Override 127 public Object get(int index) { 128 if (mCursor == null) { 129 return null; 130 } 131 if (!mCursor.moveToPosition(index)) { 132 throw new ArrayIndexOutOfBoundsException(); 133 } 134 Object item = mItemCache.get(index); 135 if (item != null) { 136 return item; 137 } 138 item = mMapper.convert(mCursor); 139 mItemCache.put(index, item); 140 return item; 141 } 142 143 /** 144 * Closes this adapter, closing the backing {@link Cursor} as well. 145 */ 146 public void close() { 147 if (mCursor != null) { 148 mCursor.close(); 149 mCursor = null; 150 } 151 } 152 153 /** 154 * Checks whether the adapter, and hence the backing {@link Cursor}, is closed. 155 */ 156 public boolean isClosed() { 157 return mCursor == null || mCursor.isClosed(); 158 } 159 160 /** 161 * Remove an item from the cache. This will force the item to be re-read 162 * from the data source the next time (@link #get(int)} is called. 163 */ 164 protected final void invalidateCache(int index) { 165 mItemCache.remove(index); 166 } 167 168 /** 169 * Remove {@code count} items starting at {@code index}. 170 */ 171 protected final void invalidateCache(int index, int count) { 172 for (int limit = count + index; index < limit; index++) { 173 invalidateCache(index); 174 } 175 } 176} 177