diff options
author | Winson Chung <winsonc@google.com> | 2012-08-28 12:45:56 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-08-28 12:45:56 -0700 |
commit | 1e533d01d52076c33414419930598c1d03f1b4a6 (patch) | |
tree | 2359a9e16f527a2f80521aad5c0ff6bc4fa0f608 /src/com/android | |
parent | 13bdaf7c9d3e4539e2db5d9f4c2bb4d8b7a8dd79 (diff) | |
parent | 81b52252796625dcbadc9f8b908f8d8a284565c0 (diff) | |
download | android_packages_apps_Trebuchet-1e533d01d52076c33414419930598c1d03f1b4a6.tar.gz android_packages_apps_Trebuchet-1e533d01d52076c33414419930598c1d03f1b4a6.tar.bz2 android_packages_apps_Trebuchet-1e533d01d52076c33414419930598c1d03f1b4a6.zip |
Merge "Ensuring that unbind calls are not queued in the worker thread and executed subsequently on the main thread. (Bug 7001531)" into jb-mr1-dev
Diffstat (limited to 'src/com/android')
-rw-r--r-- | src/com/android/launcher2/DeferredHandler.java | 42 | ||||
-rw-r--r-- | src/com/android/launcher2/Launcher.java | 17 | ||||
-rw-r--r-- | src/com/android/launcher2/LauncherModel.java | 44 |
3 files changed, 66 insertions, 37 deletions
diff --git a/src/com/android/launcher2/DeferredHandler.java b/src/com/android/launcher2/DeferredHandler.java index b7e48b130..cee27dfa8 100644 --- a/src/com/android/launcher2/DeferredHandler.java +++ b/src/com/android/launcher2/DeferredHandler.java @@ -16,12 +16,13 @@ package com.android.launcher2; -import java.util.LinkedList; - import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; +import android.util.Pair; +import java.util.LinkedList; +import java.util.ListIterator; /** * Queue of things to run on a looper thread. Items posted with {@link #post} will not @@ -31,18 +32,20 @@ import android.os.MessageQueue; * This class is fifo. */ public class DeferredHandler { - private LinkedList<Runnable> mQueue = new LinkedList<Runnable>(); + private LinkedList<Pair<Runnable, Integer>> mQueue = new LinkedList<Pair<Runnable, Integer>>(); private MessageQueue mMessageQueue = Looper.myQueue(); private Impl mHandler = new Impl(); private class Impl extends Handler implements MessageQueue.IdleHandler { public void handleMessage(Message msg) { + Pair<Runnable, Integer> p; Runnable r; synchronized (mQueue) { if (mQueue.size() == 0) { return; } - r = mQueue.removeFirst(); + p = mQueue.removeFirst(); + r = p.first; } r.run(); synchronized (mQueue) { @@ -73,8 +76,11 @@ public class DeferredHandler { /** Schedule runnable to run after everything that's on the queue right now. */ public void post(Runnable runnable) { + post(runnable, 0); + } + public void post(Runnable runnable, int type) { synchronized (mQueue) { - mQueue.add(runnable); + mQueue.add(new Pair<Runnable, Integer>(runnable, type)); if (mQueue.size() == 1) { scheduleNextLocked(); } @@ -83,7 +89,10 @@ public class DeferredHandler { /** Schedule runnable to run when the queue goes idle. */ public void postIdle(final Runnable runnable) { - post(new IdleRunnable(runnable)); + postIdle(runnable, 0); + } + public void postIdle(final Runnable runnable, int type) { + post(new IdleRunnable(runnable), type); } public void cancelRunnable(Runnable runnable) { @@ -91,6 +100,18 @@ public class DeferredHandler { while (mQueue.remove(runnable)) { } } } + public void cancelAllRunnablesOfType(int type) { + synchronized (mQueue) { + ListIterator<Pair<Runnable, Integer>> iter = mQueue.listIterator(); + Pair<Runnable, Integer> p; + while (iter.hasNext()) { + p = iter.next(); + if (p.second == type) { + iter.remove(); + } + } + } + } public void cancel() { synchronized (mQueue) { @@ -100,19 +121,20 @@ public class DeferredHandler { /** Runs all queued Runnables from the calling thread. */ public void flush() { - LinkedList<Runnable> queue = new LinkedList<Runnable>(); + LinkedList<Pair<Runnable, Integer>> queue = new LinkedList<Pair<Runnable, Integer>>(); synchronized (mQueue) { queue.addAll(mQueue); mQueue.clear(); } - for (Runnable r : queue) { - r.run(); + for (Pair<Runnable, Integer> p : queue) { + p.first.run(); } } void scheduleNextLocked() { if (mQueue.size() > 0) { - Runnable peek = mQueue.getFirst(); + Pair<Runnable, Integer> p = mQueue.getFirst(); + Runnable peek = p.first; if (peek instanceof IdleRunnable) { mMessageQueue.addIdleHandler(mHandler); } else { diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java index 1e138f772..2fcf86925 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -1486,8 +1486,11 @@ public final class Launcher extends Activity TextKeyListener.getInstance().release(); - - unbindWorkspaceAndHotseatItems(); + // Disconnect any of the callbacks and drawables associated with ItemInfos on the workspace + // to prevent leaking Launcher activities on orientation change. + if (mModel != null) { + mModel.unbindItemInfosAndClearQueuedBindRunnables(); + } getContentResolver().unregisterContentObserver(mWidgetObserver); unregisterReceiver(mCloseSystemDialogsReceiver); @@ -1878,16 +1881,6 @@ public final class Launcher extends Activity } /** - * Go through the and disconnect any of the callbacks in the drawables and the views or we - * leak the previous Home screen on orientation change. - */ - private void unbindWorkspaceAndHotseatItems() { - if (mModel != null) { - mModel.unbindWorkspaceItems(); - } - } - - /** * Launches the intent referred by the clicked shortcut. * * @param v The view representing the clicked shortcut. diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java index 792759399..269a0fd60 100644 --- a/src/com/android/launcher2/LauncherModel.java +++ b/src/com/android/launcher2/LauncherModel.java @@ -82,6 +82,12 @@ public class LauncherModel extends BroadcastReceiver { private LoaderTask mLoaderTask; private boolean mIsLoaderTaskRunning; + // Specific runnable types that are run on the main thread deferred handler, this allows us to + // clear all queued binding runnables when the Launcher activity is destroyed. + private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0; + private static final int MAIN_THREAD_BINDING_RUNNABLE = 1; + + private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader"); static { sWorkerThread.start(); @@ -177,6 +183,9 @@ public class LauncherModel extends BroadcastReceiver { /** Runs the specified runnable immediately if called from the main thread, otherwise it is * posted on the main thread handler. */ private void runOnMainThread(Runnable r) { + runOnMainThread(r, 0); + } + private void runOnMainThread(Runnable r, int type) { if (sWorkerThread.getThreadId() == Process.myTid()) { // If we are on the worker thread, post onto the main handler mHandler.post(r); @@ -200,17 +209,22 @@ public class LauncherModel extends BroadcastReceiver { return Bitmap.createBitmap(mDefaultIcon); } - public void unbindWorkspaceItems() { - sWorker.post(new Runnable() { - @Override - public void run() { - unbindWorkspaceItemsOnMainThread(); - } - }); + public void unbindItemInfosAndClearQueuedBindRunnables() { + if (sWorkerThread.getThreadId() == Process.myTid()) { + throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " + + "main thread"); + } + + // Clear any deferred bind runnables + mDeferredBindRunnables.clear(); + // Remove any queued bind runnables + mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE); + // Unbind all the workspace items + unbindWorkspaceItemsOnMainThread(); } /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */ - private void unbindWorkspaceItemsOnMainThread() { + void unbindWorkspaceItemsOnMainThread() { // Ensure that we don't use the same workspace items data structure on the main thread // by making a copy of workspace items first. final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>(); @@ -880,7 +894,7 @@ public class LauncherModel extends BroadcastReceiver { // Post the remaining side pages to be loaded if (!mDeferredBindRunnables.isEmpty()) { for (final Runnable r : mDeferredBindRunnables) { - mHandler.post(r); + mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE); } mDeferredBindRunnables.clear(); } @@ -1602,7 +1616,7 @@ public class LauncherModel extends BroadcastReceiver { if (postOnMainThread) { deferredBindRunnables.add(r); } else { - runOnMainThread(r); + runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); } } @@ -1619,7 +1633,7 @@ public class LauncherModel extends BroadcastReceiver { if (postOnMainThread) { deferredBindRunnables.add(r); } else { - runOnMainThread(r); + runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); } } @@ -1638,7 +1652,7 @@ public class LauncherModel extends BroadcastReceiver { if (postOnMainThread) { deferredBindRunnables.add(r); } else { - runOnMainThread(r); + runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); } } } @@ -1706,7 +1720,7 @@ public class LauncherModel extends BroadcastReceiver { } } }; - runOnMainThread(r); + runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); // Load items on the current page bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets, @@ -1720,7 +1734,7 @@ public class LauncherModel extends BroadcastReceiver { } } }; - runOnMainThread(r); + runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); } // Load all the remaining pages (if we are loading synchronously, we want to defer this @@ -1749,7 +1763,7 @@ public class LauncherModel extends BroadcastReceiver { if (isLoadingSynchronously) { mDeferredBindRunnables.add(r); } else { - runOnMainThread(r); + runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); } } |