diff options
author | Bobby Georgescu <georgescu@google.com> | 2013-02-13 19:23:54 -0800 |
---|---|---|
committer | Bobby Georgescu <georgescu@google.com> | 2013-02-14 18:04:03 -0800 |
commit | 61d3ab7bdff78b5a3b79de5b4902fc92fe63c587 (patch) | |
tree | 797acfaf42c9eab4163522ffb0259262ef5c3dd1 /src | |
parent | da7b84da52579cc967816e11f10acd9d9b3c714b (diff) | |
download | android_packages_apps_Snap-61d3ab7bdff78b5a3b79de5b4902fc92fe63c587.tar.gz android_packages_apps_Snap-61d3ab7bdff78b5a3b79de5b4902fc92fe63c587.tar.bz2 android_packages_apps_Snap-61d3ab7bdff78b5a3b79de5b4902fc92fe63c587.zip |
Don't use AsyncTasks to fetch images via MTP
Bug: 8192491
Avoids allocations when scrolling through the importer
grid by not using AsyncTasks anymore (which meant one
object creation per change of the source image). Also
fix an NPE if a device is unplugged during scrolling.
Change-Id: I4e7022ca5d4573402e60b16fbd82ea65bc6627e0
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java | 2 | ||||
-rw-r--r-- | src/com/android/gallery3d/ingest/ui/MtpImageView.java | 121 |
2 files changed, 81 insertions, 42 deletions
diff --git a/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java b/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java index 88645e8d0..46a2051be 100644 --- a/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java +++ b/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java @@ -43,6 +43,7 @@ public class MtpBitmapFetch { public static Bitmap getThumbnail(MtpDevice device, MtpObjectInfo info) { byte[] imageBytes = device.getThumbnail(info.getObjectHandle()); + if (imageBytes == null) return null; BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, o); @@ -60,6 +61,7 @@ public class MtpBitmapFetch { public static BitmapWithMetadata getFullsize(MtpDevice device, MtpObjectInfo info, int maxSide) { byte[] imageBytes = device.getObject(info.getObjectHandle(), info.getCompressedSize()); + if (imageBytes == null) return null; Bitmap created; if (maxSide > 0) { BitmapFactory.Options o = new BitmapFactory.Options(); diff --git a/src/com/android/gallery3d/ingest/ui/MtpImageView.java b/src/com/android/gallery3d/ingest/ui/MtpImageView.java index 9c197851e..5664d8a34 100644 --- a/src/com/android/gallery3d/ingest/ui/MtpImageView.java +++ b/src/com/android/gallery3d/ingest/ui/MtpImageView.java @@ -19,19 +19,32 @@ package com.android.gallery3d.ingest.ui; import android.content.Context; import android.mtp.MtpDevice; import android.mtp.MtpObjectInfo; -import android.os.AsyncTask; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; import android.util.AttributeSet; import android.widget.ImageView; import com.android.gallery3d.ingest.data.BitmapWithMetadata; import com.android.gallery3d.ingest.data.MtpBitmapFetch; -public class MtpImageView extends ImageView { - private static final int FADE_IN_TIME_MS = 80; +import java.lang.ref.WeakReference; +public class MtpImageView extends ImageView { private int mObjectHandle; private int mGeneration; + private WeakReference<MtpImageView> mWeakReference = new WeakReference<MtpImageView>(this); + private Object mFetchLock = new Object(); + private boolean mFetchPending = false; + private MtpObjectInfo mFetchObjectInfo; + private MtpDevice mFetchDevice; + private Object mFetchResult; + + private static final FetchImageHandler sFetchHandler = FetchImageHandler.createOnNewThread(); + private static final ShowImageHandler sFetchCompleteHandler = new ShowImageHandler(); + private void init() { showPlaceholder(); } @@ -55,8 +68,6 @@ public class MtpImageView extends ImageView { setImageResource(android.R.color.transparent); } - private LoadMtpImageTask mTask; - public void setMtpDeviceAndObjectInfo(MtpDevice device, MtpObjectInfo object, int gen) { int handle = object.getObjectHandle(); if (handle == mObjectHandle && gen == mGeneration) { @@ -66,8 +77,14 @@ public class MtpImageView extends ImageView { showPlaceholder(); mGeneration = gen; mObjectHandle = handle; - mTask = new LoadMtpImageTask(device); - mTask.execute(object); + synchronized (mFetchLock) { + mFetchObjectInfo = object; + mFetchDevice = device; + if (mFetchPending) return; + mFetchPending = true; + sFetchHandler.sendMessage( + sFetchHandler.obtainMessage(0, mWeakReference)); + } } protected Object fetchMtpImageDataFromDevice(MtpDevice device, MtpObjectInfo info) { @@ -80,51 +97,71 @@ public class MtpImageView extends ImageView { setRotation(bitmapWithMetadata.rotationDegrees); } - private class LoadMtpImageTask extends AsyncTask<MtpObjectInfo, Void, Object> { - private MtpDevice mDevice; - - public LoadMtpImageTask(MtpDevice device) { - mDevice = device; + protected void cancelLoadingAndClear() { + synchronized (mFetchLock) { + mFetchDevice = null; + mFetchObjectInfo = null; + mFetchResult = null; } + setImageResource(android.R.color.transparent); + setRotation(0); + } - @Override - protected Object doInBackground(MtpObjectInfo... args) { - Object result = null; - if (!isCancelled()) { - result = fetchMtpImageDataFromDevice(mDevice, args[0]); - } - mDevice = null; - return result; + @Override + public void onDetachedFromWindow() { + cancelLoadingAndClear(); + super.onDetachedFromWindow(); + } + + private static class FetchImageHandler extends Handler { + public FetchImageHandler(Looper l) { + super(l); } - @Override - protected void onPostExecute(Object result) { - if (isCancelled() || result == null) { - return; - } - setAlpha(0f); - onMtpImageDataFetchedFromDevice(result); - animate().alpha(1f).setDuration(FADE_IN_TIME_MS); + public static FetchImageHandler createOnNewThread() { + HandlerThread t = new HandlerThread("MtpImageView Fetch"); + t.start(); + return new FetchImageHandler(t.getLooper()); } @Override - protected void onCancelled() { + public void handleMessage(Message msg) { + @SuppressWarnings("unchecked") + MtpImageView parent = ((WeakReference<MtpImageView>) msg.obj).get(); + if (parent == null) return; + MtpObjectInfo objectInfo; + MtpDevice device; + synchronized (parent.mFetchLock) { + parent.mFetchPending = false; + device = parent.mFetchDevice; + objectInfo = parent.mFetchObjectInfo; + } + if (device == null) return; + Object result = parent.fetchMtpImageDataFromDevice(device, objectInfo); + if (result == null) return; + synchronized (parent.mFetchLock) { + if (parent.mFetchObjectInfo != objectInfo) return; + parent.mFetchResult = result; + parent.mFetchDevice = null; + parent.mFetchObjectInfo = null; + sFetchCompleteHandler.sendMessage( + sFetchCompleteHandler.obtainMessage(0, parent.mWeakReference)); + } } } - protected void cancelLoadingAndClear() { - if (mTask != null) { - mTask.cancel(true); + private static class ShowImageHandler extends Handler { + @Override + public void handleMessage(Message msg) { + @SuppressWarnings("unchecked") + MtpImageView parent = ((WeakReference<MtpImageView>) msg.obj).get(); + if (parent == null) return; + Object result; + synchronized (parent.mFetchLock) { + result = parent.mFetchResult; + } + if (result == null) return; + parent.onMtpImageDataFetchedFromDevice(result); } - mTask = null; - animate().cancel(); - setImageResource(android.R.color.transparent); - setRotation(0); - } - - @Override - public void onDetachedFromWindow() { - cancelLoadingAndClear(); - super.onDetachedFromWindow(); } } |