防止Thread被垃圾回收,防止上下文泄露
Prevent Thread from being garbage collected, and prevent context leak
我想自定义从 AccountManager 获取身份验证令牌的过程。
AccountManager
有 getAuthToken()
和 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切换)。
这里有两个问题:
- 我需要
Activity
上下文以在必要时切换到其他活动,但是当我切换到其他 activity 时,我传递给构造函数的 Activity
应该被销毁,但它不会'因为我的 Thread
持有对它的引用...所以我在这里创建内存泄漏。似乎使内部 class 成为非静态并不能解决这个问题——从 getAuthTokenForActiveAccount()
返回的引用仍然会阻止外部 Activity
被垃圾收集。有什么方法可以在不泄露上下文的情况下实现我尝试做的事情吗?
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.
你应该在你的 future 和你的 Activity 之间使用某种形式的间接通信。无论如何你应该把它移到服务中——你有没有考虑过任何配置更改?你在哪里持有你未来的参考?
我会建议你要么将你的流程移动到片段中 - 那么你就不必切换活动 - 并将你的未来放入保留的片段中(使其在方向变化中存活下来)或将其移动到后台服务中并与你的活动进行通信(或任何类型的UI)通过广播接收器或事件总线。
只要您保留对线程的一些引用,线程就不会被垃圾回收。不管它完成与否。我认为您将此与 运行 线程即使不保留对它的引用也不会被垃圾收集这一事实混淆了。 (我猜 JVM 会这样做,但我不得不承认我对此不确定)
我想自定义从 AccountManager 获取身份验证令牌的过程。
AccountManager
有 getAuthToken()
和 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切换)。
这里有两个问题:
- 我需要
Activity
上下文以在必要时切换到其他活动,但是当我切换到其他 activity 时,我传递给构造函数的Activity
应该被销毁,但它不会'因为我的Thread
持有对它的引用...所以我在这里创建内存泄漏。似乎使内部 class 成为非静态并不能解决这个问题——从getAuthTokenForActiveAccount()
返回的引用仍然会阻止外部Activity
被垃圾收集。有什么方法可以在不泄露上下文的情况下实现我尝试做的事情吗? 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.
你应该在你的 future 和你的 Activity 之间使用某种形式的间接通信。无论如何你应该把它移到服务中——你有没有考虑过任何配置更改?你在哪里持有你未来的参考? 我会建议你要么将你的流程移动到片段中 - 那么你就不必切换活动 - 并将你的未来放入保留的片段中(使其在方向变化中存活下来)或将其移动到后台服务中并与你的活动进行通信(或任何类型的UI)通过广播接收器或事件总线。
只要您保留对线程的一些引用,线程就不会被垃圾回收。不管它完成与否。我认为您将此与 运行 线程即使不保留对它的引用也不会被垃圾收集这一事实混淆了。 (我猜 JVM 会这样做,但我不得不承认我对此不确定)