防止线程被垃圾收集,并防止上下文泄漏

问题描述:

我想定制从AccountManager获取身份验证令牌的过程。防止线程被垃圾收集,并防止上下文泄漏

AccountManagergetAuthToken()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()

我有两个问题在这里:

  1. 我需要Activity上下文切换到需要的时候其他的活动,但是当我切换到其他活动Activity我传递到构造函数应该被销毁,但不会因为我的Thread有一个引用它......所以我在这里创建一个内存泄漏。看起来,使内部类非静态不会解决这个问题 - 从getAuthTokenForActiveAccount()返回的引用仍然会阻止从外部Activity垃圾收集。有没有什么办法可以实现我在不泄漏背景的情况下做的事情?
  2. Thread一旦其run()方法返回,就有资格进行垃圾回收,对不对?但在我的情况下,我希望这个线程能够坚持下去,因为它也可以作为AccountManagerFuture - 它应该保存在内存中,直到所有对它的引用都没有了。我的问题是:是否足够保留一个(强烈)参考Thread以防止它被垃圾收集?如果没有,我怎么能强制这个Thread坚持到所有的引用都没有了?

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

  1. 你应该使用某种形式的你的未来,你的Activities..You或许应该将其移动到服务反正之间的间接通信的 - 你去想任何配置更改?你在哪里持有你未来的参考? 我建议你要么将流量转移到碎片中 - 那么你不必切换活动 - 并将未来放入保留的片段(使其在存储方向变化中存活)或将其移入后台服务并与您的活动(或任何类型的UI)通过广播接收器或事件总线。

  2. 只要您保留一些引用,线程就不会被垃圾收集。不管它是否完成。我认为你很困惑这个事实,即一个正在运行的线程不会被垃圾收集,即使没有保存它的引用。 (我想JVM是这样做的,但我不得不承认我对此不确定)

+0

感谢您澄清主题。至于第一部分 - 我真的不想重新实现'AccountManager',因此我仍然会使用它的API('addAccount()','getAuthToken()','newChooseAccountIntent()'等等...) - 这些API中的一部分引用了我已经实现的“AccountAuthenticator”,其中一些API负责切换活动,因此它们需要适当的上下文......是的,我可以重新发明*,但在我做之前,我想确保它真的是我唯一的选择。 – Vasiliy

+0

所有你需要的是把你的未来,或即运行的背景操作从你的活动。这就是为什么服务。 – simekadam

+0

@simekadam不同意1个问题的解决方案。活动内存泄漏的根本原因很难参考活动。即使lint建议基于弱参照举办活动的解决方案+将类声明为静态。 – x90

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

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