There is a Fragment in my android project in which it gets data dynamically from another class.I save that data(one string and Int) into bundle and And I want that bundle to be restored when screen rotates. So I have used onSaveInstanceState method.
In this fragment, "respond" method get data(one string and Int) from another class. I can print those strings in Logcat in respond method.
Fragment Code:
public class Images extends android.support.v4.app.Fragment implements Imageinfo {
private RecyclerView IRecyclerView;
private RecyclerView.Adapter IAdapter;
private RecyclerView.LayoutManager ILayoutManager;
private Context ctx;
private Bundle bundle=new Bundle();
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v =inflater.inflate(R.layout.images, container, false);
Log.d("ONCREATE VIEW", "TRUE");
IRecyclerView = (RecyclerView) v.findViewById(R.id.images_tab);
IRecyclerView.setHasFixedSize(true);
ILayoutManager = new LinearLayoutManager(getContext());
IRecyclerView.setLayoutManager(ILayoutManager);
if(savedInstanceState!=null){
Log.d("BUNDLE ADDED NOT NULL", String.valueOf(savedInstanceState.size()));
IAdapter = new ImageAdapter(this.getContext(),((fileselect)getContext()).imageset,bundle);
IRecyclerView.setAdapter(IAdapter);
}
else{
Log.d("BUNDLE ADDED NULL", "TRUE");
IAdapter = new ImageAdapter(this.getContext(),((fileselect)getContext()).imageset,null);
IRecyclerView.setAdapter(IAdapter);
}
return v;
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState=bundle;
Log.d("SAVING TIME", String.valueOf(outState.size()));
super.onSaveInstanceState(outState);
}
#Override
public void respond(String str,int type) {
if(str!=null) {
if (type == 1) {
bundle.putString(str, str);
Log.d("BUNDLE ADDED", bundle.getString(str));
Log.d("BUNDLE ADDED Size",String.valueOf(bundle.size()));
} else {
bundle.remove(str);
Log.d("BUNDLE REMOVED Size", String.valueOf(bundle.size()));
}
}
}
}
PROBLEM:
Although the method respond receiving data(one string and Int) and saving into Bundle, bundle is becoming size zero in onSaveInstanceState when screen rotated. onSaveInstanceState is getting called whenever i rotate screen but the bundle is becoming size zero. As bundle is becoming size zero, I could not restore the two strings.
OK the problem is that, instead of adding content to the outstate variable, you are trying to reference a local variable.
The point is that the instance of the Images class is destroyed on rotation, and so will your bundle variable.
The correct way to achieve what you are trying to do is to add your strings to the outstate variable in the onSaveInstanceState method, and read it from the savedInstanceState in the onCreateView.
Try this out:
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putString("YOUR_STRING_NAME", bundle.getString("YOUR_STRING_NAME"));
Log.d("SAVING TIME", String.valueOf(outState.size()));
super.onSaveInstanceState(outState);
}
Related
i have a view pager with 3 fragments. i use retrofit rest api to populate each of my fragments for the first time. What i would like to achieve is when the user swipes back either in first or third fragment(those 2 fragment are being being destroyed by the view pager) to restore the data(saved in an array list) and not make a rest api call again. What i have done is to save the array list of downloaded data in onSaveInstanceState() and successfully retrieve it when the user swipes back to one of the 2 above fragments only FOR THE 1 FIRST TIME. The problem is when i navigate back to either one of the 2 fragments the specific bundle key where the array list was saved contains null value.
CompletedSurveysFragment(the third fragment):
public class CompletedSurveysFragment extends Fragment implements SAMVCView {
private static final String debugTag = CompletedSurveysFragment.class.getSimpleName();
private View view;
private RecyclerView completedSurveysRcV;
private SAMVCPresenterImpl SAMVCpresenterImpl;
private SurveysRcvAdapter surveysRcvAdapter;
private List<SurveyData> data;
public CompletedSurveysFragment() {}
public static CompletedSurveysFragment newInstance() {
return new CompletedSurveysFragment();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.e(debugTag, "onCreateView");
if ( view == null ) view = inflater.inflate(R.layout.fragment_completedsurveys, container, false);
completedSurveysRcV = (RecyclerView) view.findViewById(R.id.completedSurveysRcV);
return view;
}
// TODO: 21/6/2016 configure Limit and offset values
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.e(debugTag, "onActivityCreated " + savedInstanceState);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
completedSurveysRcV.setHasFixedSize(true);
completedSurveysRcV.setLayoutManager(linearLayoutManager);
completedSurveysRcV.addItemDecoration(new DividerItemDecoration(ContextCompat.getDrawable(getActivity(), R.drawable.divider)));
if (savedInstanceState == null) {
SAMVCpresenterImpl = new SAMVCPresenterImpl(this);
SAMVCpresenterImpl.getSurveysBasedOnSpecificFirmId(new AllSurveysBody(getResources().getString(R.string.list_surveys), LoginActivity.getSessionPrefs(getActivity()).getInt(getResources().getString(R.string.firm_id), 0), getResources().getString(R.string.completed), 8, 0));
surveysRcvAdapter = new SurveysRcvAdapter(null, completedSurveysRcV);
completedSurveysRcV.setAdapter(surveysRcvAdapter);
} else {
//Log.e(debugTag, savedInstanceState.+"");
if (savedInstanceState.getParcelableArrayList("data") != null) {
Log.e(debugTag, "here "+ savedInstanceState);
surveysRcvAdapter = new SurveysRcvAdapter(savedInstanceState.<SurveyData>getParcelableArrayList("data"), completedSurveysRcV);
completedSurveysRcV.setAdapter(surveysRcvAdapter);
surveysRcvAdapter.notifyDataSetChanged();
}
//Log.e(debugTag, getArguments().getParcelableArrayList("data")+"");
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList("data", (ArrayList<? extends Parcelable>) this.data);
Log.e(debugTag, "CompletedFragment onSaveInstanceState "+ outState);
}
#Override
public void onSuccessSurveysFetched(List<SurveyData> data) {
this.data = data;
surveysRcvAdapter = new SurveysRcvAdapter(data, completedSurveysRcV);
completedSurveysRcV.setAdapter(surveysRcvAdapter);
surveysRcvAdapter.notifyDataSetChanged();
}
#Override
public void onFailure() {
}
}
View pager adapter:
public class SurveysPagerAdapter extends FragmentStatePagerAdapter {
private static final String debugTag = SurveysPagerAdapter.class.getSimpleName();
private List<SurveyData> data;
String[] tabText;
public SurveysPagerAdapter(FragmentManager fragmentManager, String[] tabText) {
super(fragmentManager);
this.tabText = tabText;
}
#Override
public Fragment getItem(int position) {
Log.e("SurveysPagerAdapter", position+"");
switch (position) {
case 0:
return CompletedSurveysFragment.newInstance();
case 1:
return OngoingSurveysFragment.newInstance();
case 2:
return PendingSurveysFragment.newInstance();
default:
return null;
}
}
#Override
public CharSequence getPageTitle(int position) {
return tabText[position];
}
#Override
public int getCount() {
return 3;
}
}
Your issue is that you're always returning a new instance of your fragment. Instead of calling CompletedSurveysFragment.newInstance(); (and your other Fragments) every time user swipes, create an array of fragments and retrieve it this way:
...
Fragment [] pages = new Fragment[getCount()];
...
#Override
public Fragment getItem(int position) {
Log.e("SurveysPagerAdapter", position+"");
switch (position) {
case 0:
if(pages[position] == null)
pages[position] = CompletedSurveysFragment.newInstance();
return pages[position];
...
}
Then, you can fetch and cache your data in onCreate() and retrieve it later in onResume() in your respective fragments.
I think onPause() and onResume() won't work. Fragments are tied to their parent activity so since you browse through fragments parent activity is on an onResume() status. What I suggest you to do is to use singleton objects to fetch and store your data. Each fragment can keep a reference to the respective object and have instant access to the data you need. There is plenty of info about singleton pattern and how it works.
The reason this is happening is because onSaveInstanceState only occurs when the parent activity is closed. Since the parent activity of your viewpager is still active when you switch between your fragments, onSaveInstanceState will not be called.
To get the data to save like you are intending, what I would likely do instead is save the data in onPause() and retrieve the data in onResume().
EDIT
According to the docs you need to put the call to super.onSaveInstanceState(savedInstanceState); after you modify the Bundle.
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
I need help.I don't know what is wron here.Need Saved Instance Data in fragment but it's not working for me? Can anyone help ? Here is my code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
if (savedInstanceState == null) {
Log.e(getActivity().getClass().getSimpleName(),"DATA is NULL");
}else{
Log.e(getActivity().getClass().getSimpleName(),"DATA IS NOT NULL " + savedInstanceState.getString(Constans.SAMPLEDATA));
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(Constans.MOVIE, movie);
outState.putString(Constans.SAMPLEDATA, "sampleData");
}
This is happening because on screen rotate your activity gets recreated so does the fragment inside it start from initial position again as it was started on activity first launch
You need to add this in onCreate of your activity and set the fragment inside if statement like this example
if (savedInstanceState == null){
launchfragment
} else {
// do nothing
}
hope this helps
Add super.onSaveInstanceState(outState);
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putParcelable(Constans.MOVIE, movie);
outState.putString(Constans.SAMPLEDATA, "sampleData");
super.onSaveInstanceState(outState);
}
I am building a memory game app for a java class and i need to save which words are displayed through rotation of the device...the widgets that need to be saved and passed to the new onCreate() method are button widgets that i used setText to display the words that are being shown....can i save and pass the entire state of the application...here is my code that is obviously not working and i was hoping i could get some insight...thanks...here is my code..
private Bundle myBundle = new Bundle();
.....
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_eight);
if(savedInstanceState != null) {
savedInstanceState = myBundle;
}
......
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
myBundle = savedInstanceState;
}
You got the semantics of using the Bundle backwards. You don't ever want to save the Bundle (or overwrite it). Just use it to serialize your own state variables into it and out of it. For example, if you want to preserve two integer variables and a string between a rotation (such that you can re-initialize the view with these members later), you could do the following:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_eight);
if(savedInstanceState != null) {
// Restore our member variables that represent activity state right here from the passed in Bundle.
_x = savedInstanceState.getInt("MyApp.X", 0);
_y = savedInstanceState.getInt("MyApp.Y", 0);
_name = savedInstanceState.getString("MyApp.NAME", "player");
// not shown - initializing the view elements with the initialized member variables.
}
......
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// save our activity state by adding our member variables that represent activity state into the Bundle.
savedInstanceState.putInt("MyApp.X", _x);
savedInstanceState.putInt("MyApp.Y", _y);
savedInstanceState.putString("MyApp.NAME", _name);
// call the parent method *after* you have saved your state
super.onSaveInstanceState(savedInstanceState);
}
Bundle also supports arrays of simple types.
In method onSaveInstanceState add values which you want to save like below
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putString("key","your string here");
}
and inside oncreate
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if( savedInstanceState != null ) {
System.out.println(savedInstanceState .getString("key"));
}
}
I want to save the state of my FragmentPagerAdapter so I can reuse it after the orientation of the screen changed. Unfortunately the method saveState returns always null.
My Adapter consists of an ActionBar with two Fragments.
Here ist my method call
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt(FRAGMENT, viewPager.getCurrentItem() + 1);
outState.putParcelable(ADAPTER, fragmentTabAdapter.saveState());
super.onSaveInstanceState(outState);
}
But the Adapter in outState is always null. I don't understand why. Is there something special I missed about the use of saveState?
Hope you can help me!
this example works if the fragment is not destroyed
private int pageID;
#Override
public void onPause() {
super.onPause();
pageID = mViewPager.getCurrentItem(); // 1 save
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mViewPager.setCurrentItem(pageID, false); // 2 load
}
I have a FragmentPagerAdapter that pages through views generated by a custom SurveyPage class. The final page in the pager is generated by SurveyFinishPage, which tries to access the Survey associated with the FragmentPagerAdapter and pulls all of the survey answers together to display them. The Survey object is grabbed by SurveyFinishPage via a getSurvey() method in the main Activity.
Normally this works fine and the SurveyFinishPage is able to access the same Survey object that the FragmentPagerAdapter is using. If the Activity has been killed and restored, though, the SurveyFinishPage seems to still be accessing the old Survey (or maybe a copy of it) - it displays the answers from before the Activity was discarded regardless of changes to answers to the new, rebuilt Survey.
It seems like restoring the value of aSurvey in onRestoreInstanceState() in my MainActivity should establish the survey object for everything else, since MainActivity passes its Survey object to the FragmentPagerAdapter, which uses that object to make Fragments... but instead it seems that the FragmentPagerAdapter and the SurveyFinishPage are looking at two different things.
How can I restore the state of the fragments in my FragmentPagerAdapter properly so that they all reference the same Survey object?
MainActivity.java
public class MainActivity extends FragmentActivity {
SurveyPagerAdapter mSurveyPagerAdapter;
ViewPager mViewPager;
Survey aSurvey;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_poll);
if(savedInstanceState != null) {
testSurvey = savedInstanceState.getParcelable("survey");
}
else {
testSurvey = new Survey();
}
mSurveyPagerAdapter = new SurveyPagerAdapter(getSupportFragmentManager(), aSurvey);
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSurveyPagerAdapter);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("survey", aSurvey);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
aSurvey = (Survey)savedInstanceState.getParcelable("survey");
}
[...]
}
SurveyPagerAdapter.java
public class SurveyPagerAdapter extends FragmentPagerAdapter {
private Survey survey;
[...]
#Override
public Fragment getItem(int i) {
Fragment fragment;
Bundle args = new Bundle();
// index 0 is the title page
if(i == 0) {
fragment = new SurveyTitlePage();
}
// final index is the finish page
else if(i == getCount()-1) {
fragment = new SurveyFinishPage();
}
// all other indices are regular poll pages
else {
args.putParcelable("question", survey.getQuestion(i-1));
fragment = new SurveyPage();
fragment.setArguments(args);
}
return fragment;
}
[...]
}
SurveyFinishPage.java
public class SurveyFinishPage extends Fragment {
private Survey survey;
[...]
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setSurvey(((MainPoll)getActivity()).getSurvey());
LinearLayout view = new LinearLayout(getActivity());
view.setOrientation(LinearLayout.VERTICAL);
Button finishButton = new Button(getActivity());
finishButton.setText("FINISH");
final TextView textView = new TextView(getActivity());
finishButton.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(View v) {
String output = "";
for(int i=0; i<survey.getSize(); i++) {
try {
output += survey.getQuestion(i).getPrompt() + " - " + survey.getQuestion(i).getAnswer() + "\n";
} catch (Exception e) {
output += survey.getQuestion(i).getPrompt() + " - " + "no answer\n";
}
}
textView.setText(output);
}
});
view.addView(finishButton);
view.addView(textView);
return view;
}
}
SurveyPage.java
public class SurveyPage extends Fragment {
[...]
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Bundle args = getArguments();
Question question = args.getParcelable("question");
View pageView = question.getQuestionView(getActivity(), container);
return pageView;
}
}
You could lift the Survey object to the Android application class and reference it as a singleton. That answer will likely create some debate, but it is a reasonable solution to your problem. Android guarantees there will only ever be 1 instance of your application so you can be certain (within reason) that you'll have only 1 instance of Survey.
http://developer.android.com/guide/faq/framework.html
Singleton class
You can take advantage of the fact that your application components run in the same process through the use of a singleton. This is a class that is designed to have only one instance. It has a static method with a name such as getInstance() that returns the instance; the first time this method is called, it creates the global instance. Because all callers get the same instance, they can use this as a point of interaction. For example activity A may retrieve the instance and call setValue(3); later activity B may retrieve the instance and call getValue() to retrieve the last set value.