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 conjunction 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      */
ObjectCursor(Cursor cursor, CursorCreator<T> factory)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      */
getModel()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      */
fillCache()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
close()89     public void close() {
90         super.close();
91         mCache.clear();
92     }
93 
94 }
95