Home | History | Annotate | Download | only in content
      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      */
     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