Activity reset view on orientation change - android

I have some problems with Android Activity's orientation changes.
I have a game and some flying balloons on it. Balloon (ImageViews) are created dynamically, so they are flying. But when I change device orientation (to port or land) activity is re-creating and my balloons are disappearing. Same thing happens when I move to the next activity and then go back to my balloons activity.
Is there any way to "save" my dynamically created balloons (and it's position and other properties) on my activity
I also tried getLastNonConfigurationInstance() / onRetainNonConfigurationInstance() but it seems to me that it's work with data, not View elements (may be because parent of these views is previous activity)
public class Singleton {
private static final Singleton instance = new Singleton();
private Button btn;
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
public void createBtn(Context context, LinearLayout layout) {
if (btn == null) {
btn = new Button(context);
layout.addView(btn);
}
}
}
public class TestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Singleton s = Singleton.getInstance();
s.createBtn(this, ((LinearLayout) findViewById(R.id.baseLayout)));
}
}
Button will not appear at second onCreate (on change orientation) (I think the problem is that Button's Context is previous Activity)
Updated code:
public class Singleton {
private static final Singleton instance = new Singleton();
private Button btn;
private SparseArray<Parcelable> container;
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
public void createBtn(Context context, LinearLayout layout) {
if (btn == null) {
btn = new Button(context);
layout.addView(btn);
btn.setText("Hello");
saveBtn();
} else if (container != null){
btn = new Button(context);
btn.restoreHierarchyState(container);
layout.addView(btn);
}
}
public void saveBtn() {
container = new SparseArray<Parcelable>();
btn.saveHierarchyState(container);
}
}
I think that on new Button should appear "Hello" text, but it's doesn't happen. Whats wrong?

Override the onSaveInstanceState() callback in your activity. Save all the data to the bundle you receive in this method. In onCreate of your activity check the savedInstance bundle for null. If its not null, read back and apply the data to your views.
Update
Don't check for null in createBtn method.
public void createBtn(Context context, LinearLayout layout) {
btn = new Button(context);
layout.addView(btn);
}
Update 2
Make the container variable static. I think you are losing the values when activity restarts.

You should be fine if you store all your data in onPause() and load it back in onResume().

Try this:
Add this into your activity declaration part in the manifiest.xml file:
android:configChanges="orientation|keyboardHidden"

Related

Android Fragments - Only the original thread that created a view hierarchy can touch its views [duplicate]

This question already has answers here:
Android "Only the original thread that created a view hierarchy can touch its views."
(33 answers)
How do we use runOnUiThread in Android?
(13 answers)
Closed 2 years ago.
this is my main activity:
public class LearnTree extends AppCompatActivity {
private RulesFragment rulesFragment;
private TreeFragment treeFragment;
private PredictionFragment predictionFragment;
TabLayout tabLayout;
ViewPager viewPager;
private Button button;
private static ObjectOutputStream out;
private static ObjectInputStream in;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.learn_tree);
tabLayout=findViewById(R.id.tab_layout);
viewPager= findViewById((R.id.view_pager));
final ViewPagerAdapter viewPagerAdapter= new ViewPagerAdapter(getSupportFragmentManager());
viewPagerAdapter.addFragment(RulesFragment.getInstance(), "TREE RULES");
viewPagerAdapter.addFragment(TreeFragment.getInstance(), "REGRESSION TREE");
viewPagerAdapter.addFragment(PredictionFragment.getInstance(), "PREDICTION");
rulesFragment= (RulesFragment) viewPagerAdapter.getItem(0);
treeFragment= (TreeFragment) viewPagerAdapter.getItem(1);
predictionFragment= (PredictionFragment) viewPagerAdapter.getItem(2);
viewPager.setAdapter(viewPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
LearnTree.PrimeThread p=new LearnTree.PrimeThread();
p.start();
}
private class PrimeThread extends Thread {
public void run() {
out= SocketObject.getOut();
in = SocketObject.getIn();
// print rules
rulesFragment.setText((String)in.readObject());
//print tree
treeFragment.setText((String)in.readObject());
}
}
}
And this is one my 3 fragments, the other 2 are almost the same:
public class RulesFragment extends Fragment {
// Store instance variables
private String title;
private int page;
private TextView rulesView;
public static RulesFragment getInstance() {
RulesFragment rulesFragment = new RulesFragment();
return rulesFragment;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.rules_fragment, container, false);
rulesView= (TextView) view.findViewById(R.id.textview_treerules);
rulesView.setMovementMethod(new ScrollingMovementMethod());
return view;
}
public void setText(String text){
rulesView.setText(text);
}
}
When executing rulesFragment.setText((String)in.readObject()); I get this error: Only the original thread that created a view hierarchy can touch its views
That's because I created the textview in onCreateView but I'm editing it in setText right? The problem is that I need to edit that text multiple times during the program execution and I cannot transfer part of my code in onCreateView (to make it run like a separate thread i guess?) because I need to retrieve input from the Socket sequentially.
Is there another way to do this?
Moreover let's say I have a Spinner in the third fragment and a button "Send". When the user hits Send I'm supposed to reset every textview in each fragment to empty and I need to restart the execution in PrimeThread in LearnTree class. How can I do this? Is there a way to detect the onClick event of send button from the mainactivity?
The previous answer is very complete.
However, you could try by calling the:
Device.BeginInvokeOnMainThread(
() => { lblStatus.Text = "Updating..."; }
);
To answer your main issue, what is happening is that the thread that creates the view is the Main UI thread. For this reason, whenever you want to change something on the UI from a different thread (in your case the PrimeThread), you should execute the functions by using runOnUiThread.
This means in your code you should have:
String rules = (String)in.readObject()
String tree = (String)in.readObject()
requireActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
// print rules
rulesFragment.setText(rules);
//print tree
treeFragment.setText(tree);
}
});
For your last question about having a listener for a button click, you can do it like this:
Button buttonY = (Button)findViewById(R.id.buttonYName);
// Register the onClick listener with the implementation above
buttonY.setOnClickListener(new OnClickListener() {
public void onClick(View v)
{
(LearnTree)getActivity().primeThread.start(); // Assuming this is executed in the context of a Fragment
}
});
If you want to restart the thread in the LearnTree Activity, you need to store the thread in a class variable:
public LearnTree.PrimeThread primeThread;
Or declare it as private and have a getter/setter, it's up to you.
Also, you should create your ViewPagerAdapter like this, otherwise you will get crashes:
public class ViewPagerAdapter extends FragmentPagerAdapter {
public ViewPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
#Override
public Fragment getItem(int position) {
if(position == 0) return new RulesFragment();
if(position == 1) return new TreeFragment();
if(position == 2) return new PredictionFragment();
throw new IllegalStateException("Unexpected position " + position);
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
if(position == 0) return "TREE RULES";
if(position == 1) return "REGRESSION TREE";
if(position == 2) return "PREDICTION";
throw new IllegalStateException("Unexpected position " + position);
}
}
To get a reference to a Fragment created by a ViewPager, use the following findFragmentByTag scheme:
Fragment fragment = supportFragmentManager.findFragmentByTag("android:switcher:" + viewPager.getId() + ":" + fragmentPosition)

