防止Thread被垃圾回收,防止上下文泄露

Prevent Thread from being garbage collected, and prevent context leak

我想自定义从 AccountManager 获取身份验证令牌的过程。

AccountManagergetAuthToken()getAuthTokenByFeatures() 方法,但我想实现自定义流程,其中包括活动之间的切换等...

我想通过以下方式实现它:

public AccountManagerFuture<Bundle> getAuthTokenForActiveAccount() {
    GetAuthTokenForActiveAccountFuture future =
            new GetAuthTokenForActiveAccountFuture(MyActivity.this);
    future.start();
    return future;
}

在我的 activity 中使用以下嵌套 class:

  private static class GetAuthTokenForActiveAccountFuture extends Thread implements
                AccountManagerFuture<Bundle> {

    private final Activity mActivity;

    public GetAuthTokenForActiveAccountFuture(Activity activity) {
        mActivity = activity;
        // TODO: write this method
    }

    @Override
    public void run() {
         // TODO: write this method
    }

    @Override
    public boolean cancel(boolean b) {
        // TODO: write this method
        return false;
    }

    @Override
    public boolean isCancelled() {
        // TODO: write this method
        return false;
    }

    @Override
    public boolean isDone() {
        // TODO: write this method
        return false;
    }

    @Override
    public Bundle getResult() throws
            OperationCanceledException, IOException, AuthenticatorException {
        return internalGetResult(null, null);
    }

    @Override
    public Bundle getResult(long timeout, TimeUnit timeUnit) throws
            OperationCanceledException, IOException, AuthenticatorException {
        return internalGetResult(timeout, timeUnit);
    }

    private Bundle internalGetResult(Long timeout, TimeUnit timeUnit) throws
            OperationCanceledException, IOException, AuthenticatorException {
        // TODO: write this method
        return null;
    }
}

我的想法是,只有在完成所有必需的步骤(其中一些包括 activity切换)。

这里有两个问题:

  1. 我需要 Activity 上下文以在必要时切换到其他活动,但是当我切换到其他 activity 时,我传递给构造函数的 Activity 应该被销毁,但它不会'因为我的 Thread 持有对它的引用...所以我在这里创建内存泄漏。似乎使内部 class 成为非静态并不能解决这个问题——从 getAuthTokenForActiveAccount() 返回的引用仍然会阻止外部 Activity 被垃圾收集。有什么方法可以在不泄露上下文的情况下实现我尝试做的事情吗?
  2. Thread 一旦其 run() 方法 returns 就符合垃圾回收条件,对吗?但在我的例子中,我希望这个线程保留下来,因为它还具有 AccountManagerFuture 的功能——它应该保存在内存中,直到所有对它的引用都消失了。我的问题是:是否足以保留对 Thread 的(强)引用以防止它被垃圾收集?如果不是,我怎么能强制这个 Thread 一直存在直到所有引用都消失?

问题 1 解决方案:
使用私有 WeakReference mContextHolder。当您需要上下文时 - 调用 mContextHolder.get() 并检查 null;

问题 2 解决方案:
使用将托管您的线程的服务。

起初。 Making your Future non-static would make it having an implicit reference to its outer class - the Activity.

  1. 你应该在你的 future 和你的 Activity 之间使用某种形式的间接通信。无论如何你应该把它移到服务中——你有没有考虑过任何配置更改?你在哪里持有你未来的参考? 我会建议你要么将你的流程移动到片段中 - 那么你就不必切换活动 - 并将你的未来放入保留的片段中(使其在方向变化中存活下来)或将其移动到后台服务中并与你的活动进行通信(或任何类型的UI)通过广播接收器或事件总线。

  2. 只要您保留对线程的一些引用,线程就不会被垃圾回收。不管它完成与否。我认为您将此与 运行 线程即使不保留对它的引用也不会被垃圾收集这一事实混淆了。 (我猜 JVM 会这样做,但我不得不承认我对此不确定)