2017-06-06 104 views
0

我有一個應用程序實現MVP模式與Loader維護演示者對象的視圖娛樂(有關於此here的文章)。我是Dagger 2的新手,試圖與當前代碼一起實施。匕首2與MVP,避免創建額外的主持人對象上視圖娛樂

我設法使它工作,但現在我的演示者創建了兩次。起初它是使用一個初始化在onCreateLoader中的工廠類創建的,但是當添加Dagger 2實現時,我創建了兩個對象(工廠類和注入時)。

現在我避免在onCreateLoader中創建一個新的演示者,而是通過注入的演示者。問題在於視圖娛樂:每當視圖被破壞並重新創建時,新的演示者被注入OnCreate/OnCreateView。這是該方案:

  1. 一個新的主持人注射:

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
        ... 
        getControllerComponent().inject(this); 
        ... 
    } 
    
  2. 初始化LoaderonCreateLoader被稱爲如果Loader不存在。請注意,我們傳遞注射主持人:

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
        super.onActivityCreated(savedInstanceState); 
        getLoaderManager().initLoader(PRESENTER_LOADER_ID, null, this); 
    } 
    
    @Override 
    public Loader<MyPresenter> onCreateLoader(int id, Bundle args) { 
        switch (id) { 
         case PRESENTER_LOADER_ID: 
          return new PresenterLoader<>(getContext(), presenter); 
          //return new PresenterLoader<>(getContext(), new MyPresenterFactory()); 
        } 
    
        return null; 
    } 
    
  3. 分配從Loader收到的主持人。如果它剛剛創建,我們分配已分配的同一個對象,因此什麼都不會發生。但是,如果視圖被重新創建,那麼Dagger 2會注入一個新的主持人,在這裏我們扔掉新的主持人,並將其替換爲Loader中的舊主持人。

    @Override 
    public void onLoadFinished(Loader<MyPresenter> loader, MyPresenter data) { 
        this.presenter = data; 
    } 
    

    我想維護演示者實例,因此它是我想要發生的事情;我的問題是在每個視圖娛樂中創建一個冗餘的演示者對象。首先,這是不必要的,另外,視圖持有對不同演示者的引用,直到加載完成。很明顯,我在這段時間內(注射後和加載完成之前)沒有使用主持人,但我絕對不喜歡它,並擔心這個新的主持人將來會被錯誤地使用。

匕首專家2人,有沒有方法來創建演示在第一時間(Loader之前創建),但避免對視娛樂?非常感謝!

+0

您能分享它依賴的匕首組件定義和模塊嗎? –

回答

6

首先,我只想提一提,如果注入演示者,則不應在稍後從裝入器中再指定它。

既可以使用注射來提供物體,也可以自己提供。如果你們兩個都這樣做了,那麼你只是冒着引入錯誤的風險。


是有一種方式來創建演示所述第一時間(裝載機被創建之前),但避免它在視圖娛樂?

TL;博士您需要爲您演示,反映您的組件的壽命可能生存配置更改的範圍。此範圍不得保留對活動Context的任何引用。

組件遵循一些生命週期。您通常會在Application@PerActivity或您創建的類似範圍的組件中保留一些@Singleton帶註釋的組件,這些組件可以通過Activity創建,並且在活動經歷配置更改時將會(也應該)重新創建,因爲這些依賴關係通常引用Activity上下文並應該與活動一起生活並死去。

您在這裏面臨的主要問題是範圍問題。

如果您的演示者無法播放,那麼您每次請求播放器時都會重新創建一個演示者,只要您將其注入到其他位置,就會在無意中導致錯誤。通常情況下,主持人保持在活動範圍內,並且經常受到某些範圍的限制。


如果你的演講是@PerActivity範圍應該(像所有其他@PerActivity依賴)與所有其他的依賴一起重建的一部分。如果您保留演示者,但重新創建所有其他對象,則舊演示者仍會引用舊的依賴關係,從而導致內存泄漏。 作用域對象應該存在於它們自己的範圍內。

對象在同一範圍內可以參考彼此從而保持一個範圍的對象活着的範圍之外也會在不經意間導致的錯誤,內存泄漏等

所以你不想保持這個主持人也在你的Loader中。


如果在另一方面,你說不,主持人是一步更高層次的@PerScreen一部分,在那裏我保持更長的生命物體那麼你需要找到一種方法,實際上是保持這種@PerScreen組件活着,而您的@PerActivity組件將與該活動一起重新創建。

假設以下範圍層次:

`X > Y` read X is subcomponent of Y 
@Singleton > @PerScreen > @PerActivity 

@Singleton: Application wide 
@PerScreen: Multiple activty lifecycles, keep alive during config changes 
@PerActivity: Maybe Context dependent, recreate with every activity 

當配置發生變化時,你現在可以放棄所有的@PerActivity對象並重新創建它們,同時保持引用您的@PerScreen的。

你可能會注意到我一直在如何談論保持@PerScreen組件保持主持人,那就是這裏的重要組成部分:

@PerScreen範圍的組件,調用

myPerScreenComponent.getMyPresenter() 

將始終返回相同@PerScreen範圍的演示者。

現在,如果你@PerActivty範圍的組件是MyPerScreenComponent子組件,注入你的活動會一直給你同樣的@PerScreen範圍的主持人,這將生存的方向改變。

爲了防止內存泄漏,沒有對象從@PerScreen範圍可參考的活動,和主持人應該只保留其視圖WeakReference(或者你必須做出相當肯定的視圖設置爲null上的銷燬)。

這是什麼範圍,這就是你如何避免創建額外的演示者對象視圖娛樂

因此,不要將您的演示者放在裝載器中,而應該嘗試將組件保存在裝載器中,以避免不必要的對象重新創建。


所有這些都可能會帶來更多的複雜性,因爲您現在每個活動有2個範圍,回調更多。

我還看到了其他方法,您將演示者作爲單例保存在您的應用程序中,但是這會引入相同的問題,因爲您必須確保不保留對活動的任何引用。

就我個人而言,我只是重新創建演示者並恢復狀態,但如果您選擇使用您的方法,則應確保您對範圍和依賴關係有深入的瞭解。