I have a tableLayout in a fragment that´s not showing anything when the information used to populate the cells is taken from the savedInstanceState bundle from OnCreateVIew()
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = initializeViews(inflater,container);
if (savedInstanceState!= null){
cellsTextArrayList = savedInstanceState.getStringArrayList("extractedTextEt");
for (String word: cellsTextArrayList){
addRow(word);
}
}
return rootView;
}
private void addRow(String word){
final TableRow tr = new TableRow(getActivity().getApplicationContext());
final View view = LayoutInflater.from(getActivity().getApplicationContext()).inflate(R.layout.cell_layout, null);
EditText actualCell = view.findViewById(R.id.cell_text);
actualCell.setText(word);
tr.addView(view);
tableLayout.addView(tr);
}
#Override
public void onSaveInstanceState (Bundle outState)
{
cellsTextArrayList.add("first");
cellsTextArrayList.add("second");
cellsTextArrayList.add("third");
outState.putStringArrayList("extractedTextEt", cellsTextArrayList);
super.onSaveInstanceState(outState);
}
The cellsTextArrayList is being restored from the savedInstanceState object, the addRow() method is the one that´s not working. I ran the code on an Activity and it worked so I think this has to do with the Fragment lifecycle.
using onActivityCreated in fragment.
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
...
if (savedInstanceState != null) {
//Restore the fragment's state here
}
}
and then in the activity, you have to save the fragment's instance in onSaveInstanceState() and restore in onCreate().
class MyActivity extends Activity {
private MyFragment
public void onCreate(Bundle savedInstanceState) {
...
if (savedInstanceState != null) {
//Restore the fragment's instance
mMyFragment = getSupportFragmentManager().getFragment(savedInstanceState, "myFragmentName");
...
}
...
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//Save the fragment's instance
getSupportFragmentManager().putFragment(outState, "myFragmentName", mMyFragment);
}
}
Related
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 have fragment contains recyclerview in main activity
Fragment.java
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = inflater.inflate(R.layout.activity_main, container, false);
initInstances(view);
setRetainInstance(true);
return view;
}
private void initInstances(View view) {
mRecyclerView = (RecyclerView) view.findViewById(R.id.dialogList);
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
adapter = new MyAdapter(items);
mRecyclerView.setAdapter(mAdapter);
}
MainActivity.java
in onCreate method:
myFragment = (MyFragment) getSupportFragmentManager().findFragmentByTag(MyFragment.TAG);
if (MyFragment == null) {
MyFragment = new MyFragment();
getSupportFragmentManager().beginTransaction().add(R.id.content_frame,
myFragment, MyFragment.TAG).commit();
}
But when orientation changed, my RecyclerView redrawn.
I've tried save state with overriding onSaveInstanceState and onRestoreInstanceState like this How to prevent custom views from losing state across screen orientation changes or Saving and restoring view state android, but to no avail for me
How to correctly save state of RecyclerView and adapter's items when orientation change?
SOLUTION:
My fragment extends from BaseFragment with some methods:
public class BaseFragment extends Fragment{
Bundle savedState;
public BaseFragment() {
super();
if (getArguments() == null)
setArguments(new Bundle());
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (!restoreStateFromArguments()) {
onFirstTimeLaunched();
}
}
protected void onFirstTimeLaunched() {
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
saveStateToArguments();
}
public void saveStateToArguments() {
if (getView() != null)
savedState = saveState();
if (savedState != null) {
Bundle b = getArguments();
b.putBundle("internalSavedViewState8954201239547", savedState);
}
}
private boolean restoreStateFromArguments() {
Bundle b = getArguments();
savedState = b.getBundle("internalSavedViewState8954201239547");
if (savedState != null) {
onRestoreState(savedState);
return true;
}
return false;
}
private Bundle saveState() {
Bundle state = new Bundle();
onSaveState(state);
return state;
}
protected void onRestoreState(Bundle savedInstanceState) {
}
protected void onSaveState(Bundle outState) {
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onStop() {
super.onStop();
}
#Override
public void onDestroyView() {
super.onDestroyView();
saveStateToArguments();
}
In my fragment I override methods and save state of mLayoutManager
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
protected void onSaveState(Bundle outState) {
super.onSaveState(outState);
outState.putParcelable("myState", mLayoutManager.onSaveInstanceState());
}
#Override
protected void onRestoreState(Bundle savedInstanceState) {
super.onRestoreState(savedInstanceState);
mLayoutManager.onRestoreInstanceState(savedInstanceState.getParcelable("myState"));
}
I searched how to get the scroll position of the RecyclerView, but didn't see where I can retrieve it, so I think the best solution is to handle rotation changes directly in your java code, and preventing your activity to restart on orientation change.
To prevent restarting on orientation change, you can follow this solution.
After preventing your Activity from restart, you can build 2 xml layout files, one for portrait mode, and one for landscape mode, you add a FrameLayout in both xml files, holding the place for your RecyclerView.
When the onConfigurationChange(Configuration newConfig) method is called, you call setContentView(int layoutFile) with the appropriate LayoutFile following the new orientation, and add your RecyclerView you are holding in a member of your class in the FrameLayout.
I made a test application so I can learn how to save the InstanceState.
Now we have a Main Fragment Activity and two Tab Fragments. I have a variable in the Main Activity that it's value sat in the onCreate method.. and I would like to share it with the fragments.
So I created a public method in the Main Activity to call it inside the fragments when I need the value of that variable. ((TMainActivity) getActivity()).getTestString()
The problem is when the device is rotated I got the default value of the string and not the saved value.
And that's obviously because onRestoreInstanceState is called after the onCreate of the fragments.
Now, how can I work that out?
TMainActivity.java
public class TMainActivity extends FragmentActivity {
final private static String TAG = "TMainActivity";
final private static String EXTRA_TEST = "MAIN_KEY";
private CollectionPagerAdapter mCollectionPagerAdapter;
private ViewPager mainPager;
private String test = "Default";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v(TAG, "onCreate() Before test= " + test);
if (savedInstanceState == null) {
test = "New";
} else {
test = savedInstanceState.getString(EXTRA_TEST) + " - Restored";
}
Log.v(TAG, "onCreate() After test= " + test);
mainPager = (ViewPager) findViewById(R.id.main_pager);
mCollectionPagerAdapter = new CollectionPagerAdapter(getSupportFragmentManager());
mainPager.setAdapter(mCollectionPagerAdapter);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.v(TAG, "onSaveInstanceState()");
outState.putString(EXTRA_TEST, test);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.v(TAG, "onRestoreInstanceState()");
Log.v(TAG, "onRestoreInstanceState() savedInstanceState=" + (savedInstanceState != null));
test = savedInstanceState.getString(EXTRA_TEST);
}
public String getTestString() {
return test;
}
private class CollectionPagerAdapter extends FragmentStatePagerAdapter {
public CollectionPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = null;
switch (i) {
case 0:
fragment = new Tab1Fragment();
break;
case 1:
fragment = new Tab2Fragment();
break;
}
return fragment;
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
return "OBJECT " + (position + 1);
}
}
}
Tab1Fragment.java
public class Tab1Fragment extends Fragment {
final private static String TAG = "Tab1Fragment";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "onCreate()");
Log.v(TAG, "getTestString()=" + ((TMainActivity) getActivity()).getTestString());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_tab1, container, false);
return rootView;
}
}
Tab2Fragment.java
public class Tab2Fragment extends Fragment {
final private static String TAG = "Tab2Fragment";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "onCreate()");
Log.v(TAG, "getTestString()=" + ((TMainActivity) getActivity()).getTestString());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_tab2, container, false);
return rootView;
}
}
I just had the same problem. First is called onCreate in the Activity and in this method you have already available that Bundle with your data. That means that you can restore the Activity and then use the data in onCreateView of the Fragment which is called later.
Basically you do not override the onRestoreInstanceState() method, but rename it and call it from onCreate in your Activity. The reason not to override that method is because it would be called 2 times—from onCreate by you and then as a part of the Activity life-cycle. That would reset the value if it was changed in the Fragment.
In your case you can just move
Log.v(TAG, "getTestString()=" + ((TMainActivity) getActivity()).getTestString());
from onCreate to onCreateView.
This not a good solution when you're restoring large amount of data. Your UI thread would get stuck on restoring the Activity. But in such a case you can restore just some part of the data that is needed in the Fragment and the rest restore in onRestoreInstanceState.
I have used multiple tabs in fragment class. I was failed in saving the state of fragment. I used the method onSaveInstanceState() and save a parameter in it. But when I came back to this fragment the saved state always shows "null". I tried all the questions and answers regarding to this.Still I am facing the same problem. Please could anyone help me to solve this.
MY CODE
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setRetainInstance(true);
super.onCreate(savedInstanceState);
Log.d("savedInstanceStateInfo1", "" + savedInstanceState);
if (null != savedInstanceState) {
nAndroids = savedInstanceState.getInt("nAndroids");
Log.d("NANDROIDS", "" + nAndroids);
}
}
// Log.d("State in oncreate : ",""+savedInstanceState);
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
Log.d("SavedinstanestateInfo", "" + savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
if (container == null) {
return null;
}
// final ActionBar ab=getActivity().getSupportActionBar();
View v = (LinearLayout) inflater.inflate(R.layout.infotab, container, false);
Log.d("SavedinstanestateInfo", "" + savedInstanceState);
return v;
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt("nAndroids", nAndroids);
super.onSaveInstanceState(outState);
}
1) Apparently when using setRetainInstance(true), the Bundle for onRestoreInstanceState is null.
https://stackoverflow.com/a/8488107/1011746
2) Not necessary, but more customary to call super.onSaveInstanceState(outState) before making any modifications to outState. Same for super.onRestoreInstanceState(outState) in onRestoreInstanceState(Bundle outState).
I am adding a Map to a fragment with this code:
public class MapFragment : Fragment
{
private MapActivity map=null;
public override Android.Views.View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return new FrameLayout(Activity);
}
public override void OnActivityCreated(Bundle savedInstanceState)
{
base.OnActivityCreated(savedInstanceState);
map = new MapView(Activity,"XXXXX-v0jt5Z-XXXXXX");
//HOW TO ADD THE VIEW HERE???
}
}
My question is, in Mono for Android how to I add the Map to the View.
Note: In Java I would write this:
((ViewGroup)getView()).addView(map);
Footnote: This example uses code from the Java MapFragment source code: https://github.com/commonsguy/cw-omnibus/blob/master/Maps/NooYawkFragments/src/com/commonsware/android/mapfrags/MapFragment.java
Maps can not be added to Fragments as is, they need a hosting environment.
Here's the solution for a MapFragment:
namespace BahaiResearch.com
{
public class MyMapFragment : Fragment
{
// FROM http://stackoverflow.com/questions/5109336/mapview-in-a-fragment-honeycomb
private static String KEY_STATE_BUNDLE = "localActivityManagerState";
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Bundle state = null;
if (savedInstanceState != null) {
state = savedInstanceState.GetBundle(KEY_STATE_BUNDLE);
}
mLocalActivityManager = new LocalActivityManager(Activity, true);
mLocalActivityManager.DispatchCreate(state);
}
public override Android.Views.View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
//This is where you specify you activity class
Intent i = new Intent(Activity, typeof(SteamLocationMapActivity));
Window w = mLocalActivityManager.StartActivity("tag", i);
View currentView=w.DecorView;
currentView.Visibility = ViewStates.Visible;
currentView.FocusableInTouchMode = true;
((ViewGroup) currentView).DescendantFocusability = DescendantFocusability.AfterDescendants;
return currentView;
}
private LocalActivityManager mLocalActivityManager;
protected LocalActivityManager GetLocalActivityManager() {
return mLocalActivityManager;
}
public override void OnSaveInstanceState(Bundle outState)
{
base.OnSaveInstanceState(outState);
outState.PutBundle(KEY_STATE_BUNDLE,mLocalActivityManager.SaveInstanceState());
}
public override void OnResume()
{
base.OnResume();
mLocalActivityManager.DispatchResume();
}
public override void OnPause()
{
base.OnPause();
mLocalActivityManager.DispatchPause(Activity.IsFinishing);
}
public override void OnStop()
{
base.OnStop();
mLocalActivityManager.DispatchStop();
}
}
}