2

I know there are tons of questions about Fragments and I read many, but it seems I haven't grasped it yet.

My app has 9 Fragments. On one of them, say Fragment X, I am playing media and from there it shows up another Fragment on screen, say Y. To perform that, I thought the best was using replace().

My relevant code:

// Button clicked, goes from X to Y
getFragmentManager().beginTransaction()
                .replace(R.id.container, fragmentY)
                .commit();

When onBackPressed() is called and fragmentY is the one returned by fragmentManager.findFragmentById(R.id.container):

fragmentManager.beginTransaction()
                    .replace(R.id.container, fragmentX)
                    .commit();

Expected behavior: it'd remove X and add Y. When going back, it'd remove Y and add X.

What happened: first time I go to Y, Y is shown as expected, but X is still running as I hear the audio playing. When I go back, Y disappears and it seems fine. However, next time I click to go to Y, X is then destroyed (audio stops playing) and the app gets weird, since my ActionBar shows up and it shouldn't. Moreover, I keep a hidden Fragment with a map that gets blank after executing that.

I imagine replace() not only removes the current fragment, but all of the visible fragments. But doing .remove(X).add(Y, "y") does not show my Fragment.

Any help?

EDIT: As it was asked, my Fragment X can be added to the Activity from different points on the app, hence on different ways. They're two:

// If backPressed and current Fragment is A
fragmentTransaction.remove(fragmentA).add(R.id.container, objectFragment).commit();

or

// If backPressed and current Fragment is B (map)
fragmentTransaction.hide(fragmentB).add(R.id.container, objectFragment).commit();

Most of the times I must know where I am coming from and where I'm going, that's why I did not use addToBackStack().

Teo Inke
  • 5,928
  • 4
  • 38
  • 37
  • 2
    Is there any reason for no using the `addToBackStack(null)` on the transaction? The FragmentManager has a built in mechanism to perform this kind of navigation with the back button. In this scenario, when a fragment is sent to the backstack, its views are destroyed and recreated by calling onCreateView and onActivityCreated but not onCreate. – droidpl Jul 08 '15 at 22:16
  • Is on Destroy() of fragment x called – Aniruddha K.M Jul 09 '15 at 00:09
  • How is X initially added to the Activity? If it's not removed when Y is shown, maybe it was not added properly. Also, do you stop playing audio in Fragment.onStop()? If not, it's possible that the media player continues to play even if the Fragment has been effectively removed. – BladeCoder Jul 09 '15 at 00:55
  • @feantury, I have so many peculiarities and customization between fragment transitions (such as showing/hiding an ActionBar, or hiding/showing a Map that's never removed) that I just chose to do everything "manually," and it had worked so far. I've tried to use addToBackStack in this case, but it didn't work well, things just got messed up. – Teo Inke Jul 09 '15 at 16:36
  • @was_Hero, yes, but only the second time I go to Y – Teo Inke Jul 09 '15 at 16:37
  • @BladeCoder, I just added more code to my question. And my media is being paused on onPause(), so I don't get why I'm supposedly removing my Fragment and it hasn't even been paused. – Teo Inke Jul 09 '15 at 17:03
  • You should not hide the map fragment because it would still be in the container, you should detach it. Always keep a single fragment in your container. – BladeCoder Jul 09 '15 at 19:28
  • Also if you use addToBackStack you can know where you're going if you set a backstack listener. – BladeCoder Jul 09 '15 at 19:30
  • I know it will be in the container, but I need to keep my View in the same state, as my map has lots of downloaded images and also I want to keep it in the same position/zoom. It takes more memory to keep it loaded in memory, but I hadn't run into any NoMemoryException so far. – Teo Inke Jul 09 '15 at 23:33

2 Answers2

0

I would try to manage that adding the fragment to the back stack, using the

addToBackStack(String name) method.

There is a really helpful answer on that subject here: Difference between add(), replace(), and addToBackStack()

Community
  • 1
  • 1
iomv
  • 2,409
  • 18
  • 28
  • Thanks for your answer, but I've tried addToBackStack() and it didn't work well. See my edit to understand better. I believe the problem of this approach is that I don't just add/remove fragments, but I keep a map being hidden/shown. – Teo Inke Jul 09 '15 at 17:05
0

I'm afraid I didn't provide enough information to spot the main mistake, but anyways I'll post how I solved it and my conclusion.

The main mistake: replace() was showing Y and remove().add() was not because I was doing .add(fragmentY, tag), where it should be .add(R.id.container, fragmentY, tag).

From the documentation:

add(Fragment fragment, String tag)

Calls add(int, Fragment, String) with a 0 containerViewId.

And honestly, I couldn't figure why or when you would add a Fragment to nowhere. If someone knows the usage of it, please post a comment or edit this answer.

The second problem: as I mentioned, I have a map that is always added to the Activity and I keep hiding/showing it to keep its state. The problem with using replace() is that, well, again, from the documentation:

replace(int containerViewId, Fragment fragment, String tag)

Replace an existing fragment that was added to a container.

However, when I looked into the full description I understood:

Replace an existing fragment that was added to a container. This is essentially the same as calling remove(Fragment) for all currently added fragments that were added with the same containerViewId and then add(int, Fragment, String) with the same arguments given here.

Which means my map was being removed as well.

Lessons learned:

  • there's a method add() that does not receive the container ID and should be avoided
  • .replace(new) is not exactly the same as .remove(current).add(new).
Teo Inke
  • 5,928
  • 4
  • 38
  • 37