Android: Data between Fragments and Activities

I'm trying to pass data between a fragment and an activity and I can't. I get no errors or exceptions. On my fragment I have the vallue and on activity that value is null. I'm using interfaces.
Code of HoroscopeChoice Fragment, which is the fragment with buttons. Each button has a value, which I want to pass to the activity every time I push them.
(...)
static OnInfoChangedListener mCallback;
public HoroscopeChoice() {}
/******************************
* Callback
********/
public static void OnInfoChangedListener(OnInfoChangedListener callback) {
mCallback = callback;
}
public interface OnInfoChangedListener {
public void onInfoChanged(String horosocopo);
}
public View onCreateView(final LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_horoscope_choice,
container, false);
Button aquarius;
aquarius = (Button) view.findViewById(R.id.aquarius1);
final int id = view.getId();
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
String horoscopo = onClick2(v.getId());
Log.d("HoroscopeChoice", "push button->"+horoscopo);
mCallback.onInfoChanged(horoscopo);
}
};
aquarius.setOnClickListener(onClickListener);
public String onClick2(int id)
{
String horoscopo="";
if (id == R.id.aquarius1) {
horoscopo = "Aquarius";
}
}
(...)
Code of the Activity:
(...)
public void onInfoChanged(String horoscopo) {
Log.d("SchedulerActivity","OnInfoChanged na Scheduler->"+horoscope);
mHoroscopeDisplay = (TextView) findViewById(R.id.dailyHoroscope4);
mHoroscopeDisplay.setText(horoscopo);
}
When I do Log.d in the Fragment I get a value, on the Activity I have no value. Does anyone knows what is wrong?
You can do it via interface callbacks, but there is an even easier way with a great third party library called EventBus that is perfect for this kind of thing. You can send any object from one place to the other.
All you need to do is post the Event and create a listener method wherever is needed. Follow their guide, it's very easy.
Don't use a static listener object, especially to store something like an Activity. You should instead make the listener an instance variable. The standard pattern for using interface communication between Fragments and Activities is by using onAttach().
private OnInfoChangedListener mCallback;
#Override
public void onAttach(Activity activity) {
if (!(activity instanceof OnInfoChangedListener)) {
throw new IllegalStateException("Activity must implement OnInfoChangedListener!");
}
mCallback = (OnInfoChangedListener) activity;
}
#Override
public void onDetach() {
mCallback = null;
}

