作为Intent
的替代方案,我在Fragment
重新创建期间将数据保存在保留的无头Activity
中(我保存的对象可能非常大而且不会符合Intent
的大小限制,我认为这比序列化 - 反序列化为JSON更快,例如)。
我从this Google documentation得到了这个想法,虽然我的实现有点不同。
Fragment
:
public class DataFragment extends Fragment {
private Data data;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
public void setData(Data data) {
this.data = data;
}
public Data getData() {
return data;
}
}
我在Fragment
的{{1}}方法中将我的数据保存到此onSaveInstanceState()
:
Activity
@Override
protected void onSaveInstanceState(Bundle outState) {
FragmentManager fm = getSupportFragmentManager();
dataFragment = (DataFragment) fm.findFragmentByTag(TAG_DATA);
if (dataFragment == null) {
dataFragment = new DataFragment();
fm.beginTransaction().add(dataFragment, TAG_DATA).commitNow();
}
dataFragment.setData(myData);
super.onSaveInstanceState(outState);
}
的相关部分:
onCreate()
这可以完美地改变方向。
问题是,有时,当我的应用在后台并且我正在返回时,Data data;
FragmentManager fm = getSupportFragmentManager();
dataFragment = (DataFragment) fm.findFragmentByTag(TAG_DATA);
if (dataFragment == null) {
// the Fragment is not attached, fetching data from DB
DatabaseManager dbm = DatabaseManager.getInstance(this);
data = dbm.getData();
} else {
// the Fragment is attached, fetching the data from it
data = dataFragment.getData();
fm.beginTransaction().remove(dataFragment).commitNow();
}
会返回dataFragment.getData()
。
换句话说,null
中的以下行有时onCreate()
为data
:
null
这怎么可能?
它不会抛出data = dataFragment.getData();
,因此NullPointerException
肯定不是dataFragment
。
为什么其初始化的实例变量变为null
?
答案 0 :(得分:10)
您遇到的是过程死亡。
从技术上讲,它也被称为“低内存条件”。
保留的片段与应用程序一起被杀死,但FragmentActivity会在super.onCreate()
中重新创建保留的片段,因此您可以通过其标记找到它,但其中的数据不会被初始化。
将应用程序置于后台,然后按Android Studio左下角的红色X以终止该进程。这再现了这种现象。
答案 1 :(得分:-2)
如果活动在之前被销毁后重新创建,则可以从系统传递活动的Bundle中保存您的状态。 onCreate()和onRestoreInstanceState()回调方法都接收包含实例状态信息的相同Bundle。
显然,无论系统是创建活动的新实例还是重新创建前一个实例,都会调用onCreate()方法,在尝试读取之前,需要检查状态Bundle是否为null。如果它为null,则系统正在创建活动的新实例,而不是恢复已销毁的先前实例。 在oncreate()中:
Data data;
FragmentManager fm = getSupportFragmentManager();
dataFragment = (DataFragment) fm.findFragmentByTag(TAG_DATA);
**if (dataFragment.getData()== null) {**
// the Fragment is not attached, fetching data from DB
DatabaseManager dbm = DatabaseManager.getInstance(this);
data = dbm.getData();
} else {
// the Fragment is attached, fetching the data from it
data = dataFragment.getData();
fm.beginTransaction().remove(dataFragment).commitNow();
}