The layout of my app contains a TextView and a toggle Button. When the toggle Button is turned ON an AlertDialog appears and the user is prompted to give the time for the countdown to start. It works fine if I dont change the orientation while it counts down. However when I change orientation while the countdown keeps running the Dialog Box reappears which shouldn't. I know that changing orientation destroys and recreates my activity so given the fact that toggle button was ON before the activty is destroyed when it is recreated it continuous to be ON as it should be. So my question is if there is a way for the AlertDialog not to appear after the orientation change.
I have tried adding the following but it didnt work
Declared as class variable
public static final String TOGGLE_BUTTON_STATE = "OFF";
Trying to set the toggle Button to true
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: created.............");
mTextTime = (TextView) findViewById(R.id.textView);
mToggleButton = (ToggleButton) findViewById(R.id.toggleButton);
if((savedInstanceState != null) && TOGGLE_BUTTON_STATE.equals("ON")) {
Log.d(TAG, "onCreate: created after changing orientation........");
mToggleButton.setChecked(true);
}
mToggleButton.setOnCheckedChangeListener(this);
saving the state before it is destroyed
#Override
public void onSaveInstanceState(Bundle outState) {
if(mToggleButton.isChecked()) {
Log.d(TAG, "onSaveInstanceState: toggleButton is checked...........****");
outState.putString(TOGGLE_BUTTON_STATE, "ON");
}else {
Log.d(TAG, "onSaveInstanceState: toggleButton is not checked...........*****");
outState.putString(TOGGLE_BUTTON_STATE, "OFF");
}
super.onSaveInstanceState(outState);
}
//Listener for the ToggleButton
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
// Toast.makeText(this, "ON", Toast.LENGTH_SHORT).show();
// TOGGLE_BUTTON_ON = true;
//getting the xml user_input to java
LayoutInflater inflater = LayoutInflater.from(this);
View view = inflater.inflate(R.layout.user_input, null);
//search inside the view for the text_input
mTextUserInput = (EditText) view.findViewById(R.id.text_input);
//We create the builder and we use it to add functionality to the dialog
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Please Enter The Time");
//We create the user_input that has only the editext widget that we gonna use to get the
//time from the user
builder.setView(view);
builder.setPositiveButton("OK", this);
builder.setNegativeButton("Cancel", this);
builder.show();
} else {
// OFF selected and timer must stop
// TOGGLE_BUTTON_ON = false;
timer.stop();
}
}
ps The countdown timer keeps running properly even after orientation change
Your way of loading the previously stored state in onCreate is false. You are saving the state correctly (but i would prefer storing it as a boolean) - but you are not reading it correctly from the savedInstance.
The way i would do it:
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("TOGGLE_BUTTON_STATE", mToggleButton.isChecked());
}
#Override
protected void onCreate(Bundle savedInstanceState) {
...
if(savedInstanceState != null) {
mToggleButton.setChecked(savedInstanceState.getBoolean("TOGGLE_BUTTON_STATE"));
}
mToggleButton.setOnCheckedChangeListener(this);
...
}
You can dismiss the alert dialog when the activity is going to be destroyed.
For example:
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
...
// Save the dialog in an instance variable
mDialog = builder.show();
}
#Override
public void onStop() {
if (mDialog != null) {
mDialog.dismiss();
}
super.onStop();
}
Related
I am new to android. I am creating a app which uses a toggle button. I want the toggle button to do some tasks when the button is in checked state and do some another tasks when the button is unchecked. And I want the toggle button to retain its state even when the user closes the app(by pressing back switch) and comes back. I managed to get it done by using shared preference, but the problem is that when the user turns the toggle button on and goes back and come back again, the tasks are getting done again. Is there any way to retain my toggle button on state, and not to the tasks associated with it?? And sorry for my bad English :)
public class MainActivity extends AppCompatActivity {
ToggleButton onoff;
public static Bundle bundle=new Bundle();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
onoff = (ToggleButton) findViewById(R.id.toggleButton);
onoff.setChecked(false);
onoff.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
// do some tasks here
} else {
//do some tasks here
}
}
});
}
#Override
public void onPause(){
super.onPause();
bundle.putBoolean("ToggleButtonState", onoff.isChecked());
}
#Override
public void onResume(){
super.onResume();
if(bundle.getBoolean("ToggleButtonState",false))
{
onoff.setChecked(true);
}
}
}``
Simply add another condition to your OnCheckedChangeListener:
onoff.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked && !bundle.getBoolean("ToggleButtonState",false) {
// do some tasks here
} else if(!isChecked){ //optional + , your preference on what to to :)
//do some tasks here
}
}
});
So, when you return, and your button is checked, but your saved boolean is also true, it will not execute your task.
Edit:
For use with onSaveInstanceState :
In your activity, add the following method:
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("ToggleButtonState", onoff.isChecked());
super.onSaveInstanceState(outState);
}
And retrieve this boolean in onCreate(), under findViewById(...):
boolean checkedStatus = savedInstanceState.getBoolean("ToggleButtonState", false);
onoff.setChecked(checkedStatus);
For additional Information visit Recreating an Activity
A similar question has been asked before, but my case is different.
I have DialogFragments all over my app. When I rotate the phone, all of the DialogFragments come back without issue except this one.
I've littered the life cycle callbacks with Log messages to see what is going on, and this is the scenario:
My DialogFragment is created and shown
On rotation, I save whatever I want to into a bundle for restoration afterwards.
DialogFragment is successfully recreated. I know because onCreate through to onResume are called.
Immediately after resumption, for some inexplicable reason, onPause, onStop, onDestroyView, onDestroy and onDetach are called in rapid succession. The DialogFragment is destroyed immediately after recreation and I don't know why.
Any help is much appreciated. The DialogFragment starts an activity for result to take a picture. It works well for most phones, but the Galaxy S3 camera causes orientation changes that force the activity to be recreated. I don't mind this, I know how to handle activity recreation, but this I've never encountered.
The DialogFragment is started via a RecyclerView adapter callback from a regular fragment, in the main hosting activity.
I do not show the DialogFragment using the ChildFragmentManger in the fragment hosting the RecyclerView because multiple fragments can show this DialogFragment and the function is always the same. It was much more prudent to have the activity receive the callback regardless of which fragment started it.
From the fragment:
selectionPickAdapter.setAdapterListener(new selectionPickAdapter.AdapterListener() {
#Override
public void onSelectionClicked(Selection selection) {
if (getActivity() instanceof RankingActivity) {
((RankingActivity) getActivity()).onSelectionClicked(selection);
}
}
});
The main hosting activity receives the call back and shows it thus:
#Override
public void onSelectionClicked(Selection selection) {
if (isSignedInUser) {
selectionsToEdit.put(selection.hashCode(), selection);
if (baseCategory != null) {
selection.setCategory(baseCategory);
}
RankingSelectionEditDialogFragment rankingSelectionEditDialogFragment =
RankingSelectionEditDialogFragment.newInstance(SELECTION_EDIT, selection.hashCode(), selection);
rankingSelectionEditDialogFragment.show(getSupportFragmentManager(), EDIT_TAG);
}
else {
Intent i = new Intent(this, BusinessActivity.class);
i.putExtra(Constants.BUSINESS, selection.getBusiness().getId());
startActivity(i);
}
}
These are my lifecycle callbacks:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
selectionToEdit = savedInstanceState.getParcelable(SELECTION_TO_EDIT);
imagePath = savedInstanceState.getString(IMAGE_PATH);
}
else {
selectionToEdit = getArguments().getParcelable(SELECTION_TO_EDIT);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (savedInstanceState != null) {
Log.i(TAG, "CREATED A SECOND TIME!");
}
else {
Log.i(TAG, "CREATED ONCE!");
}
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_ranking_edit, container, false);
initializeViewComponents(rootView);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setupFragment(selectionToEdit);
}
#Override
public void onResume() {
super.onResume();
Log.i(TAG, "onResume");
Dialog dialog = getDialog();
if (dialog != null) { // Only do this if returning a dialog, not a fragment
Log.i(TAG, "Dialog is not null");
SharedPreferences sharedPreferences
= getActivity().getSharedPreferences(Constants.PREFS, Context.MODE_PRIVATE);
// Get items required to put dialog just under the ActionBar.
int screenWidth = sharedPreferences.getInt(Constants.SCREEN_WIDTH, 720);
int screenHeight = sharedPreferences.getInt(Constants.SCREEN_HEIGHT, 1280);
int screenDPI = sharedPreferences.getInt(Constants.SCREEN_DPI, 320);
Window window = dialog.getWindow();
window.setLayout(screenWidth, WindowManager.LayoutParams.WRAP_CONTENT);
WindowManager.LayoutParams windowLayoutParams = window.getAttributes();
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
windowLayoutParams.y = -((screenHeight / 2) - 56) * (screenDPI / 160);
window.setAttributes(windowLayoutParams);
if (dialog.isShowing()) {
Log.i(TAG, "Dialog is showing");
}
else {
Log.i(TAG, "Dialog is not showing");
}
}
else {
Log.i(TAG, "Dialog is null");
}
Log.i(TAG, "onResume finished");
}
/**
* The system calls this only when creating the layout in a dialog.
*/
#Override
#NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
// The only reason you might override this method when using onCreateView() is
// to modify any dialog characteristics. For example, the dialog includes a
// title by default, but your custom layout might not need it. So here you can
// remove the dialog title, but you must call the superclass to get the Dialog.
SharedPreferences sharedPreferences
= getActivity().getSharedPreferences(Constants.PREFS, Context.MODE_PRIVATE);
// Get items required to put dialog just under the ActionBar.
int screenWidth = sharedPreferences.getInt(Constants.SCREEN_WIDTH, 720);
int screenHeight = sharedPreferences.getInt(Constants.SCREEN_HEIGHT, 1280);
int screenDPI = sharedPreferences.getInt(Constants.SCREEN_DPI, 320);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
Window window = dialog.getWindow();
window.setLayout(screenWidth, WindowManager.LayoutParams.WRAP_CONTENT);
WindowManager.LayoutParams windowLayoutParams = window.getAttributes();
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
windowLayoutParams.y = -((screenHeight / 2) - 56) * (screenDPI / 160);
windowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND;
window.setAttributes(windowLayoutParams);
return dialog;
}
/**
* Restore the previous currentFragment before the dialog was brought up
*/
#Override
public void dismiss() { // Used when the user deliberately dismisses the dialog
Log.i(TAG, "Dismissed");
super.dismiss(); // Ensure Super class method is called
}
/**
* Restore the previous currentFragment before the dialog was brought up
*/
#Override
public void onCancel(DialogInterface dialog) { // Used when the user inadvertently leaves the dialog,
// e.g back pressed or touched outside the dialog
Log.i(TAG, "Cancelled");
super.onCancel(dialog); // Ensure Super class method is called
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(SELECTION_TO_EDIT, selectionToEdit);
outState.putString(IMAGE_PATH, imagePath);
}
#Override
public void onPause() {
Log.i(TAG, "onPause");
super.onPause();
}
#Override
public void onStop() {
Log.i(TAG, "onStop");
super.onStop();
}
#Override
public void onDestroyView() {
Log.i(TAG, "View Destroyed");
super.onDestroyView();
}
#Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
super.onDestroy();
}
#Override
public void onDetach() {
Log.i(TAG, "onDetach");
super.onDetach();
}
EDIT: I've fixed the issue. To show the DialogFragment, I should use the ChildFragmentManager of the hosting fragment and not the activity. That is, changing this:
RankingSelectionEditDialogFragment rankingSelectionEditDialogFragment =
RankingSelectionEditDialogFragment.newInstance(SELECTION_EDIT, selection.hashCode(), selection);
rankingSelectionEditDialogFragment.show(getSupportFragmentManager(), EDIT_TAG);
to this:
RankingSelectionEditDialogFragment rankingSelectionEditDialogFragment =
RankingSelectionEditDialogFragment.newInstance(SELECTION_EDIT, selection.hashCode(), selection);
switch (currentFragment) {
case CATEGORY_PICK:
rankingCategoryPickFragment = (RankingCategoryPickFragment)
getSupportFragmentManager().findFragmentByTag(CATEGORY_PICK_TAG);
if(rankingCategoryPickFragment != null) {
rankingSelectionEditDialogFragment.show
(rankingCategoryPickFragment.getChildFragmentManager(), EDIT_TAG);
}
break;
case BUSINESS_SORT:
rankingBusinessSortParentFragment = (RankingBusinessSortParentFragment)
getSupportFragmentManager().findFragmentByTag(BUSINESS_SORT_TAG);
if(rankingBusinessSortParentFragment != null) {
rankingSelectionEditDialogFragment.show
(rankingBusinessSortParentFragment.getChildFragmentManager(), EDIT_TAG);
}
break;
was the ticket. Hope that helps anybody else with a similar issue.
in the following code work properly and show help screen when open activity but I want show one time forever,
what can i do?
What should I add in the code?
my code:
public class KhatmMain extends Activity implements OnClickListener{
Context ctx;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ctx = this;
setContentView(R.layout.khatmmain);
showOverLay();
.
.
.
}
private void showOverLay(){
final Dialog dialog = new Dialog(ctx, android.R.style.Theme_Translucent_NoTitleBar);
dialog.setContentView(R.layout.overlay_view);
LinearLayout layout = (LinearLayout) dialog.findViewById(R.id.overlayLayout);
layout.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
dialog.dismiss();
}
});
dialog.show();
}
}
You can use SharedPrefereces to set a variable that will check if you've shown the dialog yet to the user or not, here's an example:
SharedPreferences prefs = this.getSharedPreferences("com.you.app", Context.MODE_PRIVATE);
Boolean dialogShown = prefs.getBoolean("dialogShown", false);
Then check if the value of dialogShown is false (you don't need to set it first since it will default to false the way we are calling it), then on the following code we execute some code, only if dialogShown is false, meaning we can do all the dialog stuff inside that conditional:
if(!dialogShown){
//Your show dialog code
prefs.edit().putBoolean("dialogShown",true).commit();
}
So the next time we check for the dialogShown value on the shared preferences it will be true therefor not showing the dialog. I believe this is the most common way of doing it.
There is a solution ..
when application first time start then save the shared preference to the app..
Now each and every time You retrieve the shared preference and check if it is there then move to next screen
Use this code:
public class KhatmMain extends Activity implements OnClickListener{
Context ctx;
Boolean showOneTime = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ctx = this;
setContentView(R.layout.khatmmain);
showOverLay();
.
.
.
}
private void showOverLay(){
if (showOneTime == false) {
return;
}
final Dialog dialog = new Dialog(ctx, android.R.style.Theme_Translucent_NoTitleBar);
dialog.setContentView(R.layout.overlay_view);
LinearLayout layout = (LinearLayout) dialog.findViewById(R.id.overlayLayout);
layout.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
dialog.dismiss();
}
});
dialog.show();
showOneTime = false;
}
}
I have a tabhost with three activities and I want to save the pressed state of the buttons of each activity
So now How can I save the pressed state of each button in all three child activities so that when I move from one activity to the other the button pressed state will be reflected on moving back. first activity -> all 4 buttons pressed -> go to 2nd activity -> come back to first activity -> all buttons in first activity should be in pressed state
When I go to second child tab and come to the first child tab the change(The buttons which I pressed are not in pressed state) is not reflecting
Help is always appreciated , Thanks
this is my code in first tabhost child activity
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
seatdirnbtn.setOnClickListener(listner1);
seatdirnbtn1.setOnClickListener(listner2);
seatdirnbtn.setPressed(true);
seatdirnbtn1.setPressed(true);
this.LoadPreferences();
}
private void SavePreferences() {
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("sharedPreferences",MODE_WORLD_READABLE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean("state", seatdirnbtn.isEnabled());
editor.putBoolean("state1", seatdirnbtn1.isEnabled());
editor.commit();
}
private void LoadPreferences() {
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("sharedPreferences",MODE_WORLD_READABLE);
Boolean state = sharedPreferences.getBoolean("state", false);
Boolean state1 = sharedPreferences.getBoolean("state1", false);
seatdirnbtn.setPressed(state);
seatdirnbtn1.setPressed(state1);
}
#Override
protected void onStart() {
super.onStart();
LoadPreferences();
}
#Override
protected void onPause() {
SavePreferences();
super.onPause();
}
public static boolean isclick = false;
private View.OnClickListener listner1 = new View.OnClickListener() {
public void onClick(View v) {
if (isclick) {
seatdirnbtn.setBackgroundResource(R.drawable.icon4hlt);
} else {
seatdirnbtn.setBackgroundResource(R.drawable.icon4);
}
isclick = !isclick;
}
};
private View.OnClickListener listner2 = new View.OnClickListener() {
public void onClick(View v) {
if (isclick) {
seatdirnbtn1.setBackgroundResource(R.drawable.icon2hlt);
} else {
seatdirnbtn1.setBackgroundResource(R.drawable.icon2);
}
isclick = !isclick;
}
};
probably you should override onResume() method in which you should set buttons states. this method is called after onCreate() and even the activity is already created. If you have activities in tabHost they are not created each time you switch between tabs so onCreate() method will be called only once but onResume() every time you switch to tab with particular activity.
your code which is loading preferences is in onStart() method. Look here on activity lifecycle. You can see that this method is called only if your activity was stopped before but will never called if it was just paused.
EDIT:
if you have just 2 states like in your code from question it could be better to use ToggleButton which also generally have 2 states. You can style it to have different backgrounds for each state. This tutorial could be helpfull.
Than you will have a little bit different Listener:
toggleButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
if(checked) {
//do sth if it's checked
} else {
//do sth if it's not checked;
}
}
});
to change states for them programatically:
toggleButton.setChecked(true); //or false
so finally you can save this state to SharedPreferences:
editor.putBoolean("toggleButton1",toggleButton.isChecked());
and when you will need this state:
boolean isChecked = sharedPreferences.getBoolean("toggleButton1",false);
toggleButton.setChecked(isChecked);
selector will take care of switching button backgrounds for each state.
I have a Login screen which consists of 2 EditTexts for Username and Password. My requirement is that on orientation change , input data(if any) in EditText should remain as it is and a new layout should also be drawn. I have 2 layout xml files- one in layout folder and other in layout-land folder. I am trying to implement following 2 approaches but none of them is perfect:
(1) configChanges:keyboardHidden - In this approach, I don't provide "orientation" in configChanges in manifest file. So I call setContentView() method in both onCreate() and onConfigurationChanged() methods. It fulfills both my requirements. Layout is changed and input data in EditTexts also remains as it is. But it has a big problem :
When user clicks on Login button, a ProgressDialog shows until server-response is received. Now if user rotates the device while ProgressDialog is running, app crashes. It shows an Exception saying "View cannot be attached to Window." I have tried to handle it using onSaveInstanceState (which DOES get called on orientation change) but app still crashes.
(2) configChanges:orientation|keyboardHidden - In this approach, I provide "orientation" in manifest. So now I have 2 scenarios:
(a) If I call setContentView() method in both onCreate() and onConfigurationChanged(), Layout is changed accordingly but EditText data is lost.
(b) If I call setContentView() method in onCreate() , but not in onConfigurationChanged(), then EditText data is not lost but layout also not changes accordingly.
And in this approach, onSaveInstanceState() is not even called.
So I am in a really intimidating situation. Is there any solution to this problem? Please help. Thanx in advance.
By default, Edittext save their own instance when changing orientation.
Be sure that the 2 Edittexts have unique IDs and have the same IDs in both Layouts.
That way, their state should be saved and you can let Android handle the orientation change.
If you are using a fragment, be sure it has a unique ID also and you dont recreate it when recreating the Activity.
A better approach is to let android handle the orientation change. Android will automatically fetch the layout from the correct folder and display it on the screen. All you need to do is to save the input values of the edit texts in the onSaveInsanceState() method and use these saved values to initialize the edit texts in the onCreate() method.
Here is how you can achieve this:
#Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.login_screen);
...
...
String userName, password;
if(savedInstanceState!=null)
{
userName = savedInstanceState.getString("user_name");
password= savedInstanceState.getString("password");
}
if(userName != null)
userNameEdtTxt.setText(userName);
if(password != null)
passEdtTxt.setText(password);
}
>
#Override
protected void onSaveInstanceState (Bundle outState)
{
outState.putString("user_name", userNameEdtTxt.getText().toString());
outState.putString("password", passEdtTxt.getText().toString());
}
Give the element an id and Android will manage it for you.
android:id="#id/anything"
in onConfigurationChanged method, first get the data of both the edit texts in global variables and then call setContentView method. Now set the saved data again into the edit texts.
There are many ways to do this. The simplest is 2(b) in your question. Mention android:configChanges="orientation|keyboardHidden|screenSize" in your manifest so that Activity doesn't get destroyed on Orientation changes.
Call setContentView() in onConfigChange(). but before calling setContentView() get the EditText data into a string and set it back after calling setContentView()
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mEditTextData = mEditText.getText().tostring();//mEditTextData is a String
//member variable
setContentView(R.layout.myLayout);
initializeViews();
}
private void initializeViews(){
mEditText = (EditText)findViewById(R.id.edittext1);
mEdiText.setText(mEditTextData);
}
The following should work and is standard to the activities and fragments
#Override
public void onSaveInstanceState (Bundle outState)
{
outState.putString("editTextData1", editText1.getText().toString());
outState.putString("editTextData2", editText2.getText().toString());
super.onSaveInstanceState(outState);
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate();
... find references to editText1, editText2
if (savedInstanceState != null)
{
editText1.setText(savedInstanceState.getString("editTextData1");
editText2.setText(savedInstanceState.getString("editTextData2");
}
}
Im restoring instance to restore values and it works fine for me :)
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.addtask2);
if(savedInstanceState!=null)
onRestoreInstanceState(savedInstanceState);
}
Remove android:configChanges attribute from the menifest file and let android handle the orientation change your data in edittext will automatically remain.
Now The problem you mentioned is with the progress dialog force close this is because when the orientation is changed the thread running in backgroud is trying to update the older dialog component whihc was visible. You can handle it by closing the dialog on savedinstancestate method and recalling the proceess you want to perform onRestoreInstanceState method.
Below is a sample hope it helps solving your problem:-
public class MyActivity extends Activity {
private static final String TAG = "com.example.handledataorientationchange.MainActivity";
private static ProgressDialog progressDialog;
private static Thread thread;
private static boolean isTaskRunnig;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new EditText.OnClickListener() {
#Override
public void onClick(View v) {
perform();
isTaskRunnig = true;
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void perform() {
Log.d(TAG, "perform");
progressDialog = android.app.ProgressDialog.show(this, null,
"Working, please wait...");
progressDialog
.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
//isTaskRunnig = false;
}
});
thread = new Thread() {
public void run() {
Log.d(TAG, "run");
int result = 0;
try {
// Thread.sleep(5000);
for (int i = 0; i < 20000000; i++) {
}
result = 1;
isTaskRunnig = false;
} catch (Exception e) {
e.printStackTrace();
result = 0;
}
Message msg = new Message();
msg.what = result;
handler.sendMessage(msg);
};
};
thread.start();
}
// handler to update the progress dialgo while the background task is in
// progress
private static Handler handler = new Handler() {
public void handleMessage(Message msg) {
Log.d(TAG, "handleMessage");
int result = msg.what;
if (result == 1) {// if the task is completed successfully
Log.d(TAG, "Task complete");
try {
progressDialog.dismiss();
} catch (Exception e) {
e.printStackTrace();
isTaskRunnig = true;
}
}
}
};
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d(TAG, "onRestoreInstanceState" + isTaskRunnig);
if (isTaskRunnig) {
perform();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(TAG, "onSaveInstanceState");
if (thread.isAlive()) {
thread.interrupt();
Log.d(TAG, thread.isAlive() + "");
progressDialog.dismiss();
}
}
As pointed out by Yalla T it is important to not recreate the fragment. The EditText will not lose its content if the existing fragment is reused.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_frame);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Display the fragment as the main content.
// Do not do this. It will recreate the fragment on orientation change!
// getSupportFragmentManager().beginTransaction().replace(android.R.id.content, new Fragment_Places()).commit();
// Instead do this
String fragTag = "fragUniqueName";
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = (Fragment) fm.findFragmentByTag(fragTag);
if (fragment == null)
fragment = new Fragment_XXX(); // Here your fragment
FragmentTransaction ft = fm.beginTransaction();
// ft.setCustomAnimations(R.xml.anim_slide_in_from_right, R.xml.anim_slide_out_left,
// R.xml.anim_slide_in_from_left, R.xml.anim_slide_out_right);
ft.replace(android.R.id.content, fragment, fragTag);
// ft.addToBackStack(null); // Depends on what you want to do with your back button
ft.commit();
}
Saving state = Saving (Fragment State + Activity State)
When it comes to saving the state of a Fragment during orientation change, I usually do this way.
1) Fragment State:
Save and Restore EditText value
// Saving State
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("USER_NAME", username.getText().toString());
outState.putString("PASSWORD", password.getText().toString());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.user_name_fragment, parent, false);
username = (EditText) view.findViewById(R.id.username);
password = (EditText) view.findViewById(R.id.password);
// Retriving value
if (savedInstanceState != null) {
username.setText(savedInstanceState.getString("USER_NAME"));
password.setText(savedInstanceState.getString("PASSWORD"));
}
return view;
}
2) Activity State::
Create a new Instance when the activity launches for the first time
else find the old fragment using a TAG and the FragmentManager
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
fragmentManager = getSupportFragmentManager();
if(savedInstanceState==null) {
userFragment = UserNameFragment.newInstance();
fragmentManager.beginTransaction().add(R.id.profile, userFragment, "TAG").commit();
}
else {
userFragment = fragmentManager.findFragmentByTag("TAG");
}
}
You can see the the full working code HERE
Below code is work for me. Need to care two things.
Each Input Field (Edit Text or TextInputEditText) assign unique id.
Manifest activity declaration should have on configuration change attribute with below values.
android:configChanges="orientation|keyboardHidden|screenSize"
Sample activity declaration in manifest.
<activity
android:name=".screens.register.RegisterActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:exported="true"
android:label="Registration"
android:theme="#style/AppTheme.NoActionBar" />
Sample declaration of
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/inputLayout"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:boxCornerRadiusBottomEnd="#dimen/boxCornerRadiusDP"
app:boxCornerRadiusBottomStart="#dimen/boxCornerRadiusDP"
app:boxCornerRadiusTopEnd="#dimen/boxCornerRadiusDP"
app:boxCornerRadiusTopStart="#dimen/boxCornerRadiusDP">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/inputEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:fontFamily="#font/proxima_nova_semi_bold"
android:inputType="textCapWords"
android:lines="1"
android:textColor="#color/colorInputText"
android:textColorHint="#color/colorInputText" />
</com.google.android.material.textfield.TextInputLayout>
this may help you
if your android:targetSdkVersion="12" or less
android:configChanges="orientation|keyboardHidden">
if your android:targetSdkVersion="13" or more
android:configChanges="orientation|keyboardHidden|screenSize">