1

私はClean Architectureに従ってアプリケーションを設計していました。私はFragmentが2つあるビューページャを持つActivityを持っています。私はこのためにPagerAdapterをDaggerから注入しています。Dagger2とsetRetainInstance(true)を使用しているときにNullPointExceptionを取得します。

フラグメント上のsetRetainInstance(true)を呼び出すと、そのフラグメントが破棄されるのを防ぐことができます。アクティビティが破棄されると、そのフラグメントのgetActivity()が問題を返すことがあります。バックグラウンドでアクティビティが(おそらく)破棄された後、自分のアクティビティを再開しようとするとNullPointExceptionが発生します。

だから私の質問は

  • は、私が何をしようとしている達成するために良い方法はありますか?
  • 誰かが私に指摘できるリソースはありますか?
  • フラグメントが破棄された場合でもフラグメントとアダプタがまだアクティブである理由は不明です。私はLeakCanaryでメモリリークを取得しません。

私のアクティビティには、次のように注入されるダガーコンポーネントMainActivityComponentがあります。また、HasComponentも拡張します。これに関する詳細情報についてはHasComponent

MainActivity.java

DaggerMainActivityComponent.builder() 
.applicationComponent(getApplicationComponent()) 
.activityModule(getActivityModule()) 
// Module for each fragment 
.conversationListModule(new ConversationListModule(this)) 
.friendsListModule(new FriendsListModule(this)) 
.build() 
.inject(this); 

取得活動のコンポーネントを参照してください

// Cause of the NullPointException getActivity() 
protected <C> C getComponent(Class<C> componentType) { 
    return componentType.cast(((HasComponent<C>) getActivity()).getComponent()); 
} 

は、あなたたちは混乱を持っているなら、私を知ってみましょう。私の説明は混乱であることは分かっています。おかげ

更新

私はsetRetainInstance(true)を削除しても、このエラーが防止されていないようです。アプリケーションは、しばらくの間、バックグラウンドでとどまり、最近表示された活動は、アンドロイドによってリサイクルされたときに

答えて

1

問題

問題が発生しました。アクティビティのコンポーネントが初期化される前にフラグメントによって呼び出されるため、NullPointerException(NPE)が発生します(フラグメントとアクティビティの両方が同時に再作成されます)。

ソリューション

BaseFragmentクラスに2つのライフサイクルメソッドが導入されています。

  1. onInjectView() - のonCreate(バンドル)と例外がスローされたり返さfalseの場合、それは再びonActivityCreated(バンドル)に呼び出された上で、オプションの注入を行うために呼ばれます。このメソッド内で、注入コンポーネントを取得してビューを注入できます。 Retrun注入が成功した場合はtrue、それ以降は呼び出されません。
  2. 戻り値に基づいて、2番目のメソッドが呼び出されます。このメソッドは、ビューインジェクション(バンドル)のという名前です。フラグメントが注入され、注入されたフィールドを初期化できる場合にのみ呼び出されるためです。

ベース断片

public abstract class BaseFragment extends Fragment { 

    private boolean mIsInjected = false; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setRetainInstance(true); 

     try { 
      mIsInjected = onInjectView(); 
     } catch (IllegalStateException e) { 
      Log.e(e.getClass().getSimpleName(), e.getMessage()); 
      mIsInjected = false; 
     } 
    } 

    @Override 
    public void onViewCreated(View view, Bundle savedInstanceState) { 
     super.onViewCreated(view, savedInstanceState); 
     if (mIsInjected) onViewInjected(savedInstanceState); 
    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 
     if (!mIsInjected) { 
      mIsInjected = onInjectView(); 
      if (mIsInjected) onViewInjected(savedInstanceState); 
     } 
    } 

    @SuppressWarnings("unchecked") 
    protected <C> C getComponent(Class<C> componentType) throws IllegalStateException { 
     C component = componentType.cast(((HasComponent<C>) getActivity()).getComponent()); 
     if (component == null) { 
      throw new IllegalStateException(componentType.getSimpleName() + " has not been initialized yet."); 
     } 
     return component; 
    } 


    protected boolean onInjectView() throws IllegalStateException { 
     // Return false by default. 
     return false; 
    } 

    @CallSuper 
    protected void onViewInjected(Bundle savedInstanceState) { 
     // Intentionally left empty. 
    } 
} 

public class SampleFragment extends BaseFragment implements SampleView { 

    @Inject 
    SamplePresenter mSamplePresenter; 

    @Override 
    protected boolean onInjectView() throws IllegalStateException { 
     getComponent(SampleComponent.class).inject(this); 
     return true; 
    } 

    @Override 
    protected void onViewInjected(Bundle savedInstanceState) { 
     super.onViewInjected(savedInstanceState); 
     this.mSamplePresenter.setView(this); 
    } 
} 

詳細情報はEfficient and bug-free fragment injection in Android MVP applications

で見つけることができます使い方
関連する問題