summaryrefslogtreecommitdiff
path: root/src/com/android/browser/util/ThreadedCursorAdapter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/browser/util/ThreadedCursorAdapter.java')
-rw-r--r--src/com/android/browser/util/ThreadedCursorAdapter.java193
1 files changed, 193 insertions, 0 deletions
diff --git a/src/com/android/browser/util/ThreadedCursorAdapter.java b/src/com/android/browser/util/ThreadedCursorAdapter.java
new file mode 100644
index 00000000..fe59ad1c
--- /dev/null
+++ b/src/com/android/browser/util/ThreadedCursorAdapter.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.browser.util;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.os.Process;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Adapter;
+import android.widget.BaseAdapter;
+import android.widget.CursorAdapter;
+
+import com.android.browser.R;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+
+public abstract class ThreadedCursorAdapter<T> extends BaseAdapter {
+
+ private static final String LOGTAG = "tca";
+ private static final boolean DEBUG = false;
+
+ private Context mContext;
+ private Object mCursorLock = new Object();
+ private CursorAdapter mCursorAdapter;
+ private T mLoadingObject;
+ private Handler mLoadHandler;
+ private Handler mHandler;
+ private int mSize;
+
+ private class LoadContainer {
+ WeakReference<View> view;
+ int position;
+ T bind_object;
+ Adapter owner;
+ boolean loaded;
+ }
+
+ public ThreadedCursorAdapter(Context context, Cursor c) {
+ mContext = context;
+ mCursorAdapter = new CursorAdapter(context, c, 0) {
+
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ throw new IllegalStateException("not supported");
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ throw new IllegalStateException("not supported");
+ }
+
+ @Override
+ public void notifyDataSetChanged() {
+ super.notifyDataSetChanged();
+ mSize = getCount();
+ ThreadedCursorAdapter.this.notifyDataSetChanged();
+ }
+
+ @Override
+ public void notifyDataSetInvalidated() {
+ super.notifyDataSetInvalidated();
+ mSize = getCount();
+ ThreadedCursorAdapter.this.notifyDataSetInvalidated();
+ }
+
+ };
+ mSize = mCursorAdapter.getCount();
+ HandlerThread thread = new HandlerThread("threaded_adapter_" + this,
+ Process.THREAD_PRIORITY_BACKGROUND);
+ thread.start();
+ mLoadHandler = new Handler(thread.getLooper()) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void handleMessage(Message msg) {
+ if (DEBUG) {
+ Log.d(LOGTAG, "loading: " + msg.what);
+ }
+ loadRowObject(msg.what, (LoadContainer) msg.obj);
+ }
+ };
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ @SuppressWarnings("unchecked")
+ LoadContainer container = (LoadContainer) msg.obj;
+ if (container == null) {
+ return;
+ }
+ View view = container.view.get();
+ if (view == null
+ || container.owner != ThreadedCursorAdapter.this
+ || container.position != msg.what) {
+ return;
+ }
+ container.loaded = true;
+ bindView(view, container.bind_object);
+ }
+ };
+ }
+
+ @Override
+ public int getCount() {
+ return mSize;
+ }
+
+ @Override
+ public Cursor getItem(int position) {
+ return (Cursor) mCursorAdapter.getItem(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ private void loadRowObject(int position, LoadContainer container) {
+ if (container == null
+ || container.position != position
+ || container.owner != ThreadedCursorAdapter.this
+ || container.view.get() == null) {
+ return;
+ }
+ synchronized (mCursorLock) {
+ Cursor c = (Cursor) mCursorAdapter.getItem(position);
+ container.bind_object = getRowObject(c, container.bind_object);
+ }
+ mHandler.obtainMessage(position, container).sendToTarget();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = newView(mContext, parent);
+ }
+ @SuppressWarnings("unchecked")
+ LoadContainer container = (LoadContainer) convertView.getTag(R.id.load_object);
+ if (container == null) {
+ container = new LoadContainer();
+ container.view = new WeakReference<View>(convertView);
+ convertView.setTag(R.id.load_object, container);
+ }
+ if (container.position == position
+ && container.owner == this
+ && container.loaded) {
+ bindView(convertView, container.bind_object);
+ } else {
+ bindView(convertView, cachedLoadObject());
+ container.position = position;
+ container.loaded = false;
+ container.owner = this;
+ mLoadHandler.obtainMessage(position, container).sendToTarget();
+ }
+ return convertView;
+ }
+
+ private T cachedLoadObject() {
+ if (mLoadingObject == null) {
+ mLoadingObject = getLoadingObject();
+ }
+ return mLoadingObject;
+ }
+
+ public void changeCursor(Cursor cursor) {
+ synchronized (mCursorLock) {
+ mCursorAdapter.changeCursor(cursor);
+ }
+ }
+
+ public abstract View newView(Context context, ViewGroup parent);
+ public abstract void bindView(View view, T object);
+ public abstract T getRowObject(Cursor c, T recycleObject);
+ public abstract T getLoadingObject();
+} \ No newline at end of file