1f94abcf44fc1611f76e55461f48220e621fc31b7John Reck/* 2f94abcf44fc1611f76e55461f48220e621fc31b7John Reck * Copyright (C) 2011 The Android Open Source Project 3f94abcf44fc1611f76e55461f48220e621fc31b7John Reck * 4f94abcf44fc1611f76e55461f48220e621fc31b7John Reck * Licensed under the Apache License, Version 2.0 (the "License"); 5f94abcf44fc1611f76e55461f48220e621fc31b7John Reck * you may not use this file except in compliance with the License. 6f94abcf44fc1611f76e55461f48220e621fc31b7John Reck * You may obtain a copy of the License at 7f94abcf44fc1611f76e55461f48220e621fc31b7John Reck * 8f94abcf44fc1611f76e55461f48220e621fc31b7John Reck * http://www.apache.org/licenses/LICENSE-2.0 9f94abcf44fc1611f76e55461f48220e621fc31b7John Reck * 10f94abcf44fc1611f76e55461f48220e621fc31b7John Reck * Unless required by applicable law or agreed to in writing, software 11f94abcf44fc1611f76e55461f48220e621fc31b7John Reck * distributed under the License is distributed on an "AS IS" BASIS, 12f94abcf44fc1611f76e55461f48220e621fc31b7John Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f94abcf44fc1611f76e55461f48220e621fc31b7John Reck * See the License for the specific language governing permissions and 14f94abcf44fc1611f76e55461f48220e621fc31b7John Reck * limitations under the License. 15f94abcf44fc1611f76e55461f48220e621fc31b7John Reck */ 16f94abcf44fc1611f76e55461f48220e621fc31b7John Reckpackage com.android.browser.util; 17f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 18f94abcf44fc1611f76e55461f48220e621fc31b7John Reckimport android.content.Context; 19f94abcf44fc1611f76e55461f48220e621fc31b7John Reckimport android.database.Cursor; 20f94abcf44fc1611f76e55461f48220e621fc31b7John Reckimport android.os.Handler; 21f94abcf44fc1611f76e55461f48220e621fc31b7John Reckimport android.os.HandlerThread; 22f94abcf44fc1611f76e55461f48220e621fc31b7John Reckimport android.os.Message; 23f94abcf44fc1611f76e55461f48220e621fc31b7John Reckimport android.os.Process; 243ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reckimport android.os.SystemProperties; 25f94abcf44fc1611f76e55461f48220e621fc31b7John Reckimport android.util.Log; 26f94abcf44fc1611f76e55461f48220e621fc31b7John Reckimport android.view.View; 27f94abcf44fc1611f76e55461f48220e621fc31b7John Reckimport android.view.ViewGroup; 28f94abcf44fc1611f76e55461f48220e621fc31b7John Reckimport android.widget.Adapter; 29f94abcf44fc1611f76e55461f48220e621fc31b7John Reckimport android.widget.BaseAdapter; 30f94abcf44fc1611f76e55461f48220e621fc31b7John Reckimport android.widget.CursorAdapter; 31f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 32f94abcf44fc1611f76e55461f48220e621fc31b7John Reckimport com.android.browser.R; 33f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 34f94abcf44fc1611f76e55461f48220e621fc31b7John Reckimport java.lang.ref.WeakReference; 35f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 36f94abcf44fc1611f76e55461f48220e621fc31b7John Reckpublic abstract class ThreadedCursorAdapter<T> extends BaseAdapter { 37f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 383ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck private static final String LOGTAG = "BookmarksThreadedAdapter"; 39f94abcf44fc1611f76e55461f48220e621fc31b7John Reck private static final boolean DEBUG = false; 40f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 41f94abcf44fc1611f76e55461f48220e621fc31b7John Reck private Context mContext; 42f94abcf44fc1611f76e55461f48220e621fc31b7John Reck private Object mCursorLock = new Object(); 43f94abcf44fc1611f76e55461f48220e621fc31b7John Reck private CursorAdapter mCursorAdapter; 44f94abcf44fc1611f76e55461f48220e621fc31b7John Reck private T mLoadingObject; 45f94abcf44fc1611f76e55461f48220e621fc31b7John Reck private Handler mLoadHandler; 46f94abcf44fc1611f76e55461f48220e621fc31b7John Reck private Handler mHandler; 47f94abcf44fc1611f76e55461f48220e621fc31b7John Reck private int mSize; 483ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck private boolean mHasCursor; 493ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck private long mGeneration; 503ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck 51f94abcf44fc1611f76e55461f48220e621fc31b7John Reck private class LoadContainer { 52f94abcf44fc1611f76e55461f48220e621fc31b7John Reck WeakReference<View> view; 53f94abcf44fc1611f76e55461f48220e621fc31b7John Reck int position; 54f94abcf44fc1611f76e55461f48220e621fc31b7John Reck T bind_object; 55f94abcf44fc1611f76e55461f48220e621fc31b7John Reck Adapter owner; 56f94abcf44fc1611f76e55461f48220e621fc31b7John Reck boolean loaded; 573ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck long generation; 58f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 59f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 60f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public ThreadedCursorAdapter(Context context, Cursor c) { 61f94abcf44fc1611f76e55461f48220e621fc31b7John Reck mContext = context; 623ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck mHasCursor = (c != null); 63f94abcf44fc1611f76e55461f48220e621fc31b7John Reck mCursorAdapter = new CursorAdapter(context, c, 0) { 64f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 65f94abcf44fc1611f76e55461f48220e621fc31b7John Reck @Override 66f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public View newView(Context context, Cursor cursor, ViewGroup parent) { 67f94abcf44fc1611f76e55461f48220e621fc31b7John Reck throw new IllegalStateException("not supported"); 68f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 69f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 70f94abcf44fc1611f76e55461f48220e621fc31b7John Reck @Override 71f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public void bindView(View view, Context context, Cursor cursor) { 72f94abcf44fc1611f76e55461f48220e621fc31b7John Reck throw new IllegalStateException("not supported"); 73f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 74f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 75f94abcf44fc1611f76e55461f48220e621fc31b7John Reck @Override 76f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public void notifyDataSetChanged() { 77f94abcf44fc1611f76e55461f48220e621fc31b7John Reck super.notifyDataSetChanged(); 78f94abcf44fc1611f76e55461f48220e621fc31b7John Reck mSize = getCount(); 793ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck mGeneration++; 80f94abcf44fc1611f76e55461f48220e621fc31b7John Reck ThreadedCursorAdapter.this.notifyDataSetChanged(); 81f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 82f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 83f94abcf44fc1611f76e55461f48220e621fc31b7John Reck @Override 84f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public void notifyDataSetInvalidated() { 85f94abcf44fc1611f76e55461f48220e621fc31b7John Reck super.notifyDataSetInvalidated(); 86f94abcf44fc1611f76e55461f48220e621fc31b7John Reck mSize = getCount(); 873ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck mGeneration++; 88f94abcf44fc1611f76e55461f48220e621fc31b7John Reck ThreadedCursorAdapter.this.notifyDataSetInvalidated(); 89f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 90f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 91f94abcf44fc1611f76e55461f48220e621fc31b7John Reck }; 92f94abcf44fc1611f76e55461f48220e621fc31b7John Reck mSize = mCursorAdapter.getCount(); 93f94abcf44fc1611f76e55461f48220e621fc31b7John Reck HandlerThread thread = new HandlerThread("threaded_adapter_" + this, 94f94abcf44fc1611f76e55461f48220e621fc31b7John Reck Process.THREAD_PRIORITY_BACKGROUND); 95f94abcf44fc1611f76e55461f48220e621fc31b7John Reck thread.start(); 96f94abcf44fc1611f76e55461f48220e621fc31b7John Reck mLoadHandler = new Handler(thread.getLooper()) { 97f94abcf44fc1611f76e55461f48220e621fc31b7John Reck @SuppressWarnings("unchecked") 98f94abcf44fc1611f76e55461f48220e621fc31b7John Reck @Override 99f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public void handleMessage(Message msg) { 100f94abcf44fc1611f76e55461f48220e621fc31b7John Reck if (DEBUG) { 101f94abcf44fc1611f76e55461f48220e621fc31b7John Reck Log.d(LOGTAG, "loading: " + msg.what); 102f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 103f94abcf44fc1611f76e55461f48220e621fc31b7John Reck loadRowObject(msg.what, (LoadContainer) msg.obj); 104f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 105f94abcf44fc1611f76e55461f48220e621fc31b7John Reck }; 106f94abcf44fc1611f76e55461f48220e621fc31b7John Reck mHandler = new Handler() { 107f94abcf44fc1611f76e55461f48220e621fc31b7John Reck @Override 108f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public void handleMessage(Message msg) { 109f94abcf44fc1611f76e55461f48220e621fc31b7John Reck @SuppressWarnings("unchecked") 110f94abcf44fc1611f76e55461f48220e621fc31b7John Reck LoadContainer container = (LoadContainer) msg.obj; 111f94abcf44fc1611f76e55461f48220e621fc31b7John Reck if (container == null) { 112f94abcf44fc1611f76e55461f48220e621fc31b7John Reck return; 113f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 114f94abcf44fc1611f76e55461f48220e621fc31b7John Reck View view = container.view.get(); 115f94abcf44fc1611f76e55461f48220e621fc31b7John Reck if (view == null 116f94abcf44fc1611f76e55461f48220e621fc31b7John Reck || container.owner != ThreadedCursorAdapter.this 1173ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck || container.position != msg.what 1183ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck || view.getWindowToken() == null 1193ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck || container.generation != mGeneration) { 120f94abcf44fc1611f76e55461f48220e621fc31b7John Reck return; 121f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 122f94abcf44fc1611f76e55461f48220e621fc31b7John Reck container.loaded = true; 123f94abcf44fc1611f76e55461f48220e621fc31b7John Reck bindView(view, container.bind_object); 124f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 125f94abcf44fc1611f76e55461f48220e621fc31b7John Reck }; 126f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 127f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 128f94abcf44fc1611f76e55461f48220e621fc31b7John Reck @Override 129f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public int getCount() { 130f94abcf44fc1611f76e55461f48220e621fc31b7John Reck return mSize; 131f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 132f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 133f94abcf44fc1611f76e55461f48220e621fc31b7John Reck @Override 134f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public Cursor getItem(int position) { 135f94abcf44fc1611f76e55461f48220e621fc31b7John Reck return (Cursor) mCursorAdapter.getItem(position); 136f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 137f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 138f94abcf44fc1611f76e55461f48220e621fc31b7John Reck @Override 139f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public long getItemId(int position) { 1409ee87d9ce5aae1460f53bea66bfcafd3671505a0John Reck synchronized (mCursorLock) { 1419ee87d9ce5aae1460f53bea66bfcafd3671505a0John Reck return getItemId(getItem(position)); 1429ee87d9ce5aae1460f53bea66bfcafd3671505a0John Reck } 143f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 144f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 145f94abcf44fc1611f76e55461f48220e621fc31b7John Reck private void loadRowObject(int position, LoadContainer container) { 146f94abcf44fc1611f76e55461f48220e621fc31b7John Reck if (container == null 147f94abcf44fc1611f76e55461f48220e621fc31b7John Reck || container.position != position 148f94abcf44fc1611f76e55461f48220e621fc31b7John Reck || container.owner != ThreadedCursorAdapter.this 149f94abcf44fc1611f76e55461f48220e621fc31b7John Reck || container.view.get() == null) { 150f94abcf44fc1611f76e55461f48220e621fc31b7John Reck return; 151f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 152f94abcf44fc1611f76e55461f48220e621fc31b7John Reck synchronized (mCursorLock) { 153f94abcf44fc1611f76e55461f48220e621fc31b7John Reck Cursor c = (Cursor) mCursorAdapter.getItem(position); 1543ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck if (c == null || c.isClosed()) { 1553ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck return; 1563ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck } 157dedcee2bbf80f32165398af66c5d72e886c102e8John Reck container.bind_object = getRowObject(c, container.bind_object); 158f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 159f94abcf44fc1611f76e55461f48220e621fc31b7John Reck mHandler.obtainMessage(position, container).sendToTarget(); 160f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 161f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 162f94abcf44fc1611f76e55461f48220e621fc31b7John Reck @Override 163f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public View getView(int position, View convertView, ViewGroup parent) { 164f94abcf44fc1611f76e55461f48220e621fc31b7John Reck if (convertView == null) { 165f94abcf44fc1611f76e55461f48220e621fc31b7John Reck convertView = newView(mContext, parent); 166f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 167f94abcf44fc1611f76e55461f48220e621fc31b7John Reck @SuppressWarnings("unchecked") 168f94abcf44fc1611f76e55461f48220e621fc31b7John Reck LoadContainer container = (LoadContainer) convertView.getTag(R.id.load_object); 169f94abcf44fc1611f76e55461f48220e621fc31b7John Reck if (container == null) { 170f94abcf44fc1611f76e55461f48220e621fc31b7John Reck container = new LoadContainer(); 171f94abcf44fc1611f76e55461f48220e621fc31b7John Reck container.view = new WeakReference<View>(convertView); 172f94abcf44fc1611f76e55461f48220e621fc31b7John Reck convertView.setTag(R.id.load_object, container); 173f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 174f94abcf44fc1611f76e55461f48220e621fc31b7John Reck if (container.position == position 175f94abcf44fc1611f76e55461f48220e621fc31b7John Reck && container.owner == this 1763ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck && container.loaded 1773ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck && container.generation == mGeneration) { 178f94abcf44fc1611f76e55461f48220e621fc31b7John Reck bindView(convertView, container.bind_object); 179f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } else { 180f94abcf44fc1611f76e55461f48220e621fc31b7John Reck bindView(convertView, cachedLoadObject()); 1813ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck if (mHasCursor) { 1823ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck container.position = position; 1833ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck container.loaded = false; 1843ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck container.owner = this; 1853ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck container.generation = mGeneration; 1863ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck mLoadHandler.obtainMessage(position, container).sendToTarget(); 1873ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck } 188f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 189f94abcf44fc1611f76e55461f48220e621fc31b7John Reck return convertView; 190f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 191f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 192f94abcf44fc1611f76e55461f48220e621fc31b7John Reck private T cachedLoadObject() { 193f94abcf44fc1611f76e55461f48220e621fc31b7John Reck if (mLoadingObject == null) { 194f94abcf44fc1611f76e55461f48220e621fc31b7John Reck mLoadingObject = getLoadingObject(); 195f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 196f94abcf44fc1611f76e55461f48220e621fc31b7John Reck return mLoadingObject; 197f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 198f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 199f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public void changeCursor(Cursor cursor) { 2003ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck mLoadHandler.removeCallbacksAndMessages(null); 2013ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck mHandler.removeCallbacksAndMessages(null); 202f94abcf44fc1611f76e55461f48220e621fc31b7John Reck synchronized (mCursorLock) { 2033ad8d5cf0911ba015e019bc75e8fb13c091efe0eJohn Reck mHasCursor = (cursor != null); 204f94abcf44fc1611f76e55461f48220e621fc31b7John Reck mCursorAdapter.changeCursor(cursor); 205f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 206f94abcf44fc1611f76e55461f48220e621fc31b7John Reck } 207f94abcf44fc1611f76e55461f48220e621fc31b7John Reck 208f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public abstract View newView(Context context, ViewGroup parent); 209f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public abstract void bindView(View view, T object); 210f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public abstract T getRowObject(Cursor c, T recycleObject); 211f94abcf44fc1611f76e55461f48220e621fc31b7John Reck public abstract T getLoadingObject(); 2129ee87d9ce5aae1460f53bea66bfcafd3671505a0John Reck protected abstract long getItemId(Cursor c); 213f94abcf44fc1611f76e55461f48220e621fc31b7John Reck}