android.widget.Swtich - Keep state on pause? - java

I am a new developer writing an app that logs location when a switch is toggled. My switch works when I toggle it, but it loses it's state when I take the app out of the forefront. How do I keep the state of my android switch onPause and onResume?
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
// set view, initiate switch
Switch mainSwitch = (Switch) findViewById(R.id.mainSwitch);
// deal with switch
mainSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#SuppressLint("MissingPermission")
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// if switch is on
if (isChecked) {
logLocation();
}
} else if (!isChecked) {
stopLocation();
}
// true if the switch is in the On position
Log.v("#############=", "" + isChecked);
}
});
}

Adding an answer instead of continuing in the comments.
By default Android will save the state of your UI if and only if you're using default components (meaning TextView, Button, Switch etc.) and your component has an id. This state will only survive if the OS kills the app and the user returns to it. This means that if the user presses the Home button and then returns to your Activity at a later stage, the UI state of all default components of that specific Activity will be restored. When pressing the Home button the Activity is stopped and onSaveInstanceState is called, so here you get a chance to save any state that isn't maintained by default components or if you have some data you downloaded for instance that is used to populate your UI components with data.
If the user presses the Back button the app will be killed and any UI state won't be restored per default.
To overcome this, you can use SharedPreferences or any other local storage mechanism to store your UI state to disk basically.
I've added a snippet of code, that shows how you can use the different approaches.
In your case you don't need the onSaveInstanceState method implementation, as you have a default UI component, that knows how to save its own state already and as mentioned Android does this automagically for you already.
Both states (savedInstanceState and what goes into the SharedPreferences) should be restored in the onCreate method as this is always called whenever an Activity is re-created or created the first time, while onRestoreInstanceState might not be called all the time.
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getName();
private static final String CHECKBOX__STATE = "CHECKBOX__SAVE_STATE";
private Switch checkbox;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkbox = findViewById(R.id.checkbox);
final boolean isChecked;
if (savedInstanceState != null) {
isChecked = savedInstanceState.getBoolean(CHECKBOX__STATE);
} else {
isChecked = PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(CHECKBOX__STATE, false);
}
// Setting the state (if any) of the Switch.
checkbox.setChecked(isChecked);
checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
Log.d(TAG, "onCheckedChanged: isChecked = true - log location");
} else {
Log.d(TAG, "onCheckedChanged: isChecked = false - stop logging location");
}
}
});
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(CHECKBOX__STATE, checkbox.isChecked());
}
#Override
protected void onDestroy() {
super.onDestroy();
PreferenceManager.getDefaultSharedPreferences(this)
.edit()
.putBoolean(CHECKBOX__STATE, checkbox.isChecked())
.apply();
}
}
I hope this helps :-)

Related

Android - default dark mode

I want to implement in my app Dark mode. In default I wish it been following by the system, so in Main Activity I've placed:
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
It works fine, but I if user wants to change its mind and select certain option in my app menu to toggle off/on dark mode, activity is restarting and app's still following system rules. How can I change that?
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_color_mode) {
if(AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
else
AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_YES);
return true;
}
Code responsible for option you mentioned, is within onCreate(). Mechanism that allows user to change mode is not within onCreate()
public class MainActivityextends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
}
}
When you explicitly change the dark mode, Android recreates the activity and hence calls onCreate again.
So, after you change the dark mode you won't notice a change, as AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM is called again when onCreate is called by the system.
To make this works you can save a value into SharedPreference that can be checked in onCreate before setting the system dark mode.
This can be a boolean that you can toggle when you want to manually change the dark mode.
Here is a sample
public class MainActivityextends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean isSystem = prefs.getBoolean("IS_SYSTEM", true);
if (isSystem) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_color_mode) {
if(AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
else
AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_YES);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.edit().putBoolean("IS_SYSTEM", false).apply();
return true;
}
}
UPDATE
that works perfect, but when I quit application and then launch again, default system mode is active although I've switched it. Is possible here to make it works in that way?
You can use another SharedPreference boolean to be saved permanently
public class MainActivityextends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean isSystem = prefs.getBoolean("IS_SYSTEM", true);
boolean isNight = prefs.getBoolean("IS_NIGHT", false);
if (isSystem) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
} else if (isNight) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_color_mode) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
prefs.edit().putBoolean("IS_NIGHT", false).apply();
} else {
AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_YES);
prefs.edit().putBoolean("IS_NIGHT", true).apply();
}
prefs.edit().putBoolean("IS_SYSTEM", false).apply();
return true;
}
}

Want to open landscape links inside my android webview website by single click instead of two clicks

