1

所以我遵循Clean Architecture来设计我的应用程序。我有一个Activity带视图的寻呼机,里面有两个FragmentPagerAdapter我通过 Dagger 为这个注入了。

我知道调用setRetainInstance(true)一个片段可以防止它被破坏,并且getActivity()如果 Activity 被破坏,在这样的片段上可能会返回一个问题。在我的活动处于后台并且活动已(可能)被破坏后尝试恢复我的活动时,我得到了 NullPointException。

所以我的问题是

  • 有没有更好的方法来完成我想要做的事情?
  • 有人可以指出我的任何资源吗?
  • 如果片段已被破坏,也不确定为什么片段和适配器仍然处于活动状态。LeakCanary 没有内存泄漏。

我的活动有一个 Dagger 组件 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);

获取Activity的组件

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

让我知道你们是否有任何困惑。我知道我的解释是一团糟。谢谢

更新

似乎即使我删除setRetainInstance(true)了这个错误也没有被阻止。

4

1 回答 1

1

问题

当应用程序在后台停留一段时间并且最近显示的活动被 Android 回收时,就会出现此问题。带回应用程序会导致 NullPointerException (NPE),因为片段在初始化之前调用了活动的组件(片段和活动同时重新创建)。

解决方案

在 BaseFragment 类中引入两个生命周期方法。

  1. onInjectView()  — 调用以在 onCreate(Bundle) 上进行可选注入,如果抛出异常或返回 false,则在 onActivityCreated(Bundle) 上再次调用它。在此方法中,您可以获取注入组件并注入视图。如果注入成功则返回true,则不会再次调用它。
  2. 根据返回值调用第二个方法。该方法被命名为onViewInjected(Bundle),因为它仅在片段被注入并且注入的字段可以被初始化时才被调用。

基础片段

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);
    }
}

有关Android MVP 应用程序中高效且无错误的片段注入的更多信息

于 2018-01-26T10:45:20.530 回答