mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Merge branch '714-asynchronous-context-leaks' into 'master'
Fixed asynchronous Activity leaks in Fragments If a Fragment has been detached its `getActivity()` method will return null, providing numerous crash possibilities within the app. My approach to fixing this is to make Fragments use their own `runOnUiThreadUnlessDestroyed` method, which also checks if the Fragment has been detached before running the Runnable Closes #714 See merge request !387
This commit is contained in:
@@ -47,7 +47,7 @@ import static org.briarproject.android.blogs.BlogActivity.REQUEST_WRITE_POST;
|
||||
public class BlogFragment extends BaseFragment implements
|
||||
OnBlogPostAddedListener {
|
||||
|
||||
public final static String TAG = BlogFragment.class.getName();
|
||||
private final static String TAG = BlogFragment.class.getName();
|
||||
|
||||
@Inject
|
||||
BlogController blogController;
|
||||
@@ -178,7 +178,7 @@ public class BlogFragment extends BaseFragment implements
|
||||
public void onBlogPostAdded(BlogPostHeader header, final boolean local) {
|
||||
blogController.loadBlogPost(header,
|
||||
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
||||
listener) {
|
||||
this) {
|
||||
@Override
|
||||
public void onResultUi(BlogPostItem post) {
|
||||
adapter.add(post);
|
||||
@@ -201,10 +201,10 @@ public class BlogFragment extends BaseFragment implements
|
||||
);
|
||||
}
|
||||
|
||||
void loadBlogPosts(final boolean reload) {
|
||||
private void loadBlogPosts(final boolean reload) {
|
||||
blogController.loadBlogPosts(
|
||||
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
||||
listener) {
|
||||
this) {
|
||||
@Override
|
||||
public void onResultUi(Collection<BlogPostItem> posts) {
|
||||
if (posts.isEmpty()) {
|
||||
@@ -225,7 +225,7 @@ public class BlogFragment extends BaseFragment implements
|
||||
|
||||
private void loadBlog() {
|
||||
blogController.loadBlog(
|
||||
new UiResultExceptionHandler<BlogItem, DbException>(listener) {
|
||||
new UiResultExceptionHandler<BlogItem, DbException>(this) {
|
||||
@Override
|
||||
public void onResultUi(BlogItem blog) {
|
||||
setToolbarTitle(blog.getBlog().getAuthor());
|
||||
@@ -299,7 +299,7 @@ public class BlogFragment extends BaseFragment implements
|
||||
|
||||
private void deleteBlog() {
|
||||
blogController.deleteBlog(
|
||||
new UiResultExceptionHandler<Void, DbException>(listener) {
|
||||
new UiResultExceptionHandler<Void, DbException>(this) {
|
||||
@Override
|
||||
public void onResultUi(Void result) {
|
||||
Toast.makeText(getActivity(),
|
||||
|
||||
@@ -62,7 +62,7 @@ public class BlogPostFragment extends BasePostFragment {
|
||||
super.onStart();
|
||||
blogController.loadBlogPost(postId,
|
||||
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
||||
listener) {
|
||||
this) {
|
||||
@Override
|
||||
public void onResultUi(BlogPostItem post) {
|
||||
onBlogPostLoaded(post);
|
||||
|
||||
@@ -45,7 +45,7 @@ public class BlogPostPagerFragment extends BasePostPagerFragment {
|
||||
void loadBlogPosts(final MessageId select) {
|
||||
blogController.loadBlogPosts(
|
||||
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
||||
listener) {
|
||||
this) {
|
||||
@Override
|
||||
public void onResultUi(Collection<BlogPostItem> posts) {
|
||||
onBlogPostsLoaded(select, posts);
|
||||
@@ -62,7 +62,7 @@ public class BlogPostPagerFragment extends BasePostPagerFragment {
|
||||
void loadBlogPost(BlogPostHeader header) {
|
||||
blogController.loadBlogPost(header,
|
||||
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
||||
listener) {
|
||||
this) {
|
||||
@Override
|
||||
public void onResultUi(BlogPostItem post) {
|
||||
addPost(post);
|
||||
|
||||
@@ -114,7 +114,7 @@ public class FeedFragment extends BaseFragment implements
|
||||
|
||||
private void loadPersonalBlog() {
|
||||
feedController.loadPersonalBlog(
|
||||
new UiResultExceptionHandler<Blog, DbException>(listener) {
|
||||
new UiResultExceptionHandler<Blog, DbException>(this) {
|
||||
@Override
|
||||
public void onResultUi(Blog b) {
|
||||
personalBlog = b;
|
||||
@@ -131,7 +131,7 @@ public class FeedFragment extends BaseFragment implements
|
||||
final int revision = adapter.getRevision();
|
||||
feedController.loadBlogPosts(
|
||||
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
||||
listener) {
|
||||
this) {
|
||||
@Override
|
||||
public void onResultUi(Collection<BlogPostItem> posts) {
|
||||
if (revision == adapter.getRevision()) {
|
||||
@@ -194,7 +194,7 @@ public class FeedFragment extends BaseFragment implements
|
||||
public void onBlogPostAdded(BlogPostHeader header, final boolean local) {
|
||||
feedController.loadBlogPost(header,
|
||||
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
||||
listener) {
|
||||
this) {
|
||||
@Override
|
||||
public void onResultUi(BlogPostItem post) {
|
||||
adapter.incrementRevision();
|
||||
|
||||
@@ -65,7 +65,7 @@ public class FeedPostFragment extends BasePostFragment {
|
||||
super.onStart();
|
||||
feedController.loadBlogPost(blogId, postId,
|
||||
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
||||
listener) {
|
||||
this) {
|
||||
@Override
|
||||
public void onResultUi(BlogPostItem post) {
|
||||
onBlogPostLoaded(post);
|
||||
|
||||
@@ -44,7 +44,7 @@ public class FeedPostPagerFragment extends BasePostPagerFragment {
|
||||
void loadBlogPosts(final MessageId select) {
|
||||
feedController.loadBlogPosts(
|
||||
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
||||
listener) {
|
||||
this) {
|
||||
@Override
|
||||
public void onResultUi(Collection<BlogPostItem> posts) {
|
||||
onBlogPostsLoaded(select, posts);
|
||||
@@ -61,7 +61,7 @@ public class FeedPostPagerFragment extends BasePostPagerFragment {
|
||||
void loadBlogPost(BlogPostHeader header) {
|
||||
feedController.loadBlogPost(header,
|
||||
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
||||
listener) {
|
||||
this) {
|
||||
@Override
|
||||
public void onResultUi(BlogPostItem post) {
|
||||
addPost(post);
|
||||
|
||||
@@ -93,7 +93,7 @@ public class ReblogFragment extends BaseFragment implements TextInputListener {
|
||||
// TODO: Load blog post when fragment is created. #631
|
||||
feedController.loadBlogPost(blogId, postId,
|
||||
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
||||
listener) {
|
||||
this) {
|
||||
@Override
|
||||
public void onResultUi(BlogPostItem result) {
|
||||
item = result;
|
||||
@@ -130,7 +130,7 @@ public class ReblogFragment extends BaseFragment implements TextInputListener {
|
||||
public void onSendClick(String text) {
|
||||
String comment = getComment();
|
||||
feedController.repeatPost(item, comment,
|
||||
new UiResultExceptionHandler<Void, DbException>(listener) {
|
||||
new UiResultExceptionHandler<Void, DbException>(this) {
|
||||
@Override
|
||||
public void onResultUi(Void result) {
|
||||
// do nothing, this fragment is gone already
|
||||
|
||||
@@ -223,7 +223,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
|
||||
private void displayContacts(final int revision,
|
||||
final List<ContactListItem> contacts) {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (revision == adapter.getRevision()) {
|
||||
@@ -289,7 +289,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
}
|
||||
|
||||
private void updateItem(final ContactId c, final BaseMessageHeader h) {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adapter.incrementRevision();
|
||||
@@ -305,7 +305,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
}
|
||||
|
||||
private void removeItem(final ContactId c) {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adapter.incrementRevision();
|
||||
@@ -317,7 +317,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
}
|
||||
|
||||
private void setConnected(final ContactId c, final boolean connected) {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adapter.incrementRevision();
|
||||
|
||||
@@ -178,7 +178,7 @@ public class ForumListFragment extends BaseEventFragment implements
|
||||
|
||||
private void displayForums(final int revision,
|
||||
final Collection<ForumListItem> forums) {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (revision == adapter.getRevision()) {
|
||||
@@ -214,7 +214,7 @@ public class ForumListFragment extends BaseEventFragment implements
|
||||
}
|
||||
|
||||
private void displayAvailableForums(final int availableCount) {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (availableCount == 0) {
|
||||
@@ -257,7 +257,7 @@ public class ForumListFragment extends BaseEventFragment implements
|
||||
}
|
||||
|
||||
private void updateItem(final GroupId g, final ForumPostHeader m) {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adapter.incrementRevision();
|
||||
@@ -272,7 +272,7 @@ public class ForumListFragment extends BaseEventFragment implements
|
||||
}
|
||||
|
||||
private void removeForum(final GroupId g) {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adapter.incrementRevision();
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package org.briarproject.android.fragment;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.CallSuper;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.support.v4.app.Fragment;
|
||||
@@ -33,7 +35,6 @@ public abstract class BaseFragment extends Fragment
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
@@ -54,10 +55,11 @@ public abstract class BaseFragment extends Fragment
|
||||
|
||||
@UiThread
|
||||
protected void finish() {
|
||||
getActivity().supportFinishAfterTransition();
|
||||
if (!isDetached())
|
||||
getActivity().supportFinishAfterTransition();
|
||||
}
|
||||
|
||||
public interface BaseFragmentListener extends DestroyableContext {
|
||||
public interface BaseFragmentListener {
|
||||
|
||||
@Deprecated
|
||||
void runOnDbThread(Runnable runnable);
|
||||
@@ -72,8 +74,21 @@ public abstract class BaseFragment extends Fragment
|
||||
void onFragmentCreated(String tag);
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
@Override
|
||||
public void runOnUiThreadUnlessDestroyed(Runnable r) {
|
||||
listener.runOnUiThreadUnlessDestroyed(r);
|
||||
public void runOnUiThreadUnlessDestroyed(final Runnable r) {
|
||||
final Activity activity = getActivity();
|
||||
if (activity != null) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Note that we don't have to check if the activity has
|
||||
// been destroyed as the Fragment has not been detached yet
|
||||
if (!isDetached() && !activity.isFinishing()) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
||||
KeyAgreementAbortedEvent event = (KeyAgreementAbortedEvent) e;
|
||||
keyAgreementAborted(event.didRemoteAbort());
|
||||
} else if (e instanceof KeyAgreementFinishedEvent) {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mainProgressContainer.setVisibility(VISIBLE);
|
||||
@@ -313,7 +313,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
||||
}
|
||||
|
||||
private void setQrCode(final Payload localPayload) {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
generateBitmapQR(localPayload);
|
||||
@@ -322,7 +322,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
||||
}
|
||||
|
||||
private void keyAgreementFailed() {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
reset();
|
||||
@@ -334,7 +334,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
||||
}
|
||||
|
||||
private void keyAgreementWaiting() {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
status.setText(R.string.waiting_for_contact_to_scan);
|
||||
@@ -343,7 +343,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
||||
}
|
||||
|
||||
private void keyAgreementStarted() {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mainProgressContainer.setVisibility(VISIBLE);
|
||||
@@ -353,7 +353,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
||||
}
|
||||
|
||||
private void keyAgreementAborted(final boolean remoteAborted) {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
reset();
|
||||
@@ -370,7 +370,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
||||
|
||||
@Override
|
||||
public void handleResult(final Result result) {
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
LOG.info("Got result from decoder");
|
||||
|
||||
@@ -126,7 +126,7 @@ public class GroupListFragment extends BaseFragment implements
|
||||
@Override
|
||||
public void onGroupRemoveClick(GroupItem item) {
|
||||
controller.removeGroup(item.getId(),
|
||||
new UiResultExceptionHandler<Void, DbException>(listener) {
|
||||
new UiResultExceptionHandler<Void, DbException>(this) {
|
||||
@Override
|
||||
public void onResultUi(Void result) {
|
||||
// handled by GroupRemovedEvent and onGroupRemoved()
|
||||
@@ -173,7 +173,7 @@ public class GroupListFragment extends BaseFragment implements
|
||||
final int revision = adapter.getRevision();
|
||||
controller.loadGroups(
|
||||
new UiResultExceptionHandler<Collection<GroupItem>, DbException>(
|
||||
listener) {
|
||||
this) {
|
||||
@Override
|
||||
public void onResultUi(Collection<GroupItem> groups) {
|
||||
if (revision == adapter.getRevision()) {
|
||||
|
||||
Reference in New Issue
Block a user