mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 22:29:53 +01:00
Merge branch '851-refresher-memory-leak' into 'master'
Fix memory leaks caused by periodic view refreshing tasks This branch implements @goapunk's suggested solution to #851. Credit goes to @ernir for finding the bug and the initial solution, and @goapunk for the improved solution - I just did a quick implementation so we can get this fixed as quickly as possible. Closes #851 See merge request !473
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
package org.briarproject.briar.android.blog;
|
package org.briarproject.briar.android.blog;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.support.annotation.CallSuper;
|
import android.support.annotation.CallSuper;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -20,7 +22,7 @@ import javax.annotation.Nullable;
|
|||||||
|
|
||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.MIN_RESOLUTION;
|
import static org.briarproject.briar.android.util.UiUtils.MIN_DATE_RESOLUTION;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@@ -32,8 +34,9 @@ abstract class BasePostFragment extends BaseFragment {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(BasePostFragment.class.getName());
|
Logger.getLogger(BasePostFragment.class.getName());
|
||||||
|
|
||||||
|
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
protected MessageId postId;
|
protected MessageId postId;
|
||||||
private View view;
|
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
private BlogPostViewHolder ui;
|
private BlogPostViewHolder ui;
|
||||||
private BlogPostItem post;
|
private BlogPostItem post;
|
||||||
@@ -50,7 +53,7 @@ abstract class BasePostFragment extends BaseFragment {
|
|||||||
if (p == null) throw new IllegalStateException("No post ID in args");
|
if (p == null) throw new IllegalStateException("No post ID in args");
|
||||||
postId = new MessageId(p);
|
postId = new MessageId(p);
|
||||||
|
|
||||||
view = inflater.inflate(R.layout.fragment_blog_post, container,
|
View view = inflater.inflate(R.layout.fragment_blog_post, container,
|
||||||
false);
|
false);
|
||||||
progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
|
progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
|
||||||
progressBar.setVisibility(VISIBLE);
|
progressBar.setVisibility(VISIBLE);
|
||||||
@@ -83,21 +86,19 @@ abstract class BasePostFragment extends BaseFragment {
|
|||||||
refresher = new Runnable() {
|
refresher = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (ui == null) return;
|
|
||||||
LOG.info("Updating Content...");
|
LOG.info("Updating Content...");
|
||||||
|
|
||||||
ui.updateDate(post.getTimestamp());
|
ui.updateDate(post.getTimestamp());
|
||||||
view.postDelayed(refresher, MIN_RESOLUTION);
|
handler.postDelayed(refresher, MIN_DATE_RESOLUTION);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
LOG.info("Adding Handler Callback");
|
LOG.info("Adding Handler Callback");
|
||||||
view.postDelayed(refresher, MIN_RESOLUTION);
|
handler.postDelayed(refresher, MIN_DATE_RESOLUTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopPeriodicUpdate() {
|
private void stopPeriodicUpdate() {
|
||||||
if (refresher != null && ui != null) {
|
if (refresher != null) {
|
||||||
LOG.info("Removing Handler Callback");
|
LOG.info("Removing Handler Callback");
|
||||||
view.removeCallbacks(refresher);
|
handler.removeCallbacks(refresher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
feedController.onStart();
|
feedController.onStart();
|
||||||
|
list.startPeriodicUpdate();
|
||||||
loadPersonalBlog();
|
loadPersonalBlog();
|
||||||
loadBlogPosts(false);
|
loadBlogPosts(false);
|
||||||
}
|
}
|
||||||
@@ -157,7 +158,6 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
handleDbException(exception);
|
handleDbException(exception);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
list.startPeriodicUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
|||||||
|
|
||||||
public class UiUtils {
|
public class UiUtils {
|
||||||
|
|
||||||
public static final long MIN_RESOLUTION = MINUTE_IN_MILLIS;
|
public static final long MIN_DATE_RESOLUTION = MINUTE_IN_MILLIS;
|
||||||
public static final int TEASER_LENGTH = 320;
|
public static final int TEASER_LENGTH = 320;
|
||||||
public static final float GREY_OUT = 0.5f;
|
public static final float GREY_OUT = 0.5f;
|
||||||
|
|
||||||
@@ -51,15 +51,16 @@ public class UiUtils {
|
|||||||
FORMAT_SHOW_DATE | FORMAT_ABBREV_TIME | FORMAT_ABBREV_MONTH;
|
FORMAT_SHOW_DATE | FORMAT_ABBREV_TIME | FORMAT_ABBREV_MONTH;
|
||||||
|
|
||||||
long diff = System.currentTimeMillis() - time;
|
long diff = System.currentTimeMillis() - time;
|
||||||
if (diff < MIN_RESOLUTION) return ctx.getString(R.string.now);
|
if (diff < MIN_DATE_RESOLUTION) return ctx.getString(R.string.now);
|
||||||
if (diff >= DAY_IN_MILLIS && diff < WEEK_IN_MILLIS) {
|
if (diff >= DAY_IN_MILLIS && diff < WEEK_IN_MILLIS) {
|
||||||
// also show time when older than a day, but newer than a week
|
// also show time when older than a day, but newer than a week
|
||||||
return DateUtils.getRelativeDateTimeString(ctx, time,
|
return DateUtils.getRelativeDateTimeString(ctx, time,
|
||||||
MIN_RESOLUTION, WEEK_IN_MILLIS, flags).toString();
|
MIN_DATE_RESOLUTION, WEEK_IN_MILLIS, flags).toString();
|
||||||
}
|
}
|
||||||
// otherwise just show "...ago" or date string
|
// otherwise just show "...ago" or date string
|
||||||
return DateUtils.getRelativeTimeSpanString(time,
|
return DateUtils.getRelativeTimeSpanString(time,
|
||||||
System.currentTimeMillis(), MIN_RESOLUTION, flags).toString();
|
System.currentTimeMillis(),
|
||||||
|
MIN_DATE_RESOLUTION, flags).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SpannableStringBuilder getTeaser(Context ctx, Spanned body) {
|
public static SpannableStringBuilder getTeaser(Context ctx, Spanned body) {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package org.briarproject.briar.android.view;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.support.v7.widget.RecyclerView.Adapter;
|
import android.support.v7.widget.RecyclerView.Adapter;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
@@ -17,14 +19,15 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static org.briarproject.briar.android.util.UiUtils.MIN_RESOLUTION;
|
import static org.briarproject.briar.android.util.UiUtils.MIN_DATE_RESOLUTION;
|
||||||
|
|
||||||
public class BriarRecyclerView extends FrameLayout {
|
public class BriarRecyclerView extends FrameLayout {
|
||||||
|
|
||||||
private static final long DEFAULT_REFRESH_INTERVAL = MIN_RESOLUTION;
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(BriarRecyclerView.class.getName());
|
Logger.getLogger(BriarRecyclerView.class.getName());
|
||||||
|
|
||||||
|
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
private RecyclerView recyclerView;
|
private RecyclerView recyclerView;
|
||||||
private TextView emptyView;
|
private TextView emptyView;
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
@@ -192,18 +195,19 @@ public class BriarRecyclerView extends FrameLayout {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
LOG.info("Updating Content...");
|
LOG.info("Updating Content...");
|
||||||
recyclerView.getAdapter().notifyDataSetChanged();
|
Adapter adapter = recyclerView.getAdapter();
|
||||||
postDelayed(refresher, DEFAULT_REFRESH_INTERVAL);
|
adapter.notifyItemRangeChanged(0, adapter.getItemCount());
|
||||||
|
handler.postDelayed(refresher, MIN_DATE_RESOLUTION);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
LOG.info("Adding Handler Callback");
|
LOG.info("Adding Handler Callback");
|
||||||
postDelayed(refresher, DEFAULT_REFRESH_INTERVAL);
|
handler.postDelayed(refresher, MIN_DATE_RESOLUTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopPeriodicUpdate() {
|
public void stopPeriodicUpdate() {
|
||||||
if (refresher != null) {
|
if (refresher != null) {
|
||||||
LOG.info("Removing Handler Callback");
|
LOG.info("Removing Handler Callback");
|
||||||
removeCallbacks(refresher);
|
handler.removeCallbacks(refresher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user