CursorObjectAdapter.java revision 2eaaad9c189f1ae42bf6c382a30ccab455030e54
120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn/*
220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Copyright (C) 2014 The Android Open Source Project
320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *
420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * in compliance with the License. You may obtain a copy of the License at
620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *
720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * http://www.apache.org/licenses/LICENSE-2.0
820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *
920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Unless required by applicable law or agreed to in writing, software distributed under the License
1020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
1120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * or implied. See the License for the specific language governing permissions and limitations under
1220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * the License.
1320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */
1420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournpackage android.support.v17.leanback.widget;
1520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
1620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournimport android.database.Cursor;
1720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournimport android.support.v17.leanback.database.CursorMapper;
1820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournimport android.util.LruCache;
1920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
2020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn/**
2120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Adapter implemented with a {@link Cursor}.
2220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */
2320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournpublic class CursorObjectAdapter extends ObjectAdapter {
2420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    private static final int CACHE_SIZE = 100;
250f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu    private Cursor mCursor;
260f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu    private CursorMapper mMapper;
270f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu    private final LruCache<Integer, Object> mItemCache = new LruCache<Integer, Object>(CACHE_SIZE);
2820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
2920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    public CursorObjectAdapter(PresenterSelector presenterSelector) {
3020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        super(presenterSelector);
3120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    }
3220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
3320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    public CursorObjectAdapter(Presenter presenter) {
3420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        super(presenter);
3520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    }
3620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
3720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    public CursorObjectAdapter() {
3820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        super();
3920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    }
4020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
4120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    /**
4220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * Change the underlying cursor to a new cursor. If there is
4320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * an existing cursor it will be closed.
4420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     *
4520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * @param cursor The new cursor to be used.
4620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     */
4720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    public void changeCursor(Cursor cursor) {
4820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        if (cursor == mCursor) {
4920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn            return;
5020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        }
512eaaad9c189f1ae42bf6c382a30ccab455030e54Andrew Wilson        if (mCursor != null) {
522eaaad9c189f1ae42bf6c382a30ccab455030e54Andrew Wilson            mCursor.close();
532eaaad9c189f1ae42bf6c382a30ccab455030e54Andrew Wilson        }
5420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        mCursor = cursor;
5520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        mItemCache.trimToSize(0);
5620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        onCursorChanged();
5720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    }
5820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
5920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    /**
6020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * Swap in a new Cursor, returning the old Cursor. Unlike changeCursor(Cursor),
6120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * the returned old Cursor is not closed.
6220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     *
6320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * @param cursor The new cursor to be used.
6420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     */
6520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    public Cursor swapCursor(Cursor cursor) {
6620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        if (cursor == mCursor) {
6720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn            return mCursor;
6820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        }
6920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        Cursor oldCursor = mCursor;
7020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        mCursor = cursor;
7120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        mItemCache.trimToSize(0);
7220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        onCursorChanged();
7320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        return oldCursor;
7420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    }
7520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
7620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    /**
7720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * Called whenever the cursor changes.
7820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     */
7920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    protected void onCursorChanged() {
8020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        notifyChanged();
8120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    }
8220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
8320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    /**
8420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * Gets the {@link Cursor} backing the adapter.
8520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     */
860f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu     public final Cursor getCursor() {
8720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        return mCursor;
8820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    }
8920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
9020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    /**
9120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * Sets the {@link CursorMapper} used to convert {@link Cursor} rows into
9220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * Objects.
9320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     */
940f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu    public final void setMapper(CursorMapper mapper) {
9520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        mMapper = mapper;
9620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    }
9720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
9820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    /**
9920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * Gets the {@link CursorMapper} used to convert {@link Cursor} rows into
10020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * Objects.
10120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     */
1020f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu    public final CursorMapper getMapper() {
10320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        return mMapper;
10420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    }
10520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
10620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    @Override
10720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    public int size() {
10820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        if (mCursor == null) {
10920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn            return 0;
11020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        }
11120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        return mCursor.getCount();
11220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    }
11320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
11420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    @Override
11520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    public Object get(int index) {
11620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        if (mCursor == null) {
11720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn            return null;
11820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        }
11920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        if (!mCursor.moveToPosition(index)) {
12020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn            throw new ArrayIndexOutOfBoundsException();
12120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        }
12220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        Object item = mItemCache.get(index);
12320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        if (item != null) {
12420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn            return item;
12520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        }
12620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        item = mMapper.convert(mCursor);
12720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        mItemCache.put(index, item);
12820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        return item;
12920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    }
13020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
13120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    /**
13220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * Closes this adapter, closing the backing {@link Cursor} as well.
13320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     */
13420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    public void close() {
13520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        if (mCursor != null) {
13620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn            mCursor.close();
13720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn            mCursor = null;
13820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        }
13920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    }
14020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
14120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    /**
14220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * Checks whether the adapter, and hence the backing {@link Cursor}, is closed.
14320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     */
14420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    public boolean isClosed() {
14520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        return mCursor == null || mCursor.isClosed();
14620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    }
147c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson
148c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson    /**
149c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson     * Remove an item from the cache. This will force the item to be re-read
150c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson     * from the data source the next time (@link #get(int)} is called.
151c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson     */
152c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson    protected final void invalidateCache(int index) {
153c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson        mItemCache.remove(index);
154c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson    }
155c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson
156c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson    /**
157c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson     * Remove {@code count} items starting at {@code index}.
158c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson     */
159c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson    protected final void invalidateCache(int index, int count) {
160c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson        for (int limit = count + index; index < limit; index++) {
161c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson            invalidateCache(index);
162c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson        }
163c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson    }
16420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn}
165