所以我关注了Clean Architecture设计我的应用程序。我有一个带有 View 寻呼机的 Activity
,其中有两个 Fragment
。我为此通过 Dagger 注入(inject)了 PagerAdapter
。
我知道在 fragment 上调用 setRetainInstance(true)
可以防止它被销毁,如果 Activity 是被毁。在 Activity 处于后台并且 Activity 已(可能)被销毁后尝试恢复我的 Activity 时,我收到 NullPointException。
所以我的问题是
- 有没有更好的方法来完成我想做的事情?
- 有什么资源可以指点我吗?
- 还不确定如果 fragment 已被销毁,为什么 fragment 和适配器仍处于 Activity 状态。使用 LeakCanary 时我没有发现内存泄漏。
我的 Activity 有一个 Dagger Component MainActivityComponent 注入(inject)如下。并且还扩展了 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);
Getting the Activity's component
// Cause of the NullPointException getActivity()
protected <C> C getComponent(Class<C> componentType) {
return componentType.cast(((HasComponent<C>) getActivity()).getComponent());
}
如果你们有任何困惑,请告诉我。我知道我的解释很乱。谢谢
更新
似乎即使我删除 setRetainInstance(true)
也无法阻止此错误。
最佳答案
问题
当应用程序在后台停留一段时间并且最近显示的 Activity 被 Android 回收时,就会出现问题。返回应用程序会导致 NullPointerException (NPE),因为 Activity 的组件在初始化之前被 fragment 调用(同时重新创建 fragment 和 Activity )。
解决方案
在 BaseFragment 类中引入两个生命周期方法。
- onInjectView() — 调用以在 onCreate(Bundle) 上执行可选注入(inject),如果抛出异常或返回 false,则会再次调用 onActivityCreated(Bundle)。在此方法中,您可以获得注入(inject)组件并注入(inject) View 。如果注入(inject)成功返回true,则不会再次调用。
- 根据返回值,调用第二个方法。该方法被命名为onViewInjected(Bundle),因为它仅在 fragment 已被注入(inject)并且注入(inject)字段可以被初始化时被调用。
基础 fragment
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 上找到
关于android - 使用 Dagger 2 和 setRetainInstance(true) 时获取 NullPointErexception;,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47406449/