3

我想定製從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堅持到所有的引用都沒有了?

回答

1

起初。 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

0

問題1解決方案:
使用專用的WeakReference mContextHolder。當你需要上下文時 - 調用mContextHolder.get()並檢查null;

問題2解決方案:
使用將託管您的線程的服務。