Fragment has target not in Fragment Manager - android

I'm new to android programming.
I just try to save the state of the ListView in my fragment. For that I follow headless fragments (fragment which has no UI). In this fragment, I save the data, used in the ListView, and starting the headless fragment from the main fragment (the one which has the UI).
Now I got the exception:
java.lang.IllegalStateException: Failure saving state: RetainedFragment{4161f850 #1 work} has target not in fragment manager: JobOpeningFramgent{41601c00}
As far my concern, this is happening when I'm trying to replace the fragments with another one in the DrawerLayout.
Please temme the cause of this exception, for better understanding.
Thanks.
Boopathy.

Here's a workaround:
put this in the fragment that causes the problems:
#Override
public void onSaveInstanceState(final Bundle outState) {
setTargetFragment(null, -1);
...
and remember to set it to the real target fragment when you need it.

I'm not sure what do you want to save and where do you want to save it.
The official docs state that: "A Fragment represents a behavior or a portion of user interface in an Activity."
Using a Fragment as a container of another Fragment's UI state is generally a bad idea.
If you want to persist some values throughout the activity lifecycle (that includes screen rotations) just override onSaveInstanceState method. If you want to store some variables even after activity life-time use singelton class or Preferences, and if you want to store your values even after app life-time use SharedPreferences
Please elaborate on what do you exacly want

Related

how to implement UI changes when resuming fragment in kotlin

i'm a beginner developing in kotlin * android studio. i have 2 fragments in my app: a main fragment and a settings fragment. the two share a viewmodel. heres what i'm trying to accomplish:
app launches, takes you to main fragment
user clicks settings button, takes you to settings fragment
user alters settings (preferences stored in shared viewmodel)
user returns to main fragment, UI of main fragment is altered based on which settings were selected
i have completed steps 1-3 and am trying to implement 4. i am thinking i should override onResume() in my main fragment and implement UI changes there. first off, is this a good idea? if so, how can i access my UI elements from onResume()? any guidance is appreciated
I believe both of your fragments are living in the same activity in which case using a shared ViewModel is not a bad idea.
Having said that, for settings it might be a good idea to save them in SharedPrefences if they are primitive small sized data (String, int etc..)
You are right about overriding onResume() to change your UI. Since you are going to make those changes from your fragment you should override onViewCreated() and inside onViewCreated() you can access your UI elements like this, for example:
val textView = activity.findViewById<TextView>(R.id.my_textview)
Or, you can bind your ViewModel directly into your layout in that case you don't even have to override anything. You can read further about that here

Android - Save and recreate instance of fragment

I'm new to android development, and I have come across this article, that shows how to restore the activity state : http://developer.android.com/training/basics/activity-lifecycle/recreating.html
And I was wondering if it is the same about fragments, do I need to implement
onSaveInstanceState and onCreate
the way they show, or do I also need to add something to the activity, since it is a fragment, and it doesn't work exactly like an activity.

In which situation we want to add fragment without container?

Fragment transaction has method add(Fragment fragment, String tag), which does not place fragment to container, so it cannot have view. For what it can be used?
From the Android Documentation:
However, a fragment is not required to be a part of the activity layout; you may also use a fragment without its own UI as an invisible worker for the activity.
How about this purpose ?
Simple example: an Activity starts an AsyncTask, but when device rotated activity restarts, causing AsyncTask to lose connection with the UI Thread. But this Activity can hold a Fragment (invisible, with no UI at all) that can handle all the AsyncTask work. When Activity recreated the Android OS takes care reattaching the Fragment, thus no data loss will occur.
For Dialogs you don't have any container on normal app layer. It is directly added on Window with WindowManager(See WindowManager.LayoutParams for various types of layers).
DialogFragment has an API like DialogFragment.html#show(android.app.FragmentManager, java.lang.String) which corresponds to this.
You can use fragments without UI (container) as a background worker (one benefit is that you can retain it during rotations etc) and for retaining data during rotations and other changes.
Reading http://developer.android.com/guide/components/fragments.html is strongly recommended.
Example of instance retaining: https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/app/FragmentRetainInstance.java
Also, here are similar questions (so this questions seems to be a duplicated but cannot be flagged due to bounty):
What is the use case for a Fragment with no UI?
Android non-UI Fragment usage
As #Lucius Hipan mentions, it can be used to prevent data loss.
Almost always this king of fragments are used as Retained container ( setRetainInstance(true) called in onCreate method), then after device configuration changes (e.g. orientation changing) fragment will not be recreated but remembers previous state.
It's recommended way to use asynctask.
Here is an example:
There is login activity. The user enters their credentials and presses the Login button. After that configuration change occurs (user rotates phone). So, network task was completed, but your handlers was not listening for it now. If you show any login animation, it can be stored via savedInstance, but listeners not. And instead of creating service you can simply create new retained fragment with persistant asynctask and interface to communicate with activity.
This method is a good compromise for small projects where using bus libraries is overstatement.
By calling the method add(Fragment fragment, String tag) internally calls add(int containerId, Fragment fragment, String tag) with a 0 containerId.That will be add(0, fragment, tag).
If 0 is supplied as containerId, it will not be placed the fragment in a container.

Android, why shouldn't one Fragment call another directly?

According to Android guidline, http://developer.android.com/training/basics/fragments/communicating.html
One fragment should send data to another one via the hosting Activity. I'm wondering there is a reason for that.
Since in my code, I put one variable to hold pointer to the another fragment, and assign it in onActivityCreated
//this code is in class FragmentType1, assign the pointer to the FragmentType2 for later use
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final FragmentManager fm = getFragmentManager();
mOtherFragment = (FragmentType2) fm
.findFragmentById(R.id.container_fragment);
}
and later if I want to set data for FragmentType2, I just call:
public setData(MyData data){
if (mOtherFragment!=null)
mOtherFragment.setData(data);
}
Everything is working fine now. What's wrong with that approach? Tks.
There's at least 2 reasons for it:
To facilitate de-coupling of fragments.
To avoid memory leaks that can happen by storing a reference to one fragment in another.
Another reason would be to maintain the state when the hosting activity is destroyed.
After recreation, you could fetch the state from the hosting activity, since the fragment itself would be unable to save it's state directly.
And last but not least, it is really hard for dynamically added fragments, especially when it comes to nested fragments, to get sure that both fragments are "alive" at the same time. Fragments life cycle is complex to manage properly and using a direct communication presumes you completely control this, which is rarely true.
The best model to my mind is to use an event bus, like Otto or EventBus or RoboGuice's bus.

Saving ListData Objects with onSavedInstanceState

I have an app that has one main Activity that swaps out numerous Fragment's. Well it doesn't matter what Fragment you are on, after low memory kills the Activity and you try to return to the app, it boots you back to the "start" Fragment that the Activity first calls. (Note: Almost all of these are actually ListFragment's)
So here are my questions:
Should I be using onSaveInstanceState() in EACH Fragment? And if so, am I saving the Data in the Fragment OR the Fragment itself? Or do you use onSaveInstanceState() only once in the Main Activity. (If this is even the course to take)
Note: I have setRetainInstance(true) but I don't think I am handling that correctly, if that is the solution. These are all put as the last line of onActivityCreated().
The answer depends a lot on how you are managing fragments.
I'll assume you are not using the Fragment backstack, and that you have called setRetainInstance(true) on EACH fragment.
You need to use a tag when you attach the fragments.
In Activity#onSaveInstanceState() you need to remember which fragments are visible.
In Activity#onCreate you need to find the existing Fragments by tag for each fragment, then create new instances of any Fragments you can't find. Now you can use the information from the saved instance state to make the appropriate Fragments visible (show or add or replace as necessary depending on how your code manages the fragments.)
Edit in response to questions/comments:
activty.getFragmentManager().findFragmentByTag(tag); finds an existing fragment
in a Fragment transaction: add(fragment, tag), replace(id, fragment, tag), etc. lets you specify the tag. You can also put it in a layout file using the attribute
class=".myFrag$tag"
The actual fragment object including its contents still exist when you use setRetainInstance.
Note: If you don't want to use tags, you may also use the fragment manager's putFragment/getFragment methods to put the fragment into the instance state bundle.
Finally you can simply let the fragment save itself by calling FragmentManager's saveFragmentInstanceState but I've had trouble using this correctly.

Categories

Resources