good practice using finish() - android

I'm really new to android and I've created an app that has buttons which lead to other activities where data is selected to be sent back to the main activity by an intent with extras.
When I'm done with the data gathering activity I call the finish() method to return back to my main activity.
The user may wish to revisit the information gathering activity to enter new data but it doesn't matter if the previously entered data is not there when they return to the activity.
is this considered to be good or bad practice when writing an app?
Thanks,
M

Depends on your application.
If your application need a permament data like a options activity or a date enter activity you must to "save" the changes of your activity.
There are a a easy form to do that with the Overryde methods:
/**
* Method onSaveInstanceState.
* #param outState Bundle
*/
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("ISCALLSMS", isOnCallingSms);
super.onSaveInstanceState(outState);
}
/**
* Method onRestoreInstanceState.
* #param savedInstanceState Bundle
*/
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
if ( (savedInstanceState != null) && (savedInstanceState.containsKey("ISCALLSMS")) ){
isOnCallingSms = savedInstanceState.getBoolean("ISCALLSMS");
}
super.onRestoreInstanceState(savedInstanceState);
}
*This are a example of my app. Yoy should decide what data you need to save. There are other methods to save your data, this is only one of them.
In other case, if your app dont need to save data its ok how you finish your activity

Related

Android - Saved Activity/Fragment State Never Clears

I have an Android app, composed of Fragments, that I have saving state correctly. The problem is it works a bit too well ;-). I'll enter some input into a couple of EditText elements that I then save via SharedPrefs in the "onSaveInstanceState()" method, and then hit the "Task Manager" or "Switch App" button on the phone (there's two overlapping rectangles as the icon) and swipe left to close my application. If I then go to the App Drawer and re-run the application, that saved input will still be there. I am clearing the saved instance state in the "onDestroy()" method too, but apparently that is not being called when "closing" the app from that Task Manager (confirmed via logging).
Any suggestions here? Other apps I have do not exhibit this behavior. I'd like for the saved input to be cleared when a user closes the app via Task Manager as well as probably after a set amount of time. Any ideas of what the standard practice for state handling is here?
I tested some apps I have and noticed the default Contacts app actually saves a new contact if you start a new one and switch to another app before explicitly saving. I guess I could do this but I'd rather not.
Below is some relevant code for a particular Fragment; thank you very much in advance for any assistance.
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
Log.v(Tag, "onSaveInstanceState()");
saveInstanceState();
}
#Override
public void onResume() {
super.onResume();
Log.v(Tag, "onResume()");
restoreInstanceState();
}
#Override
public void onDestroy() {
super.onDestroy();
Log.v(Tag, "onDestroy()");
clearInstanceState();
}
private void saveInstanceState() {
Log.v(Tag, "saveInstanceState()");
// get entered data
String name = mTxtName.getText().toString();
String notes = mTxtNotes.getText().toString();
// save data in Shared Prefs
PreferenceManager.getDefaultSharedPreferences(mContext)
.edit()
.putInt(KeyAmmunitionId, mAmmunitionId)
.putString(KeyName, name)
.putString(KeyNotes, notes)
.putString(StringUtils.CurrentFragmentKey, Tag)
.commit();
}
private void restoreInstanceState() {
Log.v(Tag, "restoreInstanceState()");
mTxtName = (EditText)getActivity().findViewById(R.id.frag_manage_ammunition_txtName);
mTxtNotes = (EditText)getActivity().findViewById(R.id.frag_manage_ammunition_txtNotes);
if (PreferenceManager.getDefaultSharedPreferences(mContext).contains(KeyName)) {
String ammunitionName = PreferenceManager.getDefaultSharedPreferences(mContext).getString(KeyName, StringUtils.EMPTY_STRING);
mTxtName.setText(ammunitionName);
}
if (PreferenceManager.getDefaultSharedPreferences(mContext).contains(KeyNotes)) {
String ammunitionNotes = PreferenceManager.getDefaultSharedPreferences(mContext).getString(KeyNotes, StringUtils.EMPTY_STRING);
mTxtNotes.setText(ammunitionNotes);
}
}
private void clearInstanceState() {
Log.v(Tag, "clearInstanceState()");
PreferenceManager.getDefaultSharedPreferences(mContext)
.edit()
.remove(KeyAmmunitionId)
.remove(KeyName)
.remove(KeyNotes)
.commit();
}
instead of using SharedPrefs, I've found that an internal headless fragment that retains its state is much easier to implement/cleaner.
Inside your fragment class you have this class....
/**
* "Headless" Fragment that retains state information between
* configuration changes.
*/
public class RetainedFragment extends Fragment {
/**
* internal storage to be kept put here
*/
// assuming the only 'view' in the parent fragment is this editText with some string value.
String editTextValue;
public RetainedFragment(){
editTextValue = ""; //init values on first time in.
}
/**
* Hook method called when a new instance of Fragment is
* created.
*
* #param savedInstanceState
* object that contains saved state information.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Ensure the data survives runtime configuration changes.
setRetainInstance(true);
}
// have getter/setter methods
Then in your outer fagment just 'create' the UI based off the values stored in the inner headless fragment.
OR...
You can use the RetainedFragmentManager that we figured out. Its a bit wonky and can be a bit confusing to figure out at first, but its a headless fragment that allows you to store java objects in hashmap-like manner, and they will persist across configuration changes, but won't exist if your app is fully closed, etc.
https://github.com/douglascraigschmidt/POSA-15/blob/master/ex/ImageDownloads/src/vandy/mooc/common/RetainedFragmentManager.java

Returning back to last state in previous activity

I have two activities A and B. When the application starts, activity A is loaded and I load data to it from database.
I can go to activity B without any problems, but when I go back to activity A, the old data are viewed for a moment and the activity is reloaded.
Any idea how to fix this?
Clear all fields before loading data start from DB.loading data from take little time and before this clear previous field.
Here You can put all field as blank..
You need to override onSaveInstanceState(Bundle savedInstanceState) and write the application activity state values you want to change to the Bundle parameter like this:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
/* Save UI state changes to the savedInstanceState.
* This bundle will be passed to onCreate if the process is
* killed and restarted activity
*/
savedInstanceState.putString("YourString", "");
// etc...
// etc...
}
The Bundle is essentially a way of storing a NVP ("Name-Value Pair") map, and it will get passed in to onCreate() and also onRestoreInstanceState() where you'd extract the values like this:
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore UI state from the savedInstanceState.
// This bundle has also been passed to onCreate.
String myString = savedInstanceState.getString("YourString");
}
You would usually use this technique to store instance values for your application (selections, unsaved text) etc.

