Issue
I have a fragment with a mapview. I can open another fragment (call it listfragment) from the action bar, it works fine. But if I rotate the screen, and then try to open the listfragment, it does not load, instead the mapview flickers on time (the map in the view goes blank and then appears again). If I try to load the listfragment again by clicking the menuitem on the action bar, the app crashes with
java.lang.IllegalStateException: Fragment already added:
Part of MainActivity that loads the fragment:
@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;
}
Part of NewTrackFragment with the MapView:
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);
}
I googled the best of the evening for some info about it but found nothing similar.
Solution
There's a couple of things wrong here. Right now, you are not passing TAG_NEW_TRACK_FRAGMENT
as a tag in the call to add
within onCreate
. Because of this, you are adding a NewTrackFragment
instance without an associated tag, and therefore the call to findFragmentByTag
will always return null
. Essentially, you are creating a new instance of NewTrackFragment
every time you rotate the device. This is not good, because the state of the FragmentManager
is preserved across device rotations, meaning it is still holding on to each Fragment
you add to it. Because you are unconditionally calling add
, the FragmentManager
will end up holding multiple instances of NewTrackFragment
.
With that said, what you should do is add the tag in the call to add
and only call add
once you know the FragmentManager
is not currently holding on to an instance of 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();
}
You might want to do something similar with your TrackListFragment
as well:
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();
}
}
Answered By - cascal
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.