1 /* 2 * Copyright (C) 2013 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 17 package com.android.mail.content; 18 19 import android.database.Cursor; 20 import android.database.CursorWrapper; 21 import android.util.SparseArray; 22 23 /** 24 * A cursor-backed type that can return an object for each row of the cursor. This class is most 25 * useful when: 26 * 1. The cursor is returned in conjuction with an AsyncTaskLoader and created off the UI thread. 27 * 2. A single row in the cursor specifies everything for an object. 28 */ 29 public class ObjectCursor <T> extends CursorWrapper { 30 /** The cache for objects in the underlying cursor. */ 31 private final SparseArray<T> mCache; 32 /** An object that knows how to construct {@link T} objects using cursors. */ 33 private final CursorCreator<T> mFactory; 34 35 /** 36 * Creates a new object cursor. 37 * @param cursor the underlying cursor this wraps. 38 */ 39 public ObjectCursor(Cursor cursor, CursorCreator<T> factory) { 40 super(cursor); 41 if (cursor != null) { 42 mCache = new SparseArray<T>(cursor.getCount()); 43 } else { 44 mCache = null; 45 } 46 mFactory = factory; 47 } 48 49 /** 50 * Create a concrete object at the current cursor position. There is no guarantee on object 51 * creation: an object might have been previously created, or the cache might be populated 52 * by calling {@link #fillCache()}. In both these cases, the previously created object is 53 * returned. 54 * @return a model 55 */ 56 public final T getModel() { 57 final Cursor c = getWrappedCursor(); 58 if (c == null ) { 59 return null; 60 } 61 final int currentPosition = c.getPosition(); 62 // The cache contains this object, return it. 63 final T prev = mCache.get(currentPosition); 64 if (prev != null) { 65 return prev; 66 } 67 // Get the object at the current position and add it to the cache. 68 final T model = mFactory.createFromCursor(c); 69 mCache.put(currentPosition, model); 70 return model; 71 } 72 73 /** 74 * Reads the entire cursor to populate the objects in the cache. Subsequent calls to {@link 75 * #getModel()} will return the cached objects as far as the underlying cursor does not change. 76 */ 77 final void fillCache() { 78 final Cursor c = getWrappedCursor(); 79 if (c == null || !c.moveToFirst()) { 80 return; 81 } 82 do { 83 // As a side effect of getModel, the model is cached away. 84 getModel(); 85 } while (c.moveToNext()); 86 } 87 88 @Override 89 public void close() { 90 super.close(); 91 mCache.clear(); 92 } 93 94 } 95