clean up attachment loaders
Need to clean up upon either view recycle or full-on view
detach. Also make sure to finish removing scrap views when
the conversation view is torn down, like AbsListView does.
Change-Id: Icee78edecaec757d66e91b9a692548375ad65227
diff --git a/src/com/android/mail/browse/MessageHeaderView.java b/src/com/android/mail/browse/MessageHeaderView.java
index ba5d551..f1077bf 100644
--- a/src/com/android/mail/browse/MessageHeaderView.java
+++ b/src/com/android/mail/browse/MessageHeaderView.java
@@ -56,6 +56,7 @@
import com.android.mail.providers.Attachment;
import com.android.mail.providers.Message;
import com.android.mail.providers.UIProvider;
+import com.android.mail.ui.ConversationContainer;
import com.android.mail.utils.LogUtils;
import com.android.mail.utils.Utils;
@@ -63,7 +64,8 @@
import java.io.StringReader;
public class MessageHeaderView extends LinearLayout implements OnClickListener,
- OnMenuItemClickListener, HeaderBlock, LoaderManager.LoaderCallbacks<Cursor> {
+ OnMenuItemClickListener, HeaderBlock, LoaderManager.LoaderCallbacks<Cursor>,
+ ConversationContainer.DetachListener {
/**
* Cap very long recipient lists during summary construction for efficiency.
@@ -335,6 +337,14 @@
mDefaultReplyAll = defaultReplyAll;
}
+ private Integer getLoaderId() {
+ Integer id = null;
+ if (mMessage != null && mMessage.uri != null) {
+ id = mMessage.uri.hashCode();
+ }
+ return id;
+ }
+
public int bind(Message message) {
Timer t = new Timer();
t.start(HEADER_RENDER_TAG);
@@ -349,8 +359,6 @@
mCallbacks.onHeaderCreated(mLocalMessageId);
}
- setTag(mLocalMessageId);
-
mTimestampMs = mMessage.dateReceivedMs;
if (mDateBuilder != null) {
mTimestampShort = mDateBuilder.formatShortDate(mTimestampMs);
@@ -367,7 +375,8 @@
// kick off load of Attachment objects in background thread
if (mMessage.hasAttachments) {
- mLoaderManager.initLoader(mMessage.hashCode(), Bundle.EMPTY, this);
+ LogUtils.d(LOG_TAG, "calling initLoader for message %d", getLoaderId());
+ mLoaderManager.initLoader(getLoaderId(), Bundle.EMPTY, this);
// TODO: clean up loader when the view is detached
}
@@ -449,7 +458,27 @@
@Override
public void onLoaderReset(Loader<Cursor> loader) {
- // Do nothing.
+ mAttachments = null;
+ }
+
+ private void destroyLoader() {
+ final Integer loaderId = getLoaderId();
+ if (mLoaderManager != null && loaderId != null) {
+ LogUtils.d(LOG_TAG, "detaching header view, calling destroyLoader for message %d",
+ loaderId);
+ mLoaderManager.destroyLoader(loaderId);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ destroyLoader();
+ }
+
+ @Override
+ public void onDetachedFromParent() {
+ destroyLoader();
}
private boolean isInOutbox() {
diff --git a/src/com/android/mail/ui/ConversationContainer.java b/src/com/android/mail/ui/ConversationContainer.java
index c229c29..24e04a6 100644
--- a/src/com/android/mail/ui/ConversationContainer.java
+++ b/src/com/android/mail/ui/ConversationContainer.java
@@ -123,6 +123,19 @@
private static final int VIEW_TAG_CONVERSATION_INDEX = R.id.view_tag_conversation_index;
+ /**
+ * Child views of this container should implement this interface to be notified when they are
+ * being detached.
+ *
+ */
+ public interface DetachListener {
+ /**
+ * Called on a child view when it is removed from its parent as part of
+ * {@link ConversationContainer} view recycling.
+ */
+ void onDetachedFromParent();
+ }
+
public ConversationContainer(Context c) {
this(c, null);
}
@@ -333,6 +346,19 @@
detachViewFromParent(overlayView);
mScrapViews.add(overlayView);
mChildrenToRemove.remove(overlayView);
+ if (overlayView instanceof DetachListener) {
+ ((DetachListener) overlayView).onDetachedFromParent();
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ for (View scrap : mScrapViews) {
+ removeDetachedView(scrap, false /* animate */);
+ }
+ mScrapViews.clear();
}
@Override