防止线程被垃圾收集,并防止上下文泄漏
问题描述:
我想定制从AccountManager获取身份验证令牌的过程。防止线程被垃圾收集,并防止上下文泄漏
AccountManager
有getAuthToken()
和getAuthTokenByFeatures()
方法,但我想实现一个自定义的流程,其中包括活动之间的切换,等等
我想实现它的方式如下:
public AccountManagerFuture<Bundle> getAuthTokenForActiveAccount() {
GetAuthTokenForActiveAccountFuture future =
new GetAuthTokenForActiveAccountFuture(MyActivity.this);
future.start();
return future;
}
在我的活动中使用以下嵌套类:
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;
}
}
我的想法是我可以创建自己的AccountManagerFuture对象,并在完成所有必需的步骤(其中一些包括活动切换)后才“解锁”其方法getResult()
。
我有两个问题在这里:
- 我需要
Activity
上下文切换到需要的时候其他的活动,但是当我切换到其他活动Activity
我传递到构造函数应该被销毁,但不会因为我的Thread
有一个引用它......所以我在这里创建一个内存泄漏。看起来,使内部类非静态不会解决这个问题 - 从getAuthTokenForActiveAccount()
返回的引用仍然会阻止从外部Activity
垃圾收集。有没有什么办法可以实现我在不泄漏背景的情况下做的事情? -
Thread
一旦其run()
方法返回,就有资格进行垃圾回收,对不对?但在我的情况下,我希望这个线程能够坚持下去,因为它也可以作为AccountManagerFuture
- 它应该保存在内存中,直到所有对它的引用都没有了。我的问题是:是否足够保留一个(强烈)参考Thread
以防止它被垃圾收集?如果没有,我怎么能强制这个Thread
坚持到所有的引用都没有了?
答
你应该使用某种形式的你的未来,你的Activities..You或许应该将其移动到服务反正之间的间接通信的 - 你去想任何配置更改?你在哪里持有你未来的参考? 我建议你要么将流量转移到碎片中 - 那么你不必切换活动 - 并将未来放入保留的片段(使其在存储方向变化中存活)或将其移入后台服务并与您的活动(或任何类型的UI)通过广播接收器或事件总线。
只要您保留一些引用,线程就不会被垃圾收集。不管它是否完成。我认为你很困惑这个事实,即一个正在运行的线程不会被垃圾收集,即使没有保存它的引用。 (我想JVM是这样做的,但我不得不承认我对此不确定)
答
问题1解决方案:
使用专用的WeakReference mContextHolder。当你需要上下文时 - 调用mContextHolder.get()并检查null;
问题2解决方案:
使用将托管您的线程的服务。
感谢您澄清主题。至于第一部分 - 我真的不想重新实现'AccountManager',因此我仍然会使用它的API('addAccount()','getAuthToken()','newChooseAccountIntent()'等等...) - 这些API中的一部分引用了我已经实现的“AccountAuthenticator”,其中一些API负责切换活动,因此它们需要适当的上下文......是的,我可以重新发明*,但在我做之前,我想确保它真的是我唯一的选择。 – Vasiliy
所有你需要的是把你的未来,或即运行的背景操作从你的活动。这就是为什么服务。 – simekadam
@simekadam不同意1个问题的解决方案。活动内存泄漏的根本原因很难参考活动。即使lint建议基于弱参照举办活动的解决方案+将类声明为静态。 – x90