How to save custom ListFragment state with orientation change

I am being more thorough with hope the question will actually be easier to understand.
Activity purpose: allow users to select images from gallery; display thumbnail of image in ListFragment along with title user gave the image; when user is finished save each image's uri and title, and the name user gave this collection of images.
Problem: When device is rotated the FragmentList is losing all the images and titles the user already chose, ie, all the rows of the list are missing.
Attempted problem solving:
Implemented the RetainedFragment to save the List collection on device rotation. Previously I had not done this and figured "Ah, the adapter is fed a blank List collection on creation. I'll save the state of the List and then when Activity's onCreate is called I can feed the retained List to the Adapter constructor and it'll work." But it didn't.
Then I thought, "Of course it is not working, you haven't notified the adapter of the change!" So I put the adapter.notifyDataSetChanged() in the onCreate. This didn't work.
Then I moved the adapter.notifyDataSetChanged() to onStart thinking I might need to notify the adapter later in the activity's lifecycle. Didn't work.
Note: I have another activity in this same app that use this same custom ListViewFragment and the state of the ListFragment is being preserved with device orientation changes. That activity has two principle differences: the fragment is hard coded into the .xml (I don't think that would make a difference, other than perhaps maybe Android's native saving of .xml fragments is different than programmatically added ones); and that activity uses a Loader and LoaderManager and gets its data from a Provider that I built (which gathers data from my SQLite database). Looking at the differences between these two activities is what caused me to think "you're not handling the data feeding the adapter appropriately somehow" and inspired me to use the RetainedFragment to save the List collection when the device is rotated.
...which is prompting me to think about figuring out how to, as Android says on their Loader page about LoaderManager:
"An abstract class associated with an Activity or Fragment for managing one or more Loader instances. This helps an application manage longer-running operations in conjunction with the Activity or Fragment lifecycle; the most common use of this is with a CursorLoader, however applications are free to write their own loaders for loading other types of data."
It is the "loading other types of data" part that has me thinking "Could I use a LoaderManager to load the List data? Two reasons I shy from this: 1) what I have already, at least conceptually, ought to work; 2) what I'm doing currently isn't really a "longer-running operation" at all, I don't think.
Research:
StackOverflow Fool proof way to handle Fragment on orientation change
save state of a fragment.
I think the RetainedFragment I am using saves what needs to be saved.(?)
Once for all, how to correctly save instance state of Fragments in back stack?
Save backstack fragments.
Not shown in my code pasted below, but my activity dynamically creates three other fragments and I use the following if savedInstanceState !=null and those fragments' states are saved without doing any work in onSaveInstanceState() (this is partly why it feels like my problem isn't with doing something in onSaveInstanceState because Android handles the saving my other fragments state so shouldn't it do it, too, with the ListFragment? Seems like it should).
if(savedInstanceState.containsKey(AddActivity_Frag1.F1_TAG)){
frag1 = (AddActivity_Frag1)getFragmentManager().getFragment(savedInstanceState, AddActivity_Frag1.F1_TAG);
}
Understanding Fragment's setRetainInstance(boolean)
Many of the StackOverflow questions surrounding my query seem to be mostly about how to save the scroll position of the ListFragment with orientation change but I don't need to do that (though I did read them looking for tips that might help).
Android Fragments
Android Loaders
Android Caching Bitmaps (RetainFragment stuff)
Activity - with many, hopefully unrelated things, removed:
public class AddActivity extends Activity{
// data collection
List<ImageBean> beanList;
// adapter
AddCollectionAdapter adapter;
// ListViewFragment tag
private static final String LVF_TAG = "list fragment tag";
// fragment handles
ListViewFragment listFrag;
// Handles images; LruCache for bitmapes
ImageHandler imageHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add2);
// Create ImageHandler that holds LruCache
imageHandler = new ImageHandler(this, getFragmentManager());
// Obtain retained List<ImageBean> or create new List<ImageBean>.
RetainedFragment retainFragment = RetainedFragment.findOrCreateRetainFragment(getFragmentManager());
beanList = retainFragment.list;
if(beanList == null){
beanList = new ArrayList<ImageBean>();
retainFragment.list = beanList;
}
// create fragments
if(savedInstanceState == null){
listFrag = new ListViewFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.add_fragFrame, listFrag, LVF_TAG);
ft.commit();
}else{
listFrag = (ListViewFragment)getFragmentManager().findFragmentByTag(LVF_TAG);
}
// create adapter
adapter = new AddCollectionAdapter(this, beanList);
// set list fragment adapter
listFrag.setListAdapter(adapter);
}
#Override
protected void onStart() {
// TESTING: If device orientation has changed List<ImageBean> was saved
// with a RetainedFragment. Seed the adapter with the retained
// List.
adapter.notifyDataSetChanged();
super.onStart();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
// Android automatically saves visible fragments here. (?)
super.onSaveInstanceState(outState);
}
/*
* ImageBean.
*/
public static class ImageBean{
private String collectionName; // Title of image collection
private String imageUri; // Image URI as a string
private String imageTitle; // Title given to image
public ImageBean(String name, String uri, String title){
collectionName = name;
imageUri = uri;
imageTitle = title;
}
public String getCollectionName() {
return collectionName;
}
public String getImageUri() {
return imageUri;
}
public String getImageTitle() {
return imageTitle;
}
}
/*
* Called when user is finished selecting images.
*
* Performs a bulk insert to the Provider.
*/
private void saveToDatabase() {
int arraySize = beanList.size();
final ContentValues[] valuesArray = new ContentValues[arraySize];
ContentValues values;
String imageuri;
String title;
int counter = 0;
for(ImageBean image : beanList){
imageuri = image.getImageUri();
title = image.getImageTitle();
values = new ContentValues();
values.put(CollectionsTable.COL_NAME, nameOfCollection);
values.put(CollectionsTable.COL_IMAGEURI, imageuri);
values.put(CollectionsTable.COL_TITLE, title);
values.put(CollectionsTable.COL_SEQ, counter +1);
valuesArray[counter] = values;
counter++;
}
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... arg0) {
getContentResolver().bulkInsert(CollectionsContentProvider.COLLECTIONS_URI, valuesArray);
return null;
}
#Override
protected void onPostExecute(Void result) {
// End this activity.
finish();
}
};
task.execute();
}
public ImageHandler getImageHandler(){
return imageHandler;
}
}
class RetainedFragment extends Fragment{
private static final String TAG = "RetainedFragment";
// data to retain
public List<AddActivity.ImageBean> list;
public static RetainedFragment findOrCreateRetainFragment(FragmentManager fm){
RetainedFragment fragment = (RetainedFragment)fm.findFragmentByTag(TAG);
if(fragment == null){
fragment = new RetainedFragment();
fm.beginTransaction().add(fragment, TAG);
}
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
}
ListFragment:
public class ListViewFragment extends ListFragment {
ListFragListener listener;
public interface ListFragListener{
public void listFragListener(Cursor cursor);
}
#Override
public void onCreate(Bundle savedInstanceState) {
// Retain this fragment across configuration change
setRetainInstance(true);
super.onCreate(savedInstanceState);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Set listener
if(activity instanceof ListFragListener){
listener = (ListFragListener)activity;
}else{
//Instantiating activity does not implement ListFragListener.
}
}
#Override
public void onListItemClick(ListView listView, View v, int position, long id) {
// no action necessary
}
}
Adapter:
public class AddCollectionAdapter extends BaseAdapter {
// data collection
List<ImageBean> beanList;
// layout inflator
private LayoutInflater inflater;
// context
Context context;
public AddCollectionAdapter(Context context, List<ImageBean> beanList){
this.context = context;
this.beanList = beanList;
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return beanList.size();
}
#Override
public Object getItem(int position) {
return beanList.get(position);
}
#Override
public long getItemId(int arg0) {
// collection not from database nor is going directly to database; this is useless.
return 0;
}
// holder pattern
private class ViewHolder{
ImageView imageView;
TextView titleView;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
View xmlTemplate = convertView;
if(xmlTemplate == null){
//inflate xml
xmlTemplate = inflater.inflate(R.layout.frag_listview_row, null);
// initilaize ViewHolder
holder = new ViewHolder();
// get views that are inside the xml
holder.imageView = (ImageView)xmlTemplate.findViewById(R.id.add_lvrow_image);
holder.titleView = (TextView)xmlTemplate.findViewById(R.id.add_lvrow_title);
// set tag
xmlTemplate.setTag(holder);
}else{
holder = (ViewHolder)xmlTemplate.getTag();
}
// Get image details from List<ImageBean>
ImageBean bean = beanList.get(position);
String imageUri = bean.getImageUri();
String title = bean.getImageTitle();
// Set Holder ImageView bitmap; Use parent activity's ImageHandler to load image into Holder's ImageView.
((AddActivity)context).getImageHandler().loadBitmap(imageUri, holder.imageView, Constants.LISTVIEW_XML_WIDTH, Constants.LISTVIEW_XML_HEIGHT);
// Set Holder's TextView.
holder.titleView.setText(title);
// return view
return xmlTemplate;
}
}
Solved. After putting log statements in strategic places I discovered the RetainedFragment's list was always null. After some head scratching noticed this in RetainedFragment:
fm.beginTransaction().add(fragment, TAG);
I'm missing the commit()!
After I added that the state is being preserved now with configuration changes.
More information related to saving ListFragment state that I discovered during my trials and tribulations:
If you add a fragment via:
if(savedInstanceState == null){
listFrag = new ListViewFragment();
// programmatically add fragment to ViewGroup
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.add_fragFrame, listFrag, LVF_TAG);
}
Then either of these will work in the else:
1) This one works because Android takes care of saving the Fragment:
listFrag = (ListViewFragment)getFragmentManager().findFragmentByTag(LVF_TAG);
2) This one works because the fragment was specifically saved into bundle in
onSaveInstanceState:
listFrag = (ListViewFragment)getFragmentManager().getFragment(savedInstanceState, LVF_TAG);
For number 2 to work, this happens in onSaveInstanceState():
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getFragmentManager().putFragment(outState, LVF_TAG, listFrag);
}

