java.lang.IllegalStateException: FragmentManager has been destroyed
Asked Answered
D

5

19

In activity onResume method I call volley request, which is getting list of items and then loads them to ListFragment inside this activity. When I enter activity for the first time everything is working correctly, but when I re-enter activity the ListFragment is empty and there is message in console "FragmentManager has been destroyed".

This is my activity's code:

@Override
protected void onResume() {
    super.onResume();
    // Volley request inside - which call back albumsFoundViewUpdate
    artistController.getArtistAlbums(artist);
}

public void albumsFoundViewUpdate(ArrayList<UserAlbumLink> links)
{
    // Load list fragment
    UserAlbumLinkListFragment fragment = new UserAlbumLinkListFragment(links, artist);
    getSupportFragmentManager().beginTransaction().replace(R.id.artist_activity__albums_container, fragment).commit();
}

The exception is thrown at commit() statement.

My ListFragment code:

public class UserAlbumLinkListFragment extends ListFragment {
    private List<UserAlbumLink> albumLinks;
    private UserAlbumLinkListAdapter adapter;
    private Artist artist;


    public UserAlbumLinkListFragment() {
    }

    public UserAlbumLinkListFragment(List<UserAlbumLink> albumLinks, Artist artist) {
        this.albumLinks = albumLinks;
        this.artist = artist;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        adapter = new UserAlbumLinkListAdapter(getActivity(), R.layout.album_list_item, albumLinks, artist);
        setListAdapter(adapter);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_album_list, container, false);
    }
}

As I understand FragmentManager gets destroyed when activity is getting destroyed, but how do I get new FragmentManager for recreated activity? Why getSupportFragmentManager() is not working?

Denesedengue answered 11/3, 2020 at 17:8 Comment(0)
S
17

This happens when you get the FragmentManager from an Activity that was destroyed, usually if you do activity.getSupportFragmentManager(); from another class for example.

In your case, first check if the FragmentManager was not destroyed, then use it:

FragmentManager fragmentManager = getSupportFragmentManager();

if (!fragmentManager.isDestroyed()) {
    fragmentManager
    .beginTransaction()
    .replace(R.id.artist_activity__albums_container, fragment)
    .commit();
}
Sheehan answered 8/11, 2021 at 23:9 Comment(3)
What should be pass in fragment?Rotor
What would be a good practice to write in an "else" block? I mean, when this "if" statement is not executed, what would happen? I should rebuild the activity or the fragment manager?Akela
@Rotor The fragment that you want to show.Grits
H
7

you need to check whether the activity is still running or it has finished

if(!isFinished()){
 FragmentManager fragmentManager = getSupportFragmentManager();
 fragmentManager.beginTransaction()
.replace(R.id.artist_activity__albums_container, fragment)
.commit();

 }

that function will get the boolean value from activity lifecycle functions. I think this will work for you!

Highminded answered 11/3, 2020 at 18:15 Comment(2)
Where does isFinished comes from ?Judicious
thanks for your answer. it was isFinishing() in my case from Activity.javaLowelllowenstein
O
1
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .replace(R.id.artist_activity__albums_container, fragment)
    .commit();

I guess this is how it should ideally be called. You may check once.

Orlan answered 11/3, 2020 at 17:19 Comment(2)
Tried this one, but result is the same. When I call getSupportFragmentManager() for the second time the fragmentManager.isDestroyed() is already = true. I've even tried to create FragmentService class like this public class FragmentService { public static void replaceFragment(FragmentActivity activity, int container, Fragment f){ FragmentManager fragmentManager = activity.getSupportFragmentManager(); fragmentManager.beginTransaction().replace(container, f).commit(); } } but it didn't help eitherDenesedengue
This is excatly the same like in the question. A temporary variable for the fragment manager changes nothing.Grits
F
1

Check if the class related to Volley request is holding a reference to your activity. If that is the case, by the time you relaunch your application, the old activity would have been destroyed but the request gives the callback to it which leads to the error - "FragmentManager has been destroyed". It is better to pass your activity as callback reference while calling the volley request functions and checking isFinishing() before acting on the request callback.

Floatable answered 9/4, 2021 at 8:54 Comment(0)
D
-5

I totally didn't get why did it worked, but I've solved the problem. I've created static activity variable and initiate it with this in onCreate method:

private static ArtistActivity activity;
@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    activity = this;
    ...
}

And I've noticed that in method albumsFoundViewUpdate this.isDestroyed() returns true (when I relaunch this activity for second time) and activity.isDestroyed() returns false. So I've remake albumsFoundViewUpdate like this:

public void albumsFoundViewUpdate(ArrayList<UserAlbumLink> links)
{
    // Load list fragment
    UserAlbumLinkListFragment fragment = new UserAlbumLinkListFragment(links, artist);
    FragmentManager fragmentManager = activity.getSupportFragmentManager();
    fragmentManager.beginTransaction().replace(R.id.artist_activity__albums_container, fragment).commit();
}

and now it's working perfectly fine every time!

Denesedengue answered 11/3, 2020 at 20:55 Comment(7)
If anyone can explain that, please do. I totally don't get it...Denesedengue
This worked for me as well. I guess it has to do because of the Activity's instance.Encyst
please do not add a static reference to an Activity, that will create a memory leak since the reference will never be garbage collected. Try to rotate your device some times and you will have several instances of your Activity in memoryPollster
Avoid static instance.. it will create more problems than solve itSergio
You are setting yourself up for OutOfMemoryExceptions by holding a static reference to an Activity.Rothstein
@KasperFinneNielsen I'm assuming my activity is getting killed and recolected by garbage collector after a long time my app stays in the background. Is there a way to prevent this? without making a static activity. I mean, I want to set activity to higher priority so it doesn't get killed that easilyAkela
@DanielCettour This is the way it has to be. Activities in the background have to be destroyed after some time. Everything you do against this is wrong. If you need a background application you have to create a service.Grits

© 2022 - 2024 — McMap. All rights reserved.