diff options
author | Android (Google) Code Review <android-gerrit@google.com> | 2009-05-12 23:54:40 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2009-05-12 23:54:40 -0700 |
commit | 4af352aa53952e4c69563aee95c87140bd528f71 (patch) | |
tree | a20aa6e041648a7bf1090747cc46951a1cd5a53c /src/com/android/camera | |
parent | bdaaf5ea009b8b652c7a638e6bc94bfc01da921b (diff) | |
parent | 341ad98e59d92769e1cc8ba68fa86c72dce0543b (diff) | |
download | LegacyCamera-4af352aa53952e4c69563aee95c87140bd528f71.zip LegacyCamera-4af352aa53952e4c69563aee95c87140bd528f71.tar.gz LegacyCamera-4af352aa53952e4c69563aee95c87140bd528f71.tar.bz2 |
Merge change 1440 into donut
* changes:
Make ImageLoader load image in order.
Diffstat (limited to 'src/com/android/camera')
-rw-r--r-- | src/com/android/camera/GridViewSpecial.java | 92 | ||||
-rw-r--r-- | src/com/android/camera/ImageLoader.java | 97 | ||||
-rw-r--r-- | src/com/android/camera/Util.java | 6 |
3 files changed, 109 insertions, 86 deletions
diff --git a/src/com/android/camera/GridViewSpecial.java b/src/com/android/camera/GridViewSpecial.java index 23fd063..87751b3 100644 --- a/src/com/android/camera/GridViewSpecial.java +++ b/src/com/android/camera/GridViewSpecial.java @@ -38,6 +38,8 @@ import android.widget.Scroller; import java.util.HashMap; +import static com.android.camera.Util.Assert; + class GridViewSpecial extends View { private static final String TAG = "GridViewSpecial"; @@ -140,28 +142,28 @@ class GridViewSpecial extends View { }; public void setLoader(ImageLoader loader) { - assert mRunning == false; + Assert(mRunning == false); mLoader = loader; } public void setListener(Listener listener) { - assert mRunning == false; + Assert(mRunning == false); mListener = listener; } public void setDrawAdapter(DrawAdapter adapter) { - assert mRunning == false; + Assert(mRunning == false); mDrawAdapter = adapter; } public void setImageList(IImageList list) { - assert mRunning == false; + Assert(mRunning == false); mAllImages = list; mCount = mAllImages.getCount(); } public void setSizeChoice(int choice) { - assert mRunning == false; + Assert(mRunning == false); if (mSizeChoice == choice) return; mSizeChoice = choice; } @@ -332,7 +334,7 @@ class GridViewSpecial extends View { } @Override - public boolean onSingleTapUp(MotionEvent e) { + public boolean onSingleTapConfirmed(MotionEvent e) { select(mCurrentSelection, false); int index = computeSelectedIndex(e.getX(), e.getY()); if (index >= 0 && index < mCount) { @@ -418,9 +420,9 @@ class GridViewSpecial extends View { public void start() { // These must be set before start(). - assert mLoader != null; - assert mListener != null; - assert mDrawAdapter != null; + Assert(mLoader != null); + Assert(mListener != null); + Assert(mDrawAdapter != null); mRunning = true; requestLayout(); } @@ -706,8 +708,29 @@ class ImageBlockManager { static final int REQUESTS_LOW = 3; static final int REQUESTS_HIGH = 6; - // Scan the cache and send requests to ImageLoader if needed. + // After clear requests currently in queue, start loading the thumbnails. + // We need to clear the queue first because the proper order of loading + // may have changed (because the visible region changed, or some images + // have been invalidated). private void startLoading() { + clearLoaderQueue(); + continueLoading(); + } + + private void clearLoaderQueue() { + int[] tags = mLoader.clearQueue(); + for (int pos : tags) { + int row = pos / mColumns; + int col = pos - row * mColumns; + ImageBlock blk = mCache.get(row); + Assert(blk != null); // We won't reuse the block if it has pending + // requests. See getEmptyBlock(). + blk.cancelRequest(col); + } + } + + // Scan the cache and send requests to ImageLoader if needed. + private void continueLoading() { // Check if we still have enough requests in the queue. if (mPendingRequest >= REQUESTS_LOW) return; @@ -722,10 +745,10 @@ class ImageBlockManager { for (int d = 1; d <= range; d++) { int after = mEndRow - 1 + d; int before = mStartRow - d; - if (after >= mCount && before < 0) { + if (after >= mRows && before < 0) { break; // Nothing more the scan. } - if (after < mCount && scanOne(after)) return; + if (after < mRows && scanOne(after)) return; if (before >= 0 && scanOne(before)) return; } } @@ -738,7 +761,7 @@ class ImageBlockManager { // Returns number of requests we issued for this row. private int tryToLoad(int row) { - assert row >= 0 && row < mRows; + Assert(row >= 0 && row < mRows); ImageBlock blk = mCache.get(row); if (blk == null) { // Find an empty block @@ -762,7 +785,7 @@ class ImageBlockManager { for (int index : mCache.keySet()) { // Make sure we don't reclaim a block which still has pending // request. - if (mCache.get(index).isBusy()) { + if (mCache.get(index).hasPendingRequests()) { continue; } int dist = 0; @@ -906,7 +929,7 @@ class ImageBlockManager { } public void invalidate() { - // We do not change mRequestedMask or do cancelExistingRequests() + // We do not change mRequestedMask or do cancelAllRequests() // because the data coming from pending requests are valid. (We only // invalidate data which has been drawn to the bitmap). mCompletedMask = 0; @@ -914,7 +937,7 @@ class ImageBlockManager { // After recycle, the ImageBlock instance should not be accessed. public void recycle() { - cancelExistingRequests(); + cancelAllRequests(); mBitmap.recycle(); mBitmap = null; } @@ -925,7 +948,7 @@ class ImageBlockManager { // Returns number of requests submitted to ImageLoader. public int loadImages() { - assert mRow != -1; + Assert(mRow != -1); int columns = numColumns(mRow); @@ -966,7 +989,7 @@ class ImageBlockManager { } }; // Load Image - mLoader.getBitmap(image, cb, isVisible()); + mLoader.getBitmap(image, cb, pos); mRequestedMask |= (1 << col); retVal += 1; } @@ -976,7 +999,7 @@ class ImageBlockManager { } // Whether this block has pending requests. - public boolean isBusy() { + public boolean hasPendingRequests() { return mRequestedMask != 0; } @@ -998,20 +1021,18 @@ class ImageBlockManager { } int mask = (1 << col); - assert (mRequestedMask & mask) != 0; - assert (mCompletedMask & mask) == 0; + Assert((mCompletedMask & mask) == 0); + Assert((mRequestedMask & mask) != 0); mRequestedMask &= ~mask; mCompletedMask |= mask; mPendingRequest--; - if (mRequestedMask == 0) { - if (isVisible()) { - mRedrawCallback.run(); - } + if (isVisible()) { + mRedrawCallback.run(); } // Kick start next block loading. - startLoading(); + continueLoading(); } // Draw the loaded bitmap to the block bitmap. @@ -1059,11 +1080,20 @@ class ImageBlockManager { } } - // Try to cancel pending requests. After this there could still be - // requests not cancelled (because it is already in progress). We deal - // with that situation by setting mBitmap to null in recycle() and check - // this in loadImageDone(). - private void cancelExistingRequests() { + // Mark a request as cancelled. The request has already been removed + // from the queue of ImageLoader, so we only need to mark the fact. + public void cancelRequest(int col) { + int mask = (1 << col); + Assert((mRequestedMask & mask) != 0); + mRequestedMask &= ~mask; + mPendingRequest--; + } + + // Try to cancel all pending requests for this block. After this + // completes there could still be requests not cancelled (because it is + // already in progress). We deal with that situation by setting mBitmap to + // null in recycle() and check this in loadImageDone(). + private void cancelAllRequests() { for (int i = 0; i < mColumns; i++) { int mask = (1 << i); if ((mRequestedMask & mask) != 0) { diff --git a/src/com/android/camera/ImageLoader.java b/src/com/android/camera/ImageLoader.java index a349ea8..e71f5c3 100644 --- a/src/com/android/camera/ImageLoader.java +++ b/src/com/android/camera/ImageLoader.java @@ -33,9 +33,8 @@ public class ImageLoader { @SuppressWarnings("unused") private static final String TAG = "ImageLoader"; - // queue of work to do in the worker thread + // Queue of work to do in the worker thread. The work is done in order. private final ArrayList<WorkItem> mQueue = new ArrayList<WorkItem>(); - private final ArrayList<WorkItem> mInProgress = new ArrayList<WorkItem>(); // the worker thread and a done flag so we know when to exit private boolean mDone; @@ -58,66 +57,63 @@ public class ImageLoader { public void run(Bitmap result); } - public boolean cancel(final IImage image) { + public void getBitmap(IImage image, + LoadedCallback imageLoadedRunnable, + int tag) { + if (mDecodeThread == null) { + start(); + } synchronized (mQueue) { - WorkItem w = new WorkItem(image, null); + WorkItem w = new WorkItem(image, imageLoadedRunnable, tag); + mQueue.add(w); + mQueue.notifyAll(); + } + } - int existing = mQueue.indexOf(w); - if (existing >= 0) { - mQueue.remove(existing); + public boolean cancel(final IImage image) { + synchronized (mQueue) { + int index = findItem(image); + if (index >= 0) { + mQueue.remove(index); return true; + } else { + return false; } - return false; } } - public void getBitmap(IImage image, - LoadedCallback imageLoadedRunnable, - boolean postAtFront) { - if (mDecodeThread == null) { - start(); + // The caller should hold mQueue lock. + private int findItem(IImage image) { + for (int i = 0; i < mQueue.size(); i++) { + if (mQueue.get(i).mImage == image) { + return i; + } } - synchronized (mQueue) { - WorkItem w = new WorkItem(image, imageLoadedRunnable); - - if (mInProgress.contains(w)) return; + return -1; + } - boolean contains = mQueue.contains(w); - if (contains) { - if (postAtFront) { - // move this item to the front - mQueue.remove(w); - mQueue.add(0, w); - } - } else { - if (postAtFront) { - mQueue.add(0, w); - } else { - mQueue.add(w); - } - mQueue.notifyAll(); + // Clear the queue. Returns an array of tags that were in the queue. + public int[] clearQueue() { + synchronized (mQueue) { + int n = mQueue.size(); + int[] tags = new int[n]; + for (int i = 0; i < n; i++) { + tags[i] = mQueue.get(i).mTag; } + mQueue.clear(); + return tags; } } private class WorkItem { IImage mImage; LoadedCallback mOnLoadedRunnable; + int mTag; - WorkItem(IImage image, LoadedCallback onLoadedRunnable) { + WorkItem(IImage image, LoadedCallback onLoadedRunnable, int tag) { mImage = image; mOnLoadedRunnable = onLoadedRunnable; - } - - @Override - public boolean equals(Object other) { - WorkItem otherWorkItem = (WorkItem) other; - return otherWorkItem.mImage == mImage; - } - - @Override - public int hashCode() { - return mImage.fullSizeImageUri().hashCode(); + mTag = tag; } } @@ -128,16 +124,15 @@ public class ImageLoader { } private class WorkerThread implements Runnable { - // pick off items on the queue, one by one, and compute their bitmap. - // place the resulting bitmap in the cache. then callback by executing + // Pick off items on the queue, one by one, and compute their bitmap. + // Place the resulting bitmap in the cache, then call back by executing // the given runnable so things can get updated appropriately. public void run() { while (!mDone) { WorkItem workItem = null; synchronized (mQueue) { - if (mQueue.size() > 0) { + if (!mQueue.isEmpty()) { workItem = mQueue.remove(0); - mInProgress.add(workItem); } else { if (!mThumbnailChecker.hasMoreThumbnailsToCheck()) { try { @@ -160,14 +155,6 @@ public class ImageLoader { final Bitmap b = workItem.mImage.miniThumbBitmap(); - synchronized (mQueue) { - mInProgress.remove(workItem); - } - - if (mDone) { - break; - } - if (workItem.mOnLoadedRunnable != null) { workItem.mOnLoadedRunnable.run(b); } diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java index 4991d0e..991fe39 100644 --- a/src/com/android/camera/Util.java +++ b/src/com/android/camera/Util.java @@ -406,4 +406,10 @@ public class Util { } return sNullOnClickListener; } + + public static void Assert(boolean cond) { + if (!cond) { + throw new AssertionError(); + } + } } |