Best way to backup user's inputs dealing with orientation changes - android

I am developing a simple apps that allow users to post articles on a website.
It's just a simple form with inputs for title et text and a send button.
To do this, I used a FragmentActivity with a Fragment called ArticleFragment inside.
I've read everywhere that the best way to save user's inputs was to override onPause() in the fragment, and to restore them in the onCreateView().
#Override
public void onPause() {
Log.i(TAG, "Pausing fragment");
Log.i(TAG, "Saving edits");
// Sauvegarde des saisies
EditText titreEdit = (EditText) getActivity().findViewById(R.id.titre_saisie);
EditText texteEdit = (EditText) getActivity().findViewById(R.id.texte_saisie);
String titre = titreEdit.getText().toString();
String texte = texteEdit.getText().toString();
SharedPreferences settings = getActivity().getPreferences(0);
Editor editor = settings.edit();
editor.putString("titre", titre);
editor.putString("texte", texte);
editor.commit();
Toast toast = Toast.makeText(getActivity(), R.string.article_enregistre, Toast.LENGTH_SHORT);
toast.show();
super.onPause();
}
As you can see, each time the activity is paused, a Toast is shown to inform the user that inputs have been saved.
That's what I wanted. But whenever the user changes the orientation of the screen, the popup is shown again (because Activity is paused, then destroyed) and this may annoye the user.
I tried to add android:configChanges="orientation" in the Manifest, but I think this is not the best way to deal with this issue.
I also tried to make a solution with onSaveInstance() but I do not understand how it works : sometimes onSavedInstance is null, sometimes not.
With all this, the main question is what is the best way to save user inputs, with orientation changes and back button, and where to restore what was saved.
Thank you!

Check if input values are empty in onBackPressed() and onClick of whatever button that takes the user to Home and display appropriate Toast message

Add android:configChanges="orientation"to manifest file.
Override onConfigurationChanged. Before you call super.onConfigurationChanged save the data.
If you have different layout files for portrait and landscape you have to remove all the views and setcontentview and initialize them(just like what you do on create ) after all these you can restore the data

I don't quite follow your logic. Lets see ... You have two edittext fields and save button, when user changes screen orientation on destroy you can save input in shared preferences or in Bundle and when onCreate() starts you can check if values are not empty and then show toast that there is a draft. If user hits back button you can also save input and display toast, if he/she hits send you just send input, right ?

Related

Saving Entire Activity State

I have an Android app, that allows the user to dynamically add their own buttons to the layout. I need to make it so that once the app is closed and re-opened, this dynamically added button returns to the layout. Instead of loading the default layout.
Currently, I'm dynamically adding buttons through the ActionBar of the App:
if (id == R.id.add_button)
{
String string = "Adding Button in Progress";
Toast.makeText(getApplicationContext(), string, Toast.LENGTH_SHORT).show( );
Button myButton = new Button(this);
myButton.setText("Button");
RelativeLayout layout = (RelativeLayout)findViewById(R.id.Layout1);
layout.addView(myButton);
//myButton.setVisibility(View.VISIBLE);
return true;
}
This creates the Button fine, however when the app is closed and re-opened, it launches up the default layout.
I've done some research on having the app save and reload the updated layout. It seems that I need to use onSaveInstanceState. Here is what I have so far in terms of trying to save the layout:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the app state here:
savedInstanceState.putAll(savedInstanceState);
super.onSaveInstanceState(savedInstanceState);
}
And here is what I have in terms of trying to "reload/restore" said layout. Notice I'm not using onRestoreInstanceState, instead I'm doing it through the onCreate method:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
//savedInstanceState.get(savedInstanceState);
}
else
{
//initialize members with default values for a new instance
setContentView(R.layout.activity_main);
}
}
I'm not sure if I'm saving/loading correctly, but any advice on how I can accomplish this task would be greatly appreciated.
Thanks for your time!
P.S. I'm still a fairly new member so I couldn't comment/ask questions on existing threads.
I know there's a lot of information out there on trying to load/save layouts, however in my case I need it to save the Button, and not a string of user text. In other words, its not a fixed value that I need to save. If the user adds n buttons, when the app is exited and relaunched, it should have those same 3 buttons.
Saved Instance State is a key-value pair about your activity. The documentation clearly says that it is destroyed when the app is closed .(pressing back button or if the system itself shutsdown the app).This is only useful when you are navigating within the app or changing orientation.
One solution is to create a Shared Preference of the details your application needs to identify the given structure consisting the dynamic contents. The fetch the values whenever you open the app and code according to it.
Other solutions are to use databases or files to store data about your dynamic content.
just store the String or Boolean.. when ever you try to use them in onRestoreInstanceState then create Button or anything dynamically and use stored String or boolean to set text on them

Android SavedPrefrerences loading?

I am trying to make an app(http://pastebin.com/uWkP6XNY) that when you press a button, creates a custom sms message. The user can go to a second activity (http://pastebin.com/MK2NPV5R) thats full of edit-texts that when saved, will bring back strings to be used to change the custom sms.
The issues I am facing is how I initalize my variables with whats in savedpreferences. I put this in my onCreate method.
smsintroduction = (sp.getString("intro", "")); //these are both strings initalized at the top
smsbody = (sp.getString("body", ""));
On start up, since it can't get "intro" from the dictionary, it goes to a null string. I want to be able to use my save() function in my second activity to save, which I Think I already do, but be able to change my two strings above.
I put the code above to set the strings in a method that completes the finalized textbody, but it keeps giving me emptystrings.
The only thing that gets created is "!", as shown in finishedtext().
It looks like in your MainActivity in onCreateOptionsMenu you are overriding the sp member previously set in onCreate with
sp = getSharedPreferences("prefs", 0);
Try removing that line or setting those shared prefs to a different instance member.

"Login" activity: ProgressDialog alternative

I have got an activity where the user can enter host name, user name and password and then click on a "Verify credentials" button. Then the credentials will be checked, which will take some time. In the meantime the user should neither be able to change the credentials nor to click on "Verify" again. So, a modal dialog like the ProgressDialog seems perfect for this.
Unfortunately, ProgressDialog has the well-know limitations regarding orientation changes etc. The guide (UI/Dialogs) tells to avoid ProgressDialog at all and use a ProgressBar in the layout instead (like in Progress & Activity). What does this mean? Shall I create another activity with just one progress bar? Or disable all input fields and put a progress bar on top of it? Sounds quite weird to me... whats your preferred solution?
Best thing which I use is:
Put a ProgressBar just beside the Login Button.
I have put a progressbar beside it(Whose visibility is set to View.GONE) in the OnCreate method.
When the user clicks on the Login/Submit button, I set the visibility of the button to View.GONE and visibility of ProgressBar to View.VISIBLE.
It looks good and the user cannot click on the button until the work is done, If an error occurs, toggle the visibility to let the user try again
Like #micro.pravi mentioned in his answer, you can implement the ProgressBar inside your layout. To keep the state after an orientation change you have to use onSaveInstanceState and onRestoreInstanceState to save and restore important values, i.e. private variables, like the private boolean isChecking
public class MyActivity extends Activity {
public boolean isProcessing;
#Override
public void onCreate(Bundle stateBundle) {
super.onCreate(stateBundle);
// Set Layout
setContentView(R.layout.main);
if(stateBundle!=null) {
// read your data here from the bundle
isProcessing = stateBundle.getBoolean("isProcessing");
}
setUiState(isChecking);
}
#Override
protected void onRestoreInstanceState(Bundle stateBundle) {
// Second value of getBoolean is the default value
isProcessing = stateBundle.getBoolean("isProcessing", false);
super.onRestoreInstanceState(stateBundle);
}
#Override
protected void onSaveInstanceState(Bundle stateBundle) {
// Save the critical data
stateBundle.putString("isProcessing", isProcessing);
super.onSaveInstanceState(stateBundle);
}
#Override
protected onResume() {
setUiState(isProcessing);
}
private setUiState(boolean processing) {
textView.setEnabled(!processing);
button.setEnabled(!processing);
progressbar.setVisibility(processing?View.VISIBLE:View.GONE);
}
}
This should be used to saved any critical data on orientation change or when the App is being killed and later restored by the OS. You don't have to save your TextView data, as the defautl View elements already handle this by themselves. Also do not store Image data this way. Instead store the Uri or path to the Url and load it on restore
For temporarily solving your problem, you can continue using the Progress Dialog and put this line in your Login Activity's tag in Manifest.xml file :
android:configChanges="orientation|keyboardHidden|screenSize"
Using this line of code will not affect the Progress Dialog on orientation changes. But it is considered a wrong practice according to Android Development's Documentation.
In the long run, i recommend you to Preserve the states for orientation changes.

Android - Language change when clicking back

I have this settings section where I allow users to change the languages displayed within the app. When the user chooses a different language, the activity is reloaded so that the change of language can be applied. But the problem is, when the user clicks back right after changing the language, the language shown in the background activity is still the same.
So my question is, what should I do to apply the change of language when I get back to some activity on the background? I suppose I should do something to detect the change in onResume method, but I'm not sure what it is. If you have any suggestions, please let me know.
Thank you.
After several attempts, I have found the solution to my problem. On my onCreate method, I get the SharedPreferences that contains the value of current language, and get the current language:
SharedPrefrences languagepref = getSharedPreferences("language",MODE_PRIVATE);
String language = languagepref.getString("languageToLoad", Locale.getDefault().getDisplayLanguage());
Then, in my onResume method, I assign the value of the above mentioned variable language to a local variable, and update the value of language. Then I compare these two variables - if they are different, I will destroy the current activity and start another:
#Override
public void onResume(){
super.onResume();
String oldLanguage = language;
language = languagepref.getString("languageToLoad", Locale.getDefault().getDisplayLanguage());
if (!oldLanguage.equals(language)){
finish();
startActivity(getIntent());
}
}
And voila, that did the trick!
I would suggest using SharedPreferences. You can store a lang key with the associated value in there and update it when necessary. In your onResume() methods you can get the lang value and then populate views according the value stored.
SharedPreferences sharedPreferences;
sharedPreferences = this.getSharedPreferences("MyActivity", Activity.MODE_PRIVATE);
String lang = sharedPreferences.getString("lang", "en-GB");
SharedPreferences.Editor editor;
editor = sharedPreferences.edit();
editor.putString("lang", "en-US").commit();
That's the basics you need to get going.
Have you tried restarting the Activity after the change is done ?
You can Simply use
finish();
startActivity(getIntent());
to refresh an activity whenever it detects a preference change.
The built in back pressed function does not refresh the code,so do this after u you change the language.
#Override
public void onBackPressed()
{
//new MainActivity();
Intent intent=new Intent(this,MainActivity.class);
startActivity(intent);
}
and in Main Activity class do this
public MainActivity() {
//1- This code is responsible for updating the change of all Strings from a language to another
//it will be called every time this activity is instantiated (da,since it is a constructor) , or when this activity gets
// called by an intent.
//2- Every String inside this Activity(ever fragment inside it ) will also be under the effect of change of language
LocalUtils.updateConfig(this);
}
Please review the following answer and add this to it. To get a full answer written by Roberto.B and LarsH:
Changing Locale within the app itself

How to refresh Activity

Actually in my app i have a button on an listView..now on click of that button i have done some changes..so when i move to previous activity after than this changes should appear on that activity..but in my case the changes occur but not appears after i exit from the activity where my listView Button is present..so how can i do that so that my changes occur immediately after i exit from my first activity..code i have wrritten:
code for ListView Button Onclick:
public boolean stopCycleStage(View v)
{
Button butStop=(Button) findViewById(R.id.butStop);
TextView setStopTxtViewTitle =(TextView)findViewById(R.id.setStopTxtViewTitle);
Date currentDate=new Date();
int iStopStartCount = CycleManager.getSingletonObject().getStopStartCount();
Date dtStopDate = currentDate;
CycleManager.getSingletonObject().setStopStartDate(dtStopDate, iStopStartCount);
Date dtStart = CycleManager.getSingletonObject().getStartDate();
if (dtStopDate.getTime() == dtStart.getTime())
CycleManager.getSingletonObject().removeHistoryDate(dtStart);
butStop.setBackgroundResource(R.drawable.settings_but_disabled);
setStopTxtViewTitle.setTextColor(Color.parseColor("#808080"));
return true;
}
In your first activity, you should refresh the view in the onResume function rather than just in the onStart or onCreate.
Refer to the activity documentation to see the lifecycle of an activity
PS: this is just a guess because you have not given enough code to show how you load the data in your 1st acitvity.
Id use onActivityResult() in the waiting activity, and in there I would redraw the elements that should have changed when you clicked your button in the child activity. In any case, onActivityResult() is the correct way to go unless you are not waiting for any data from child activity, then I'd use onResume().
See http://developer.android.com/reference/android/app/Activity.html#StartingActivities for information on what you should use in your particular situation (you didn't exactly give much information :))

Categories

Resources