0

I've been for the most part following the highest highest voted answer Here and a little from some other answers on SO. I'm trying to handle a configuration change or anything that would call onSaveInstanceState() / onRestoreInstanceState(). So far I'm able to get TextViews restored (properly?), but I'm having issues with dynamically added ui elements like ImageButtons, in my example the buttons are not being restored. It's probably something stupid, but I've avoided asking for help long enough. I had seen somewhere mention of saving Objects to bundle.... but this seemed more straight forward. Grateful for any suggestions.

oh also I've only been testing on emulator, rotating between landscape/portrait

EDIT: updated with a working example and suggestion from @18446744073709551615. Thanks everyone for the help, looks like saving entire objects might be a better approach for more complex code.

basic xml layout:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="set"
        android:text="Button" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="add"
        android:text="Button" />

</LinearLayout>

This is just a slightly modified blank activity:

package com.example.savestate;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends Activity {

    private static final String TAG = "MainActivity";
    int btnId = 0;
    int myBtns;
    LinearLayout panel;
    TextView textView;
    String myString;
    ImageButton[] btnArray;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "begin of creation, myString is " + myString);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.textView1);
        Log.d(TAG, "end of creation, myString is: " + myString);

    }

    @Override
    protected void onResume() {
        super.onResume();
        textView.setText(myString);
        restoreBtns();
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putString("MyString", "Welcome back");
        savedInstanceState.putInt("MyBtns", btnId);
        Log.d(TAG, "on save, myString is: " + myString);
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        myString = savedInstanceState.getString("MyString");
        myBtns = savedInstanceState.getInt("MyBtns");

        Log.d(TAG, "on restore, myBtns is: " + myBtns);
        Log.d(TAG, "on restore, myString is: " + myString);

    }

    public void restoreBtns() {
        if(myBtns > 0) {
            panel = (LinearLayout) findViewById(R.id.LinearLayout1);
            btnArray = new ImageButton[myBtns];
            for (int i = 0; i < myBtns; i++){
                btnId++;
                btnArray[i] = new ImageButton(this);
                btnArray[i].setImageResource(R.drawable.ic_launcher);
                btnArray[i].setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                btnArray[i].setId(btnId);
                panel.addView(btnArray[i]);

            }
        }

     }

    public void add(View view) {
        btnId++;
        panel = (LinearLayout) findViewById(R.id.LinearLayout1);
        ImageButton imgBtn = new ImageButton(this);
        imgBtn.setImageResource(R.drawable.ic_launcher);
        imgBtn.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 
        imgBtn.setId(btnId);
        panel.addView(imgBtn);

     }

    public void set(View view) {
        textView.setText("Goodbye");
        Log.d(TAG, "on set(), myString is " + myString);

    }

}
Wojciech Wirzbicki
  • 3,887
  • 6
  • 36
  • 59
ziondreamt
  • 467
  • 1
  • 4
  • 14
  • What is the exact problem? Does the app crash? Aren't the buttons restored properly? – Tim Kranen Nov 18 '13 at 09:33
  • sorry, the buttons do not get restored – ziondreamt Nov 18 '13 at 09:34
  • 1
    You are aware you aren't setting any locations right? Try to debug the application, specifically the restoreBtns() method. If you save the ImageButton entirely (as an object) I think you'd get better results. – Tim Kranen Nov 18 '13 at 09:38
  • er, I was under the impression that in a LinerLayout I wouldn't need to store a location... or am I misunderstanding? I will look into object storage. – ziondreamt Nov 18 '13 at 09:40
  • You're right about the LinearLayout of you don't want to store any margins either etc. It's seems like you don't want that so this is the right approach. You can pass the ImageButton by serializing it. – Tim Kranen Nov 18 '13 at 09:44
  • Sadly it does look like something is wrong with restoreBtns() even if I'm not passing it a variable from the bundle – ziondreamt Nov 18 '13 at 09:49
  • simple way is use android:configChanges in your mainfest.xml – Biraj Zalavadia Nov 18 '13 at 10:10

2 Answers2

1

When onCreate() executes, myBtns is 0. Due to the if statement, restoreBtns() is a no-op. Then, onStart() is called, and after that, onRestoreInstanceState() is called: This method is called after onStart(). So myBtns is initialized only after it is used.

Suggestion: move the button stuff to onResume().

18446744073709551615
  • 16,368
  • 4
  • 94
  • 127
  • I fell asleep shortly after I posted the question, I'll try this suggestion and also edit my question to make it less useless. – ziondreamt Nov 18 '13 at 20:17
  • ok, onResume() works and seems like a clean way to handle this, is there any way i can pass a bundle to it so I can do something like: `if (savedInstanceState != null) { restoreBtns(); textView.setText(myString); }` – ziondreamt Nov 18 '13 at 20:33
  • BTW, please notice the argument: _onCreate(_ ***Bundle savedInstanceState*** _)_. Unless null, this is the bundle from the previous "incarnation". – 18446744073709551615 Nov 19 '13 at 10:29
  • that's what I want though isn't it? if it were null, wouldn't that stop me from using using the data i put into the bundle? – ziondreamt Nov 19 '13 at 20:47
  • If null, it is a fresh start, no previous "incarnation". _Log.d()_ the bundle from _onCreate()_ and you will see it. – 18446744073709551615 Nov 20 '13 at 13:01
0

Try this way

<activity
            android:name="com.yourpackage.YourActivity"
            android:configChanges="keyboardHidden|orientation|screenSize" />
Biraj Zalavadia
  • 28,348
  • 10
  • 61
  • 77