Android - call OnSaveInstanceState from another class than main

I am creating some EditTexts with button, I created a class which implements OnClickListener, and I want to save those EditTexts after screen rotation but they always disappear. I know that
Activity on rotation is destroyed and created again
I cant save EditText in Bundle since it does not implement Parcelable or something like that
So I tried to save at least their ID's and Text they have in them with the onSaveInstanceState(Bundle savedInstanceState)
but it is not called because it is not in main class, but in another called ViewControl. I need to save some private variables (text and ids) so that is the reason why I have this method inside my class. I tried to call this method from another onSaveInstance which is in main but no luck neither. Can you tell me some easy way to programatically create EditTexts one below another and KEEP them after screen rotation? I really cant find any easy way...
Main class
public class MainActivity extends Activity {
private ViewControl vc;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vc = new ViewControl(this);
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
vc.onSaveInstanceState(savedInstanceState);
}
ViewControl class
import java.util.ArrayList;
public class ViewControl extends Activity implements View.OnClickListener{
private Button btn;
private RelativeLayout rl;
private Activity act;
private ArrayList<Integer> id;
private ArrayList<String> userpath;
private int lastId;
public ViewControl(Activity activity) {
this.act = activity;
this.id = new ArrayList<Integer>();
this.userpath = new ArrayList<String>();
this.rl = (RelativeLayout)act.findViewById(R.id.layout);
this.btn = (Button)act.findViewById(R.id.btn);
this.id.add(Integer.valueOf(R.id.btn));
this.btn.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(id.size() != 1)
lastId = id.get(id.size() - 1);
else
lastId = R.id.btn;
RelativeLayout.LayoutParams par = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
par.addRule(RelativeLayout.BELOW, lastId);
EditText et = new EditText(act);
et.setId(++lastId);
id.add(Integer.valueOf(lastId));
et.setText(Integer.toString(lastId));
rl.addView(et, par);
lastId = et.getId();
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putIntegerArrayList("ids", id);
savedInstanceState.putStringArrayList("userpaths", userpath);
savedInstanceState.putInt("lastId", lastId);
Toast.makeText(act, "Onsave", Toast.LENGTH_LONG).show();
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
this.id = savedInstanceState.getIntegerArrayList("ids");
this.userpath = savedInstanceState.getStringArrayList("userpaths");
this.lastId = savedInstanceState.getInt("lastId");
Toast.makeText(act, "Onrestore", Toast.LENGTH_LONG).show();
for(int i = 0; i < id.size(); i++)
{
RelativeLayout.LayoutParams par = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
par.addRule(RelativeLayout.BELOW, lastId);
EditText et = new EditText(act);
et.setId(this.id.get(i));
}
}
}
The calls are in the wrong order (both in MainActivity and ViewControl). First you should add your data, then pass the Bundle to super to save it (see the docs here). (Your onRestoreInstanceState is OK)