I am trying to make an android app from my website using webview such that I want a certain links in my website to open in landscape mode and others in portrait mode inside my webview. For this purpose, I have implemented below code inside the overridden function shouldOverrideUrlLoading which does the work, but not up to the mark. What this code does is, on clicking the landscape links the first time, it changes orientation of the present page to landscape mode but does not go to the website link and if I click it a second time when the current page is already in landscape mode, then it goes to the website link in landscape mode. This does the work, but it is very irritating because the link positions get changed in landscape mode and user will have to again search the link by scrolling and if the user clicks a portrait mode link during the second time, the present page turns to portrait mode but does not go to the website link. In short, the activity restarts due to orientation change, but the weird thing is this happens irrespective of the order of loadUrl and setRequestedOrientation functions and makes no difference on placing sleep ( for say 5 seconds ) before or after setRequestedOrientation, in either cases it sleeps ( for say 5 seconds ) first and then changes the orientation on first click and on second click, it sleeps first ( for say 5 seconds ) and then loads the url link and I am unable to understand the reason behind this strange behaviour ( Same feeling which quantum mechanics scientists experience ). I have tried everything like giving below code in AndroidManifest file :
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
And also tried overriding below functions in MainActivity file :
#Override
protected void onSaveInstanceState(Bundle outState )
{
super.onSaveInstanceState(outState);
mywebView.saveState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
mywebView.restoreState(savedInstanceState);
}
#Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
}
Experts please help in resolving this orientation change on first click only.
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
/* try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
if(url.contains("<<some keywords>>")){
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
else{
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
return true;
}
Please try this code ! i have implemented shouldOverrideUrlLoading,onPageStarted ,onPageFinished .Screen Orientation is changed in onPageStarted if any condition satisfy .
public class WebViewActivity extends AppCompatActivity
{
private WebView mywebView;
private ProgressBar myprogressBar;
private static final String TAG = "WebViewActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web_view);
myprogressBar = findViewById(R.id.myProgressBar);
myprogressBar.setVisibility(View.GONE);
mywebView = findViewById(R.id.myWebView);
mywebView.getSettings().setLoadsImagesAutomatically(true);
mywebView.getSettings().setJavaScriptEnabled(true);
mywebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
mywebView.setWebViewClient(new MyBrowser());
mywebView.loadUrl("https://stackoverflow.com/");
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mywebView.saveState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mywebView.restoreState(savedInstanceState);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
private class MyBrowser extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.d(TAG, "shouldOverrideUrlLoading: loading ");
myprogressBar.setVisibility(View.VISIBLE);
view.loadUrl(url);
return true;
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon)
{
Log.d(TAG, "onPageStarted: started");
myprogressBar.setVisibility(View.VISIBLE);
/*
here you have to include the your keywords instead of tags [hardcoded string]
*/
if (url.contains("tags")) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
super.onPageStarted(view, url, favicon);
}
#Override
public void onPageFinished(WebView view, String url) {
myprogressBar.setVisibility(View.GONE);
Log.d(TAG, "onPageFinished: finished");
super.onPageFinished(view, url);
}
}
}

How to save a Button drawable when rotating screen

I just read this: Saving Android Activity state using Save Instance State
this: Android - Open resource from #drawable String
My situation is: I have a Button background set when pressing it to be green with
button.setBackgroundResource(R.drawable.greenbutton);
How can I store this information with onSaveInstanceState and onRestoreInstanceState?
I tried: How to maintain a button style and click state after screen rotation? and worked but maybe there is something better than a three-nested-if-conditionals procedure? I mean I have to do this for 4+ Button and I think it a lot of work for just a simple cause :)
Thank you
EDIT: this is the code so far
package com.example.android.testbutton;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.change);
}
Button button;
Boolean click;
public void changeColor(View view) {
click = true;
button.setBackgroundResource(R.drawable.greenbutton);
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save UI state changes to the savedInstanceState.
// This bundle will be passed to onCreate if the process is
// killed and restarted.
savedInstanceState.putBoolean("buttonClicked", click);
// etc.
super.onSaveInstanceState(savedInstanceState);
}
//onRestoreInstanceState
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore UI state from the savedInstanceState.
// This bundle has also been passed to onCreate.
Boolean firstAnswer = savedInstanceState.getBoolean("buttonClicked");
{
if (savedInstanceState != null) {
if (savedInstanceState.containsKey("buttonClicked")) {
if (savedInstanceState.getBoolean("buttonClicked"))
button.setBackgroundResource(R.drawable.greenbutton);
//some codes to make the button becomes clicked.
}
}
}
}
}
set a variable on your activity too, and then save that and restore it with your state.
public class MyActivity extends Activity {
public static final String KEY_BUTTON_IS_GREEN = "isGreen";
boolean buttonIsGreen;
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean(KEY_BUTTON_IS_GREEN, buttonIsGreen);
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
buttonIsGreen = savedInstanceState.getBoolean(KEY_BUTTON_IS_GREEN, false);
if (buttonIsGreen){
// find the button and set it green.
}
}
you'll need to add to your method that sets the button green and also set your variable = true if the button is green.
You have a few options:
You can set specific flags in AndroidManifest file:
<activity name= ".YourActivity" android:configChanges="orientation|screenSize"/>
It does not work by default because , when you change the orientation onCreate will be called again and it redraws your view. But If you set these flags and you are using a different layout for landscape mode, by adding these parameters the layout for landscape mode will not be called, because onCreate will not be called second time.
You can save int resources by:
int colorFirst = answerOne.getHighlightColor();
savedInstanceState.putInt("key", colorFirst);