Android Save Instance State

I have created two activities A and B. In the Activity A, using onSaveInstanceState method I am saving bundle value ex(outState.putString("selectSaveDate", this.CalSelectedDate)) and going to the Activity B. When I hit back button to the Activity A , In the oncreate method the bundle value is null. I am unable to get my saved value in the oncreate method.
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.clear();
Log.i("bundleSave", "tester1" + this.CalSelectedDate);
outState.putString("selectSaveDate", this.CalSelectedDate);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null){
Log.i("todolist", "dsa" + savedInstanceState.getString("selectSaveDate"));
}
}
You only store data in a bundle in the OnSaveInstanceState method to persist data when your activity is destroyed and re-created (such as when rotating the screen or when the android os may decide to kill your activity if it is low on resources). When you launch activity B on top of your currently executing activity A, A is put in to a stopped state (therefore, your A activity is not destroyed). Also, when you come back from onStop, the next method that is called is onStart() (technically onRestart() is called be before onStart() but I find that callback is rarely ever implemented.
In conclusion, if your trying to keep persist data between launching an activity on top of your currently executing activity, you can just store that data in instance variables for that activity. If your trying to persist data between app launches then your going to want to look into storing data in Android's built in sqllite database or Android's SharedPreferences.
You should also obtain a real good understanding of the Activity lifecycle (its tricky but needed to code successfully in android):
http://developer.android.com/training/basics/activity-lifecycle/index.html
please try to Override onSaveInstanceState(Bundle savedInstanceState) and write the application state values you want to change to the Bundle parameter like this:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
// Save UI state changes to the savedInstanceState.
// This bundle will be passed to onCreate if the process is
// killed and restarted.
savedInstanceState.putDouble("myDouble", 1.9);
savedInstanceState.putInt("MyInt", 1);
savedInstanceState.putString("MyString", "How are you");
// etc.
}
it will get passed in to onCreate and also onRestoreInstanceState where you'd extract the values like this:
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore UI state from the savedInstanceState.
// This bundle has also been passed to onCreate.
double myDouble = savedInstanceState.getDouble("myDouble");
int myInt = savedInstanceState.getInt("MyInt");
String myString = savedInstanceState.getString("MyString");
}
or follow activity life cycle for better understanding.

How to use onSavedInstanceState example please