Easiest way to save data in savedInstanceState when managing an adapter(viewpager)

I'm working with an adapter(viewpager) and when the app changes orientation it loses its information. Which is the easiest way to conserve this information? I was going to use savedInstanceState inside the adapter but it doesn't recognise it.
Finally, I have done it following the advice of Jofre as he pointed in Activity restart on rotation Android
and looking in http://developer.android.com/intl/es/guide/topics/resources/runtime-changes.html
YOU MUST NOT MODIFY MANIFEST. DON'T ADD android:configChanges
SOLUTION:
//ALL THE VARIABLES YOU NEED TO SAVE IN YOUR ADAPTER PUT THEM AS PUBLIC, IE:
//public int a = 2;
//public String b = "a";
Public class Yourclass extends Activity{
Classofyouradapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.yourlayout);
final Save_object data = (Save_object) getLastNonConfigurationInstance();
adapter = new Classofyouradapter(your variables);
if (data != null) {
fillit(data);
}
myPager = (ViewPager) findViewById(R.id.yourpanelpager);
myPager.setAdapter(adapter);
}
#Override
public Object onRetainNonConfigurationInstance() {
final Save_object data = new Save_object();
return data;
}
public class Save_object{
int a = adapter.a;
String b = adapter.b;
//Rest of variables
}
public void fillit(Save_object data){
adapter.a= data.a;
adapter.b= data.b;
//Rest of variables
}
}

Categories

Resources