Is that compulsory to set data using bundle and set argument?
What is wrong Here?
MyFragment frag = new MyFragment ()
frag.setData(mSchoolData);
//add to back stack stuff.
by using the setArgs() you will ensure that this Fragment can be recreated due to lifecycle event...while by passing arguments with your own setters it may not work properly under certain circustances. That is why it is absolutely recommended to either uset Args OR use Intent extras, these will always be automatically provided by the system if the fragment gets recreated.
Related
I have a Fragment that is used in a ViewPager. Fragment instances are constructed via factory method like this:
public static MyFragment newInstance(int sectionNumber, List<String> aList) {
MyFragment fragment = new MyFragment();
fragment.list = aList;
return fragment;
}
The list is passed from the activity's onCreate() method to a SectionsPagerAdapter instance where I call newInstance() for my fragment. The list can never be null (there are checks in the code).
Problem: The application fails with NPE in onStart() method when I try to enter
Multi-Window view. The list is null.
What I noticed is that the fields that I set in newInstance() call are now nulls. Only those that are initialized in onCreateView() are assigned with objects. I guess the system initializes my Fragment in a different way bypassing my newInstance() method.
Question: Why fields that are set in my factory method are set to null? Why it happens only in Multi-Window mode? How to prevent this?
Probably I misuse something, thought creating a fragment via factory method is what Astroid Studio offers by default.
You should never be setting data in your fragment like that because of this exact issue.
When your app goes into multi window mode your fragment/activity get recreated so any data you passed in like that is lost.
What you should be doing that does handles configuration changes is pass your data in a bundle to your fragment via setArguments. When your fragment loads you then get the bundle via getArguments then grab the information from the bundle and proceede as normal.
get/setArguments holds the bundle information through configuration changes
it would look something like this
myFragment = new MyFragment();
Bundle b = new Bundle();
b.putLong("list",aList);
myFragment.setArguments(b);
Multi-window is a form of Configuration change. I bet if you rotate the device the same issue will occur.
In your Activity's AndroidManifest block, try adding the following (as a property of <activity>:
android:configChanges="keyboard|screenLayout|screenSize|orientation"
This will tell Android that you want to handle Configuration changes yourself, and will call your Activity's (and Fragment's) onConfigurationChanged() method instead of handling itself. Leave that method alone and you should be good.
I am still new to Android programming, i did search for checking the difference between Bundle in Activity and in Fragment and what are the use cases of these.
Please give me the difference with exact use case.
Thanks for your help :)
It is a different bundle.
When you create activity you get system or custom bundle (with save data).
When you create fragment you can put same date from activity (ex same id) but this will be a new bundle.
If you want same data in frament like super.onSaveInstanceState(savedInstanceState); in activity, you need to return this bundle to activity, and for restoring you must parse this data in activity and put to fragment.
Is there a way to send a bundle to a fragment without actually putting that fragment into a container? I ask because I want to take a few Strings from an EditTexts input field and then call them in another fragment at a later time.
I have code like this
Bundle bundle = new Bundle();
Fragment fragment = new Assessment_Fragment();
bundle.putString("company", companyName);
bundle.putString("project", projectName);
fragment.setArguments(bundle);
getFragmentManager().beginTransaction()
.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
.replace(R.id.header_fragment_container, fragment).commit();
In this code I pass the bundle with the transaction but I also replace the existing fragment in the "header_fragment_container". I don't want to do that. I just want to pass the bundled data to the specified fragment. When that fragment is eventually called I will receive the bundle. Is this possible?
Is this possible?
Sure. Just delete the last Java statement (getFragmentManager()....).
Now, as to whether it is sensible for you to create a fragment, then never add it to the fragment manager (either with a UI or not), that's another matter. Java supports lots of classes; Fragment is just one of them. If you need a generic data container, choose something lighter weight, such as just the Bundle itself.
So I've learned that I need an empty constructor in order for my fragments not to crash on reinitialization. My problem is that I use lists of data for my fragments when they are initialized (at least some of them). So what would be a good way to start new fragments with a list of data. Should I in the OnCreate() make a getData method which gets the data from some other source or what would be a proper approach?
Feeding the bundle with data really wouldn't be a very good approach as I have a lot of data.
So let's take a case (I understand it tons better that way).
When a user clicks on a button the fragment is started. What I used to do was creating a new fragment this way:
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.center_container, new DetailFragment(item));
fragmentTransaction.addToBackStack(DETAIL_TAG);
fragmentTransaction.commit();
Then in my fragment:
public DetailFragment(EventItem item) {
mItem = item;
mPlaces = Database.getContainerPlaces(getActivity()).getValidItems();
}
I can't give all the data to a bundle, so that wouldn't work. So what should I do?
A: Should I initialize the fragment with the empty constructor and then from my activity use setters to set the data directly in the fragment? However, won't I be missing data if the user presses home, Android closes the fragment and the user later returns?
B: Should I initialize the fragment with factory pattern and call setRetainInstance(true), give the fragment a key for identifying the data, and then letting the fragment fetch the data needed in onCreateView from some third source?
C: Should I just make an empty constructor and then in onCreate() fetch the data needed for the fragment?
It should be noted that the app is locked in portrait so the issue is primarily with maintaining the objects when Android closes and the user restarts.
So what would be a good way to start new fragments with a list of data.
Use the factory pattern and the "arguments" Bundle, such as:
package com.commonsware.empublite;
import android.os.Bundle;
public class SimpleContentFragment extends AbstractContentFragment {
private static final String KEY_FILE="file";
protected static SimpleContentFragment newInstance(String file) {
SimpleContentFragment f=new SimpleContentFragment();
Bundle args=new Bundle();
args.putString(KEY_FILE, file);
f.setArguments(args);
return(f);
}
#Override
String getPage() {
return(getArguments().getString(KEY_FILE));
}
}
If you are retaining your fragment instance, you should be able to get away with just using ordinary setters to put stuff in data members. The "arguments" Bundle is retained as part of configuration changes, so for non-retained instances, this is the way to ensure your setup data is retained if the user rotates the screen, etc.
I currently have an app that relies heavily on Intents and the extras given to them before starting the activity. The extras are used when calling a webservice which in turn supplies the content that needs to be shown
I am trying to convert that model, to one where I have a static Fragment (lets call it Player) at the bottom of my screen, and another Fragment (lets call it Content) above it which will show the main content. By selecting options on the main screen other content will be shown by replacing the Content Fragment.
But, these new Fragments are currently the Intents that rely on the extras so heavily.
Is there a way to replace a Fragment by a new one, but still be able to add extras to it?
If so, let's say I have the following piece of code:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_holder, new MusicAlbumList(), "albumlist");
ft.commit();
How would I add the extras to the MusicAlbumList?
If that's not possible, how will I get the data that's currently being passed through extras into my new Fragment before it force closes due to missing essential data?
Or you can do this
MusicAlbumList fragment = new MusicAlbumList();
Bundle args = new Bundle();
args.putString("StringName","Value here");
fragment.setArguments(args);
then do your replace stuff. Then in the fragments onStart or onCreate call this.getArguments(); to pull the bundle, then get your extras out of there.
Change the constructor of MusicAlbumList from default constructor to one with arguments like new MusicAlbumList(int arg1, ...) and pass the values you want to set through the constructor