简体   繁体   中英

Putting and getting savedInstanceState data

I'm just trying to understand the Activity lifetime with this simple example by trying to find how I get back the SomeIntegers g_values object and the ArrayList AnInteger objects within it.

As it is, it is not of much meaning but will serve as a paradigm of my real situation where initial setup requires the app to schlepp through countless reams of pre-processing eg access and list fonts, analyse all my available games, in the APK, on file and online in my website, players records etc. The final app is a system of games and activities to help SpLD (dyslexia) students of all ages exercise their reading, spelling, organisational skills and short term memory. It is of serious intent. Although free running, it is best used with SpLD supervisors/tutors who can set the work schedule of their charge and even add their own games.

Anyway enough of the irrelevant background.

Can I save my somewhat complex objects using access to the savedInstanceState (somewhat hampered by their being no putxxxxx method of the correct form) or should abandon this approach and recover the data from persistent files or databases? This can be discussed hopefully within the limits of this simple example, the real thing is simply more of the same but with different details.

Note added after. There is also the issue of taking the user/player back to where he/she was when the app experienced the need to save its InstanceState. As the major influence seems to be the orientation of the tablet, I could maybe side step that by locking the orientation at start up. This would simplify many display issues also but is it an "unacceptable" style?

import android.os.Parcelable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class TestBundle extends AppCompatActivity {
    SomeIntegers g_values;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        System.out.println("onCreate (" + (savedInstanceState == null ? "null)" : "set)"));
        if (savedInstanceState == null)
        {   g_values = new SomeIntegers();
            String result = g_values.report();
            System.out.println("Startup Result: " + result);
            setContentView(R.layout.activity_test_bundle); // Where do I put this line?
        }
        else
        {   //Do I get g_values back here?
            //More relevantly, can I, and how can I, put g_values in the
            //savedInstanceState when onSaveInstanceState is called?
            String result = g_values.report();
            System.out.println("Result: " + result);
        }
    }
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        System.out.println("onSaveInstanceState (" + (outState == null ? "null)" : "set)"));
        //How do I add g_values to the Bundle?
    }
    // Following is just stuff to watch the progress of the
    // Activity in the ADB Log. Not of much relevance. Or is it?
    @Override
    protected void onStop() {
        super.onStop();
        System.out.println("onStop()");
    }
    @Override
    protected void onStart() {
        super.onStart();
        System.out.println("onStart()");
    }
    @Override
    protected void onRestart() {
        super.onRestart();
        System.out.println("onRestart()");
    }
    @Override
    protected void onResume() {
        super.onResume();
        System.out.println("onResume()");
    }
    @Override
    protected void onPause() {
        super.onPause();
        System.out.println("onPause()");
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        System.out.println("onDestroy()");
    }
}

public class SomeIntegers {
    private ArrayList<AnInteger> c_values;
    SomeIntegers() {
        c_values = new ArrayList<AnInteger>();
        c_values.add (new AnInteger(1));
        c_values.add (new AnInteger(2));
        c_values.add (new AnInteger(3));
        c_values.add (new AnInteger(4));
        c_values.add (new AnInteger(29));
        c_values.add (new AnInteger(30));
    }
    String report() {
        String g = "";
        for (AnInteger ai  : c_values) {
            if (!g.isEmpty()) g = g + ", ";
            g = g + ai.getC_value();
        }
        return (g.isEmpty() ? "Empty" : g);
    }
}
public class AnInteger {
    private int c_value;
    AnInteger(int value) { c_value = value); }
    public int getC_value () { return c_value; }
}

Thank you. Josie Hill

The concept of restoring the activity states is based on device orientation. So for example if you pull some changes from persisted file, loaded it, when the screen changes it angle of rotation that data will be recreated. So the activity uses a bundle to wrap that data, and permits the user to save the current working state of such file, which then can be restored. Here is a great link . Your requirements sounds consistent as it regards data changes, as per my first question regarding the anticipated file sizes, your requirements sounds relatively small.

To work compound data types and abstract data types , do consider using GSON.which is a Java serialization/deserialization library to convert Java Objects into JSON and back

Therefore I can recommend you using the power of shared preferences in android.If you have a relatively small collection of key-values that you'd like to save, you should use the SharedPreferences APIs. A SharedPreferences object points to a file containing key-value pairs and provides simple methods to read and write them. In simple terms,Shared Preferences allow you to save and retrieve data in the form of key,value pair.

Android provides many ways of storing data of an application. If your requirements needs storage consistency, I would go with the database approach, I would recommend using realm.Realm is a mobile database and a replacement for SQLite. Although is an OO database it has some differences with other databases. Realm is not using SQLite as it's engine. Instead it has own C++ core and aims to provide a mobile-first alternative to SQLite.

Hope this was helpful:)

First make your data models implement Parcelable :

AnInteger:

public class AnInteger implements Parcelable {
    private int c_value;

    public AnInteger(int value) {
        this.c_value = value;
    }

    public int getC_value() {
        return c_value;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.c_value);
    }

    protected AnInteger(Parcel in) {
        this.c_value = in.readInt();
    }

    public static final Parcelable.Creator<AnInteger> CREATOR = new Parcelable.Creator<AnInteger>() {
        @Override
        public AnInteger createFromParcel(Parcel source) {
            return new AnInteger(source);
        }

        @Override
        public AnInteger[] newArray(int size) {
            return new AnInteger[size];
        }
    };
}

SomeIntegers:

public class SomeIntegers implements Parcelable {
    private ArrayList<AnInteger> c_values;

    public SomeIntegers() {
        c_values = new ArrayList<>();
        c_values.add(new AnInteger(1));
        c_values.add(new AnInteger(2));
        c_values.add(new AnInteger(3));
        c_values.add(new AnInteger(4));
        c_values.add(new AnInteger(29));
        c_values.add(new AnInteger(30));
    }

    public String report() {
        String g = "";
        for (AnInteger ai : c_values) {
            if (!g.isEmpty()) {
                g = g + ", ";
            }
            g = g + ai.getC_value();
        }
        return (g.isEmpty() ? "Empty" : g);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeTypedList(this.c_values);
    }

    protected SomeIntegers(Parcel in) {
        this.c_values = in.createTypedArrayList(AnInteger.CREATOR);
    }

    public static final Parcelable.Creator<SomeIntegers> CREATOR = new Parcelable.Creator<SomeIntegers>() {
        @Override
        public SomeIntegers createFromParcel(Parcel source) {
            return new SomeIntegers(source);
        }

        @Override
        public SomeIntegers[] newArray(int size) {
            return new SomeIntegers[size];
        }
    };
}

Then in your activity saving and restoring gets pretty easy, here is an example using your current data model:

//set up class fields/members
private final static String STATE_G_VALS = "STATE_G_VALS";
SomeIntegers g_values = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test_bundle);
    System.out.println("onCreate (" + (savedInstanceState == null ? "null)" : "set)"));
    if (savedInstanceState != null) {
        // get g_values back here
        g_values = savedInstanceState.getParcelable(STATE_G_VALS);
    }

    if (g_values == null) {
        // ok its null, lets make one
        g_values = new SomeIntegers();
    }
    // log some stuff
    String result = g_values.report();
    System.out.println("Result: " + result);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
    //set g_values to the Bundle/saved state (even if it is null)
    outState.putParcelable(STATE_G_VALS, g_values);
    super.onSaveInstanceState(outState);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM