EditText not automatically saved on screen orientation change - android

I read that Android automatically saves the content of EditText objects when an application is about to be stopped or killed. However, in my app the content of an EditText is lost when screen orientation changes.
Is it normal behaviour? Do I then have to manually save/restore its content with onSaveInstanceState/onRestoreInstanceState? Or is there an easier method to tell Android to save it end restore it?
Edit:
I create the EditText object programmatically, not in XML. This turns out to be related to the problem (see accepted answer below).

This is not normal behavior.
First and foremost, ensure that you have IDs assigned to your EditText controls in the layout XML.
Edit 1: It just needs an ID, period. If you're doing this programmatically, it will lose state unless it has an ID.
So using this as a quick & dirty example:
// Find my layout
LinearLayout mLinearLayout = (LinearLayout) findViewById(R.id.ll1);
// Add a new EditText with default text of "test"
EditText testText = new EditText(this.getApplicationContext());
testText.setText("test");
// This line is the key; without it, any additional text changes will
// be lost on rotation. Try it with and without the setId, text will revert
// to just "test" when you rotate.
testText.setId(100);
// Add your new EditText to the view.
mLinearLayout.addView(testText);
That will solve your problem.
Should that fail, you'll need to save and restore state yourself.
Override onSaveInstanceState like so:
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("textKey", mEditText.getText().toString());
}
And then restore in OnCreate:
public void onCreate(Bundle savedInstanceState) {
if(savedInstanceState != null)
{
mEditText.setText(savedInstanceState.getString("textKey"));
}
}
Also, please don't use android:configChanges="orientation" to try to accomplish this, it's the wrong way to go.

could you use android:freezesText="true" in the xml layout?

The easiest way I found to save an object on onSaveInstanceState is to implement serializable and put in bundle
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("myObj", myObj);
}
where myObj class implements serializable and in onCreate() method
if (savedInstanceState != null && savedInstanceState.getSerializable("myObj") != null) {
myObj = ((MyObj) savedInstanceState.getSerializable("myObj"));
}

One possible cause is that you override onSaveInstanceState but you forget to call the same for super class
super.onSaveInstanceState(outState);
State of all views in activity is auto saved UNLESS you override this functionality. Even if this is obvious, mistakes are possible.

You just need UNIQUE ID for the edit text. Make sure if you dynamically add edit text, chances of having same id can cause not restoring the text.
Same way if you add in xml, use unique id. Hope it will help someone.
FYI: EditText by default having setFreezesText as true

Related

Saving whole instance of an activity

Is there any simple way to save the whole activity instance and restoring it ?
After spending 1 hour of searching all corners of internet, I ended up here. I still don't know how to make this.
Yes, I know how to save current instance using onSaveInstanceState and onRestoreInstanceState
but no one in the internet explained it with a large complex coding like dynamically created views, many textviews and calculations,etc. Everyone explaining this with only one or two textViews and I was like "How someone can create an app with only few TextViews!?!" like below:
onSaveInstanceState()
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.i(TAG, "onSaveInstanceState");
final EditText textBox =
(EditText) findViewById(R.id.editText);
CharSequence userText = textBox.getText();
outState.putCharSequence("savedText", userText);
}
onRestoreInstanceState()
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.i(TAG, "onRestoreInstanceState");
final EditText textBox =
(EditText) findViewById(R.id.editText);
CharSequence userText =
savedInstanceState.getCharSequence("savedText");
textBox.setText(userText);
}
I can totally understand this above method. But What to do if we complete a quite complicated coding and want to save & restore the state I have completed all my complex coding stuff and landed in this problem.
I'm sure there will be a simple way to achieve this. Please understand my problem. Help me.
If I understand correctly, you want to save the current state of the page even the page changes, if this is the case, it can be solved by data binding as follows:
1.enable data binding in Gradle
2. in XML file put your layout into layout tag
<layout>
...// your activity view layout
</layout>
then define it in your activity :
private lateinit var binding: FragmentNameBinding
4.add this expression in onCreate or onCreateView(for fragment)
if (!(::binding.isInitialized)) {
//initialize you layout file and what ever you want
}
//then initialize what you want to not change after the layout
changed and back to it

I can't see my logs in Android Studio logcat

Here's a simple app, I'm trying to create logs in the printToLogs method.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v("Log0","test");
}
public void printToLogs(View view){
TextView menuTextView1 = findViewById(R.id.menu_item_1);
TextView menuTextView2 = findViewById(R.id.menu_item_2);
TextView menuTextView3 = findViewById(R.id.menu_item_3);
String item1 = (String) menuTextView1.getText();
String item2 = (String) menuTextView2.getText();
String item3 = (String) menuTextView3.getText();
Log.v("Log1",item1);
Log.v("Log2",item2);
Log.v("Log3",item3);
}
but logs with the tags Log1, Log2, Log3 are not shown at all in the logcat, what does show up is the Log0 in the onCreate method, but the other ones in printToLogs never show up when I search for them at all. I attempted re-installing the app and restarting logging. That didn't work.
The menu items are: Mango sorbet, Blueberry pie, Chocolate lava cake. And yes, I tried searching for them, and they are not in the logcat either.
If this is your actual code, you aren't even calling printToLogs in the onCreate method. You should be more diligent before posting something simple like this.
Barring a serious runtime environment issue, this problem should be fairly easy to solve.
It seems as if the printToLogs(View view) method is to be executed in response to the user clicking a button. If so, try including the following line in your activity_main.xml if you haven't already:
android:onClick="printToLogs"
This will bind the button on the UI with the printToLogs(View view) method.
If, on the other hand, printToLogs(View view) is intended to be a standalone method (i.e. one that should execute regardless of user input) it should not accept a View as an argument. For your purposes, its parameter list should be completely empty. In other words, the method signature should read:
public void printToLogs()
Also, it should be called within the onCreate(Bundle savedInstances) method. Add the following to the onCreate(Bundle savedInstances) method:
printToLogs();
This will initiate the execution of the method as soon as the app begins to run.
Make sure the logcat filter is set to "Verbose" when testing like so: (img is link since apparently I need 10 rep. to embed images into answers directly)
logcat filter
heyy add your method/function name in your button by using property section or just android:onClick in your xml file and then it will be solved

Android switching to layout-land [duplicate]

This question already has answers here:
Handle screen rotation without losing data - Android
(8 answers)
Closed 6 years ago.
I have activity_main.xml layout file and I created landscape layout file in "layout-land" directory. Obviously both files have the same names.
Landscape and main layouts work good, but when I move my phone to swich layout, all my textViews and editTextes changes to default values.
You have to save your information in a bundle and restore it during OnCreate().
https://developer.android.com/training/basics/activity-lifecycle/recreating.html
Every time you rotate your phone, configuration change happen and a new instance of your activity is created. That's why your Textview and Edittext are set to default values. However, if your views have id's set on them in the xml, then the values set on them will not be lost during a configuration change. If you don't want to set id then another way would be to save your Textview and Edittext values in onSaveInstanceState and restoring them in onRestoreInstanceState. For example to save your textview and edittext values follow the following code:
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("arg1", textview1.getText());
outState.putString("arg2", edittext1.getText().toString());
......
}
To restore the saved values follow following code:
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
textview1.setText(savedInstanceState.getString("arg1"));
edittext1.setText(savedInstanceState.getString("arg2"));
......
}
You can read more about this here: https://inthecheesefactory.com/blog/fragment-state-saving-best-practices/en

Saving state causes app to crash

Log is saying activity cant be paused, and a number format exception, I'm trying to save state of two edit texts that hold numbers,but both can be empty or one can be empty
In my activity there are two edit texts the user can either enter numbers manually and move to the next step or open a calculator to add up some numbers, and set the total to one of the edit texts, i want to save the state so if he needs to fill both edit text using the calculator, the first number he set will still be there when they come back with the second number.
I don't know to deal with this, here is the last bit of code i tried.
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
double length =Double.parseDouble(edtNumber1.getText().toString());
double height = Double.parseDouble(edtNumber2.getText().toString());
outState.putDouble("LENGTH", length);
outState.putDouble("HEIGHT", height);
}
And in onCreate
if (savedInstanceState != null) {
double hght = savedInstanceState.getDouble("LENGTH");
double lnth = savedInstanceState.getDouble("LENGTH");
if (savedInstanceState.containsKey("LENGTH")); {
edtNumber1.setText(Double.toString(lnth));
}
if(savedInstanceState.containsKey("HEIGHT")); {
edtNumber2.setText(Double.toString(hght));
}
}
Try to call super.onSaveInstanceState(outState); at the end of the method and make sure your editText contain numbers.
Thus, change
double hght = savedInstanceState.getDouble("LENGTH");
by
double hght = savedInstanceState.getDouble("HEIGHT");
And delete your ; in if (savedInstanceState.containsKey("LENGTH")); and if (savedInstanceState.containsKey("HEIGHT"));
IT means that one (or both) of the text fields don't have a number. You need to catch that exception around ParseDouble and deal with it somehow (probably by using a default).
You have extraneous semi-colons after your "if" statements, turning them into no-ops and causing the blocks that follow to always be executed.

setTheme function not working on resume

I am trying to use setTheme function which basically set theme based on some DB value but the problem is once I have updated DB with theme to be set,I need to finish() the activity for theme settings to be implemented. code being -
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
settingsDBAdapter = new SettingsDBAdapter(this);
settingsDBAdapter.open();
setSettingsTheme(); <<------THIS LINE WILL SET THEME
setContentView(R.layout.layout_task_manager);
quickAddButton = (Button) findViewById(R.id.QuickAddButtonId);
quickAddTaskText = (EditText) findViewById(R.id.QuickAddEditTextId);
mDBHelper = new TasksDBAdapter(this);
mDBHelper.open();
fillData();
//code to create long press on any list item and calls onCreateContextMenu method
registerForContextMenu(getListView());
registerButtonListenersAndSetDefaultText();
}
public void setSettingsTheme(){
String currentTheme = settingsDBAdapter.fetchThemeSettings("theme");
Log.i(TAG,"settingsDBAdapter + currentTheme-->" + settingsDBAdapter + currentTheme);
//setTheme(R.style.HoloTheme);
if(currentTheme.trim().equalsIgnoreCase("holo")){
Log.i(TAG, "in holo<<<<<<<<");
setTheme(R.style.HoloTheme);
}else if(currentTheme.trim().equalsIgnoreCase("hololight")){
Log.i(TAG, "in hololight<<<<<<<");
setTheme(R.style.HoloLightTheme);
}else{
Log.i(TAG, "iin else<<<<<<<");
setTheme(R.style.HoloTheme);
}
}
I have also tried calling setSettingsTheme() function after overriding onResume() function still of no use.Log.i present in setSettingsTheme() function gives proper value always.
Can anyone please help me in my understanding. Thanks in advance,Kaushik
The documentation for ContextThemeWrapper.setTheme(int) says:
Set the base theme for this context. Note that this should be called
before any views are instantiated in the Context (for example before
calling setContentView(View) or inflate(int, ViewGroup)).
The Theme attributes are read in the Views constructors, so after changing the theme you'll want to recreate the UI. You can call finish() and then startActivity(getIntent()) in your Activity to restart it, or have to code a way to rebuild each and every View object.
Firstly, hat tip to Raffaele for pointing me in the right direction on this.
Also, I know this is an old post, so if there is now a better way to do this please let me know.
Anyway...
I ran into a similar issue trying to create a watch face for my Moto360. You can't change the theme instance that is referenced by the View hierarchy, but you can force that instance to take on the attributes of the theme you want to switch to. If you get a reference to your theme and call Resource.Theme.applyStyle(int,boolean), the attributes of the target theme get applied to the theme referenced by your View. After that a call to invalidate the View will update the UI with the new styling.
For example: (Somewhere in your activity ...)
Resources.Theme myTheme = SomeActivity.this.getTheme();
View myThemedView = SomeActivity.this.findViewById(R.id.myRootView);
myTheme.applyStyle(R.style.MyOtherTheme,true);
myThemedView.invalidate();
// Above, "true" clobbers existing styles, "false" preserves them
// and attempts to add in any new attributes.
Again, I did this on a watch face Service on a Moto360 without incident. I have not tried this on an Activity yet.
Resources.Theme.applyStyle(int,boolean)
You can see my code here (BatmanWatchFaceService.java).

Categories

Resources