CharSequence Restarts After Orientation Change

I have a CharSequence which displays a sequence of text after each imageview click however the CharSequence seems to restart if the orientation is changed mid sequence.
Does anyone know how this can be resolved?
On an orientation change the activity is restarted, and the inCreate() is called again. You have to take that in consideration.
A small example of how to store and retrieve a value:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
isStarted = savedInstanceState.getBoolean("isStarted");
}
}
#Override
protected void onResume() {
isStarted = true;
super.onResume();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("isStarted", isStarted);
super.onSaveInstanceState(outState);
}
For more information and methods: Saving Android Activity state using Save Instance State
using android:configChanges="orientation|keyboardHidden|screenSize"> resolved the issue

New Preferences not loading when back button is pressed

I have this preferences class (below) that saves two ListPreferences, but if the ListPreferences are changed and the back button is pressed, the changes don't take affect unless the application is restarted. Did I miss something? Have been looking everywhere, but just can't seem to find an answer the fits or works. Please help.
public class Preferences extends PreferenceActivity {
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onResume() {
super.onResume();
}
}
Application Code
public class Quotes extends Activity implements OnClickListener {
ProgressDialog dialog;
private WebView webview;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
String q = SP.getString("appViewType","http://www.google.com");
String c = SP.getString("appRefreshRate","20");
webview = (WebView) findViewById(R.id.scroll);
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebViewClient(new QuotesWebView(this));
webview.loadUrl(q);
ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
timer.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
webview.reload();
}
}, 10, Long.parseLong(c),TimeUnit.SECONDS);
findViewById(R.id.refresh).setOnClickListener(this);
}
#Override
public void onPause(){
super.onPause();
}
#Override
public void onResume(){
super.onResume();
}
public void onClick(View v){
switch(v.getId()){
case R.id.refresh:
webview.reload();
break;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
MenuItem about = menu.getItem(0);
about.setIntent(new Intent(this, About.class));
MenuItem preferences = menu.getItem(1);
preferences.setIntent(new Intent(this, Preferences.class));
return true;
}
}
You need to somehow reload your preferences when the preferences activity finishes. I thought Dirol's suggestion of loading them in onResume() instead of onCreate() was excellent; have you tried it? Or am I misunderstanding the problem as well.
In my own case, I launched the preferences activity with startActivityForResult() and then on the activity result callback, I reloaded the preferences.
Code snippets:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_PREFERENCES:
Intent intent = new Intent().setClass(this, CalcPreferences.class);
startActivityForResult(intent, MENU_PREFERENCES);
break;
default: return super.onOptionsItemSelected(item);
}
return true;
}
#Override
protected void onActivityResult(int req, int result, Intent data) {
switch( req ) {
case MENU_PREFERENCES:
SharedPreferences sp =
PreferenceManager.getDefaultSharedPreferences(this);
updatePreferences(sp);
break;
default:
super.onActivityResult(req, result, data);
break;
}
}
#Override
protected void updatePreferences(SharedPreferences sp) {
super.updatePreferences(sp);
keyclick = sp.getBoolean("keyclick", keyclick);
}
Anyway, this is what works for me. I may try moving my updatePreferences() call to onResume() myself to see if that works too.
Try overriding the onBackPressed() method.
If your "Up" button (top left <-) provides the correct result, then you can set the Back button to behave like the Up button.
#Override
public void onBackPressed() {
super.onBackPressed();
NavUtils.navigateUpFromSameTask(this);
}
You load preferences only on onCreate() method. That method called only when a fresh activity starts up. The addPreferencesFromResource inflates the xml file into the preferences, so you only get the info, which is already has been stored in the xml at the moment addPreferencesFromResource was called, not after.
Try to move that method to onResume. But watch for the memory leak. I don't know exactly what the addPreferencesFromResource do, but from the documentation - I would be very suspicious about that method activity.
I had the same problem and solved it as follows:
The main activity class implements OnSharedPreferenceChangeListener:
public class Activity_name extends Activity implements OnSharedPreferenceChangeListener {
...
}
Inside the main activity class the onSharedPreferenceChanged is run whenever a preference entry changes. I simply update all my variables from the preferences as i did in onCreate:
#Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
<read all preferences as you did in onCreate()>
}
This does the trick and I hope it saves you some time in searching for a solution.
I've had the same problem...
Try to create preference instance and load its data in every class and every activity where you need it.
It worked for me...Hope it helps.
You will need to reload your view or whatever object which uses those preferences, preferably when preference activity closes.
Preference activities do not change nothing but an internal file with your preferences(key=value list). When it is changed, preferenceActivity calls onPreferenceChaged() and nothing more. It doesn't refresh your stuff by itself. You need to reload prefs and to reuse them in onResume() method or equivalent.

Categories