I'm confused when it comes down to saving a state. So I know that onSaveInstanceState(Bundle) is called when the activity is about to be destroyed. But how do you store your information in it and bring it back to its original state in onCreate(Bundle savedInstanceState)? I don't understand how this bundle will restore information. It would be helpful if someone can provide an example.
The Dev guide doesn't do a good job of explaining this.
public class Conversation extends Activity {
private ProgressDialog progDialog;
int typeBar;
TextView text1;
EditText edit;
Button respond;
private String name;
private String textAtView;
private String savedName;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.dorothydialog);
text1 = (TextView)findViewById(R.id.dialog);
edit = (EditText)findViewById(R.id.repsond);
respond = (Button)findViewById(R.id.button01);
if(savedInstanceState != null){
savedInstanceState.get(savedName);
text1.setText(savedName);
}
else{
text1.setText("Hello! What is your name?");
respond.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
name = edit.getText().toString();
text1.setText("Nice to meet you "+ name);
}
});
}
}
#Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putString(savedName, name);
}
}
The Bundle is a container for all the information you want to save. You use the put* functions to insert data into it. Here's a short list (there are more) of put functions you can use to store data in the Bundle.
putString
putBoolean
putByte
putChar
putFloat
putLong
putShort
putParcelable (used for objects but they must implement Parcelable)
In your onCreate function, this Bundle is handed back to the program. The best way to check if the application is being reloaded, or started for the first time is:
if (savedInstanceState != null) {
// Then the application is being reloaded
}
To get the data back out, use the get* functions just like the put* functions. The data is stored as a name-value pair. This is like a hashmap. You provide a key and the value, then when you want the value back, you give the key and the function gets the value. Here's a short example.
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putString("message", "This is my message to be reloaded");
super.onSaveInstanceState(outState);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
String message = savedInstanceState.getString("message");
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
}
Your saved message will be toasted to the screen.
One major note that all new Android developers should know is that any information in Widgets (TextView, Buttons, etc.) will be persisted automatically by Android as long as you assign an ID to them. So that means most of the UI state is taken care of without issue. Only when you need to store other data does this become an issue.
From Android Docs:
The only work required by you is to
provide a unique ID (with the
android:id attribute) for each widget
you want to save its state. If a
widget does not have an ID, then it
cannot save its state
A good information: you don't need to check whether the Bundle object is null into the onCreate() method. Use the onRestoreInstanceState() method, which the system calls after the onStart() method. The system calls onRestoreInstanceState() only if there is a saved state to restore, so you do not need to check whether the Bundle is null
Store information:
static final String PLAYER_SCORE = "playerScore";
static final String PLAYER_LEVEL = "playerLevel";
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt(PLAYER_SCORE, mCurrentScore);
savedInstanceState.putInt(PLAYER_LEVEL, mCurrentLevel);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
If you don't want to restore information in your onCreate-Method:
Here are the examples: Recreating an Activity
Instead of restoring the state during onCreate() you may choose to implement onRestoreInstanceState(), which the system calls after the onStart() method. The system calls onRestoreInstanceState() only if there is a saved state to restore, so you do not need to check whether the Bundle is null
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
mCurrentScore = savedInstanceState.getInt(PLAYER_SCORE);
mCurrentLevel = savedInstanceState.getInt(PLAYER_LEVEL);
}
Basically onSaveInstanceState(Bundle outBundle) will give you a bundle.
When you look at the Bundle class, you will see that you can put lots of different stuff inside it. At the next call of onCreate(), you just get that Bundle back as an argument.
Then you can read your values again and restore your activity.
Lets say you have an activity with an EditText. The user wrote some text inside it.
After that the system calls your onSaveInstanceState().
You read the text from the EditText and write it into the Bundle via Bundle.putString("edit_text_value", theValue).
Now onCreate is called. You check if the supplied bundle is not null. If thats the case,
you can restore your value via Bundle.getString("edit_text_value") and put it back into your EditText.
This is for extra information.
Imagine this scenario
ActivityA launch ActivityB.
ActivityB launch a new ActivityAPrime by
Intent intent = new Intent(getApplicationContext(), ActivityA.class);
startActivity(intent);
ActivityAPrime has no relationship with ActivityA.
In this case the Bundle in ActivityAPrime.onCreate() will be null.
If ActivityA and ActivityAPrime should be the same activity instead of different activities,
ActivityB should call finish() than using startActivity().
If Data Is not Loaded From savedInstanceState use following code.
The problem is url call is not to complete fully so, check if data is loaded then to show the instanceState value.
//suppose data is not Loaded to savedInstanceState at 1st swipe
if (savedInstanceState == null && !mAlreadyLoaded){
mAlreadyLoaded = true;
GetStoryData();//Url Call
} else {
if (listArray != null) { //Data Array From JsonArray(ListArray)
System.out.println("LocalData " + listArray);
view.findViewById(R.id.progressBar).setVisibility(View.GONE);
}else{
GetStoryData();//Url Call
}
}

Saving state between activities

I have 2 activities named FirstActivity.java and SecondActivity.java.
When I click a button in FirstActivity, I call SecondActivity. When I return back from SecondActivity, based on the result, I need to skip some steps in FirstActivity which are performed in its onCreate() method.
Coming back from SecondActivity I used Bundle to put data which I gave as input to Intent. I accessed that data in onCreate() of first activity .
When I start, activity application was crashing showing as NullPointerException in the line where I am accessing data of 2nd activity.
The reason, I think, is when the application is launched for the first time there are no values in the Bundle
So, can anyone help me in sorting out this issue?
You have to implement the onSaveInstanceState(Bundle savedInstanceState) and save the values you would like to save into a Bundle. Implement onRestoreInstanceState(Bundle savedInstanceState) to recover the Bundle and set the data again:
public class MyActivity extends Activity {
/** The boolean I'll save in a bundle when a state change happens */
private boolean mMyBoolean;
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putBoolean("MyBoolean", mMyBoolean);
// ... save more data
super.onSaveInstanceState(savedInstanceState);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mMyBoolean = savedInstanceState.getBoolean("MyBoolean");
// ... recover more data
}
}
Here you will find the usage documentation about the state handling: http://developer.android.com/reference/android/app/Activity.html
Just search for thos methods in the docs :P

Categories

Resources