MapView 搞砸了我的片段交易?
MapView messed up my fragment transactions?
我有一个带有地图视图的片段。我可以从操作栏中打开另一个片段(称之为 listfragment),它工作正常。但是如果我旋转屏幕,然后尝试打开 listfragment,它不会加载,地图视图会按时闪烁(视图中的地图变为空白然后再次出现)。如果我尝试通过单击操作栏上的菜单项再次加载列表片段,应用程序会崩溃并显示
java.lang.IllegalStateException: Fragment already added:
加载片段的 MainActivity 部分:
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mNewTrackFragment = (NewTrackFragment) getFragmentManager()
.findFragmentByTag(TAG_NEW_TRACK_FRAGMENT);
if (mNewTrackFragment == null) {
mNewTrackFragment = NewTrackFragment.newInstance();
}
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.fragment_container, mNewTrackFragment)
.commit();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_track_list) {
if (null == mTrackListFragment) {
mTrackListFragment = TrackListFragment.newInstance();
}
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.fragment_container, mTrackListFragment, TAG_TRACK_LIST_FRAGMENT)
.addToBackStack(null)
.commit();
return true;
}
带有 MapView 的 NewTrackFragment 的一部分:
public NewTrackFragment() {
}
public static NewTrackFragment newInstance() {
NewTrackFragment fragment = new NewTrackFragment();
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_new_track, container, false);
mTrackTitleTV = (TextView) view.findViewById(R.id.tv_track_title);
mDistanceTV = (TextView) view.findViewById(R.id.tv_distance);
mElapsedTimeTV = (TextView) view.findViewById(R.id.tv_elapsed_time);
mSpeedTV = (TextView) view.findViewById(R.id.tv_speed);
mAscentTV = (TextView) view.findViewById(R.id.tv_ascent);
mDescentTV = (TextView) view.findViewById(R.id.tv_descent);
mAltitudeTV = (TextView) view.findViewById(R.id.tv_altitude);
mStartStopFab = (FloatingActionButton) view.findViewById(R.id.fab_startstop);
mMapView = (MapView) view.findViewById(R.id.new_track_mapview);
setupMapView(savedInstanceState);
return view;
}
private void setupMapView(Bundle savedInstanceState) {
mMapView.onCreate(savedInstanceState);
mMapView.getMapAsync(this);
}
我在谷歌上搜索了一些关于它的信息,但没有找到类似的东西。
这里有几处错误。现在,在 onCreate
中调用 add
时,您不会将 TAG_NEW_TRACK_FRAGMENT
作为标记传递。因此,您要添加一个没有关联标签的 NewTrackFragment
实例,因此对 findFragmentByTag
的调用将始终 return null
。本质上,每次旋转设备时都会创建一个 NewTrackFragment
的新实例。这并不好,因为 FragmentManager
的状态在设备旋转期间保留,这意味着它仍然保留您添加到它的每个 Fragment
。因为您无条件调用 add
,所以 FragmentManager
最终会持有 NewTrackFragment
.
的多个实例
话虽如此,您应该做的是在对 add
的调用中添加标记,并且仅在您知道 FragmentManager
当前未持有一个时才调用 add
NewTrackFragment
的实例:
mNewTrackFragment = (NewTrackFragment) getFragmentManager()
.findFragmentByTag(TAG_NEW_TRACK_FRAGMENT);
if (mNewTrackFragment == null) {
mNewTrackFragment = NewTrackFragment.newInstance();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.fragment_container, mNewTrackFragment, TAG_NEW_TRACK_FRAGMENT)
.commit();
}
您可能也想对 TrackListFragment
做一些类似的事情:
if (id == R.id.action_track_list) {
FragmentManager fragmentManager = getFragmentManager();
mTrackListFragment = (TrackListFragment) fragmentManager.findFragmentByTag(TAG_TRACK_LIST_FRAGMENT);
if (null == mTrackListFragment) {
mTrackListFragment = TrackListFragment.newInstance();
fragmentManager.beginTransaction()
.replace(R.id.fragment_container, mTrackListFragment, TAG_TRACK_LIST_FRAGMENT)
.addToBackStack(null)
.commit();
}
}
我有一个带有地图视图的片段。我可以从操作栏中打开另一个片段(称之为 listfragment),它工作正常。但是如果我旋转屏幕,然后尝试打开 listfragment,它不会加载,地图视图会按时闪烁(视图中的地图变为空白然后再次出现)。如果我尝试通过单击操作栏上的菜单项再次加载列表片段,应用程序会崩溃并显示
java.lang.IllegalStateException: Fragment already added:
加载片段的 MainActivity 部分:
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mNewTrackFragment = (NewTrackFragment) getFragmentManager()
.findFragmentByTag(TAG_NEW_TRACK_FRAGMENT);
if (mNewTrackFragment == null) {
mNewTrackFragment = NewTrackFragment.newInstance();
}
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.fragment_container, mNewTrackFragment)
.commit();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_track_list) {
if (null == mTrackListFragment) {
mTrackListFragment = TrackListFragment.newInstance();
}
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.fragment_container, mTrackListFragment, TAG_TRACK_LIST_FRAGMENT)
.addToBackStack(null)
.commit();
return true;
}
带有 MapView 的 NewTrackFragment 的一部分:
public NewTrackFragment() {
}
public static NewTrackFragment newInstance() {
NewTrackFragment fragment = new NewTrackFragment();
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_new_track, container, false);
mTrackTitleTV = (TextView) view.findViewById(R.id.tv_track_title);
mDistanceTV = (TextView) view.findViewById(R.id.tv_distance);
mElapsedTimeTV = (TextView) view.findViewById(R.id.tv_elapsed_time);
mSpeedTV = (TextView) view.findViewById(R.id.tv_speed);
mAscentTV = (TextView) view.findViewById(R.id.tv_ascent);
mDescentTV = (TextView) view.findViewById(R.id.tv_descent);
mAltitudeTV = (TextView) view.findViewById(R.id.tv_altitude);
mStartStopFab = (FloatingActionButton) view.findViewById(R.id.fab_startstop);
mMapView = (MapView) view.findViewById(R.id.new_track_mapview);
setupMapView(savedInstanceState);
return view;
}
private void setupMapView(Bundle savedInstanceState) {
mMapView.onCreate(savedInstanceState);
mMapView.getMapAsync(this);
}
我在谷歌上搜索了一些关于它的信息,但没有找到类似的东西。
这里有几处错误。现在,在 onCreate
中调用 add
时,您不会将 TAG_NEW_TRACK_FRAGMENT
作为标记传递。因此,您要添加一个没有关联标签的 NewTrackFragment
实例,因此对 findFragmentByTag
的调用将始终 return null
。本质上,每次旋转设备时都会创建一个 NewTrackFragment
的新实例。这并不好,因为 FragmentManager
的状态在设备旋转期间保留,这意味着它仍然保留您添加到它的每个 Fragment
。因为您无条件调用 add
,所以 FragmentManager
最终会持有 NewTrackFragment
.
话虽如此,您应该做的是在对 add
的调用中添加标记,并且仅在您知道 FragmentManager
当前未持有一个时才调用 add
NewTrackFragment
的实例:
mNewTrackFragment = (NewTrackFragment) getFragmentManager()
.findFragmentByTag(TAG_NEW_TRACK_FRAGMENT);
if (mNewTrackFragment == null) {
mNewTrackFragment = NewTrackFragment.newInstance();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.fragment_container, mNewTrackFragment, TAG_NEW_TRACK_FRAGMENT)
.commit();
}
您可能也想对 TrackListFragment
做一些类似的事情:
if (id == R.id.action_track_list) {
FragmentManager fragmentManager = getFragmentManager();
mTrackListFragment = (TrackListFragment) fragmentManager.findFragmentByTag(TAG_TRACK_LIST_FRAGMENT);
if (null == mTrackListFragment) {
mTrackListFragment = TrackListFragment.newInstance();
fragmentManager.beginTransaction()
.replace(R.id.fragment_container, mTrackListFragment, TAG_TRACK_LIST_FRAGMENT)
.addToBackStack(null)
.commit();
}
}