App crashes when changes are made to preferences on resume - android

I'm having an issue with my preference page crashing my app. On the first visit, it acts as expected. But as soon as I revisit the page and try to change a switch, the app crashes. Here's what the XML looks like for my preferences:
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:gravity="left"
android:title="#string/description_title"
app:iconSpaceReserved="false">
<SwitchPreference
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:key="#string/pallet_pref_key"
android:title="#string/pallet_pref"
app:iconSpaceReserved="false" />
<SwitchPreference
android:key="#string/nose_pref_key"
android:title="#string/nose_pref"
app:iconSpaceReserved="false" />
<SwitchPreference
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:key="#string/finish_pref_key"
android:title="#string/finish_pref"
app:iconSpaceReserved="false" />
</PreferenceCategory>
</PreferenceScreen>
The Java looks like this:
import android.os.Bundle;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import androidx.preference.SwitchPreference;
public class SettingsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings_activity);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.settings, new SettingsFragment())
.commit();
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
public static class SettingsFragment extends PreferenceFragmentCompat {
private SharedPreferences sharedPref;
private boolean pNose;
private boolean pPallet;
private boolean pFinish;
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.root_preferences, rootKey);
sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
sharedPref.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
if(s.equals(getResources().getString(R.string.pallet_pref_key))) {
pPallet = sharedPreferences.getBoolean(s,false);
SwitchPreference pNose = findPreference(getResources().getString(R.string.nose_pref_key));
SwitchPreference pFinish = findPreference(getResources().getString(R.string.finish_pref_key));
if (pPallet) {
pNose.setChecked(false);
pFinish.setChecked(false);
}
}
else if(s.equals(getResources().getString(R.string.nose_pref_key))) {
pNose = sharedPreferences.getBoolean(s,false);
SwitchPreference pPallet = findPreference(getResources().getString(R.string.pallet_pref_key));
SwitchPreference pFinish = findPreference(getResources().getString(R.string.finish_pref_key));
if (pNose) {
pPallet.setChecked(false);
pFinish.setChecked(false);
}
}
else if(s.equals(getResources().getString(R.string.finish_pref_key))) {
pFinish = sharedPreferences.getBoolean(s,false);
SwitchPreference pPallet = findPreference(getResources().getString(R.string.pallet_pref_key));
SwitchPreference pNose = findPreference(getResources().getString(R.string.nose_pref_key));
if (pFinish) {
pNose.setChecked(false);
pPallet.setChecked(false);
}
}
}
});
}
}
}
So basically I'm just trying to make it so only one switch can be enabled at a time. I did some research and found a few threads on here that mentioned I should add this code:
#Override
protected void onResume() {
super.onResume();
// Set up a listener whenever a key changes
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
#Override
protected void onPause() {
super.onPause();
// Unregister the listener whenever a key changes
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
}
I'm thinking that's probably the reason for the crash, but when I add that code below the "OnSharedPreferenceChangeListener() {" statement onResume() and onPause() are greyed out unless I hoist it to the top in which case the this keyword throws an error. Does anyone see what I'm doing wrong?
Here's the error that I get on the crash:

Related

SettingActivity by using switchpreferenceCompat

I have a preference screen having multiple SwitchpreferenceCompat. I need to give a user choice of theme change,vibration,etc in settingActivity. Can any one help me in how to set vibrate or theme change by clicking switch in settingactivity. I used this inside my settingActivity fragment but when i click setting activity the app stops
SwitchPreferenceCompat switchPref = findPreference("key");
switchPref.setChecked(true);
`res/xml/root_preference.xml
<SwitchPreferenceCompat
android:id="#+id/vibrate"
app:key="On"
app:title="Vibrate"
android:summaryOff="Off"
android:summaryOn="On"
app:icon="#drawable/ic_baseline_vibration_24"
android:defaultValue="true" />
<SwitchPreferenceCompat
app:key="On"
app:title="Sound"
app:summaryOff="Off"
app:summaryOn="On"
app:icon="#drawable/ic_baseline_volume_up_24"
android:defaultValue="true"/>
</PreferenceCategory>
User clicks the vibration on the app must vibrate when the button is clicked in the activity. How can i do this?
Use Androidx library
implementation 'androidx.preference:preference:1.1.1'
Then create xml folder and add your SwitchPreferenceCompat like below:
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">
<SwitchPreferenceCompat
android:id="#+id/vibrate"
android:key="vibrate"
android:summary="It will vibrate your phone"
android:title="Vibrate"/>
<SwitchPreferenceCompat
android:id="#+id/changeTheme"
android:key="theme"
android:title="Change Theme"
android:summary="It will toggle your app theme"/>
</androidx.preference.PreferenceScreen>
Then create SwitchPreferenceCompatActivity like below:
public class SwitchPreferenceCompatActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_switch_preference_compat);
if(savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.preferences_container, new MySettingsFragment())
.commit();
}
}
public static class MySettingsFragment extends PreferenceFragmentCompat {
SharedPreferences.OnSharedPreferenceChangeListener listener;
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.my_switch_preference_compat, rootKey);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Log.e("key", key);
if(key.equals("vibrate") && sharedPreferences.getBoolean("vibrate", false)) {
vibratePhone();
}
}
};
}
#Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(listener);
}
#Override
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(listener);
}
private void vibratePhone() {
Vibrator vibrator = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator != null) {
// Vibrate for 500 milliseconds
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
//deprecated in API 26
vibrator.vibrate(500);
}
}
}
}
}
Note: add <uses-permission android:name="android.permission.VIBRATE" /> permission on manifest file.

Android SharedPreferences confusion

I am a beginner in android and I have a confusion regarding Shared Preferences implementation. My goal is to use a string where a user defines some text which will be used in MainFragment. Given the fact that user may change that string when application is running I need a listener as well. So according to one book so far I have a SettingsActivity and a SettingsFragment.
SettingsActivity so far:
public class SettingsActivity extends AppCompatActivity {
private SharedPreferences prefs;
private String stringIWantToSave;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
getFragmentManager().beginTransaction().
replace(android.R.id.content, new SettingsFragment(), "settings_fragment").commit();
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
prefs = PreferenceManager.getDefaultSharedPreferences(this);
}
#Override
protected void onResume() {
super.onResume();
stringIWantToSave = prefs.getString("stringIWantToSave", "myString");
}
}
SettingsFragment so far:
public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
private SharedPreferences sharedPreferences;
private String stringIWantToSave;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
}
#Override
public void onPause() {
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
super.onPause();
}
#Override
public void onResume() {
super.onResume();
sharedPreferences.getString("stringIWantToSave", "myString");
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
}
}
My questions are:
• In which method and how should I save the changed value from the user?
• How can I implement the listener so that it will inform the MainFragment that the string has changed?
1. To achieve the SettingsActivity with EditTextPreference, first you have to create a PreferenceScreen that contains EditTextPreference.
preferences.xml:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<EditTextPreference
android:key="pref_key_name"
android:title="Name"
android:summary="Enter your name here!"
android:dialogTitle="Enter name:">
</EditTextPreference>
</PreferenceScreen>
2. Create a Fragment extending PreferenceFragment. Do preference initialization and add OnSharedPreferenceChangeListener to update the UI when user input their name.
SettingsFragment.java:
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
// Preference Keys
public static final String KEY_PREF_NAME = "pref_key_name";
// Shared preference
SharedPreferences mSharedPreferences;
// Name preference
EditTextPreference mPreferenceName;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
// Shared preference
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
// Name preference
mPreferenceName = (EditTextPreference) getPreferenceScreen().findPreference(KEY_PREF_NAME);
// Initialize
initPreferences();
}
public void initPreferences()
{
// Name
String oldName = mSharedPreferences.getString(KEY_PREF_NAME, "Enter your name here!");
// Update view
mPreferenceName.setSummary(oldName);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPref, String key) {
if(key.equals(KEY_PREF_NAME))
{
// Name
String currentName = sharedPref.getString(key, "DEFAULT_VALUE");
// Update view
mPreferenceName.setSummary(currentName);
}
}
#Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
}
}
3. Finally, Create SettingsActivity and show SettingsFragment on its FrameLayout.
SettingsActivity.java:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
public class SettingsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
// Settings Fragment
SettingsFragment settingsFragment = new SettingsFragment();
getFragmentManager().beginTransaction().replace(R.id.content, settingsFragment).commit();
}
#Override
protected void onResume() {
super.onResume();
}
}
HOW TO USE:
To use updated name from preference, get the name value from preference inside your activity or fragments onResume() method:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume() {
super.onResume();
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
// Name
String name = sharedPreferences.getString(SettingsFragment.KEY_PREF_NAME, "DEFAULT_VALUE");
// Do something with name
................
........................
}
}
OUTPUT:
Hope this will help~

Listening for SharedPreferences changes in MainActivity

I am trying to listen SharedPreferences changes in the MainActivity. And update the values in the settings of the app. And the working code goes like:
private SharedPreferences SP, prefs;
SharedPreferences.OnSharedPreferenceChangeListener mListener;
SP = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
mListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
Toast.makeText(MainActivity.this, "Key changed: "+key, Toast.LENGTH_SHORT).show();
}
};
SP.registerOnSharedPreferenceChangeListener(mListener);
But when I try to change the key value like this. It says can not resolve findPreference method. I tried doing it using context but still the error persists.
private SharedPreferences SP, prefs;
SharedPreferences.OnSharedPreferenceChangeListener mListener;
SP = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
mListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals("username")) {
Preference pref = findPreference(key);
pref.setDefaultValue(prefs.getString(key, "bob")); }
};
SP.registerOnSharedPreferenceChangeListener(mListener);
How can we import the method definition in MainActivity. Please tell if the way I am changing value here, if correct?
Settings.java
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.os.Bundle;
public class Settings extends PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit();
}
public static class MyPreferenceFragment extends PreferenceFragment
{
PrefManager prefManager;
#Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
}
preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<EditTextPreference android:title="Your Name"
android:key="username"
android:summary="Please provide your username">
</EditTextPreference>
</PreferenceScreen>
I basically want to update the Preference in the settings page whenever SharedPreferences of key "username" is getting changed in the code.
You must implement PreferenceActivity in your activity
Add extends PreferenceActivity after your activity name and then import it's namespace:
public class MainActivity extends PreferenceActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
}
}
For more info look at http://developer.android.com/reference/android/preference/PreferenceActivity.html
EDITED
Use the following code:
public class Settings extends PreferenceActivity {
private SharedPreferences SP;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit();
SharedPreferences.OnSharedPreferenceChangeListener mListener;
SP = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
}
public static class MyPreferenceFragment extends PreferenceFragment implements
SharedPreferences.OnSharedPreferenceChangeListener{
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
#Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
}
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals("username")) {
Preference pref = findPreference(key);
pref.setDefaultValue(prefs.getString(key, "bob"));
}
}
}
}

Preference onClick Not Detected

i have setup an onpreference click listener for a preference but it fails to fire even though the preference is found by the find preference command.
Activity
public class PreferenceActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Display the fragment as the main content
setContentView(R.layout.activity_preference);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.replace(R.id.settings, new SettingsFragment())
.commit();
}
}
public static class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
Context context;
private final String DOB = "date";
private SharedPreferences prefs;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
context = getActivity().getApplicationContext();
Preference dob = findPreference(DOB);
Log.i("test", dob.getKey() + "");
dob.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
Log.i("test", "2");
return false;
}
});
}
#Override
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
}
#Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
}
}
The preference xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="My Account">
<EditTextPreference
android:key="profile_name"
android:summary="Taylor Swift"
android:title="Username" />
<Preference
android:key="date"
android:summary="N.A."
android:title="#string/date" />
</PreferenceCategory>
</PreferenceScreen>
The log output for "test" correctly displays the key of the preference but the log within the onclick never fires.
I've created simple project with your code and everything seems to be working fine.
Log.i("test", "2");
is being called when I click "Date" field.

SharedPreference Change Listener and custom preference

I have those preference:
<xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<CheckBoxPreference
android:key="pk1"
android:title="#string/pt1"
android:summary="#string/pt1s"
android:defaultValue="false" />
<CheckBoxPreference
android:key="pk2"
android:title="#string/pt2"
android:defaultValue="false" />
<ListPreference
android:key="pk3"
android:title="#string/pt3"
android:dialogTitle="#string/pt3"
android:entries="#array/fontsi"
android:entryValues="#array/fontsiv"
android:defaultValue="0" />
<Preference
android:key="pkb"
android:title="#string/ptb" />
</PreferenceScreen>
And the settings activity:
public class SettingsActivity extends PreferenceActivity {
SharedPreferences.OnSharedPreferenceChangeListener lst;
SharedPreferences prf;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
prf = getPreferenceScreen().getSharedPreferences();
lst = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
Log.i("SettingsActivity","!any preference changen!");
if (key.equals("pk1")) { Log.i("SettingsActivity","!pref PK1 called!"); } }
else if (key.equals("pkb")) { Log.i("SettingsActivity","!pref PKB called!"); }
prf.registerOnSharedPreferenceChangeListener(lst);
}
#Override
protected void onResume() {
super.onResume();
prf.registerOnSharedPreferenceChangeListener(lst); }
#Override
protected void onPause() {
super.onPause();
prf.unregisterOnSharedPreferenceChangeListener(lst); }
...
}
The listener works with all the preferences but e custom preference (the last one, pkb as key)!
That i want to use as a back button.
Anybody knows why ?
Obviously your preference doesn't change any preferences.
Since it doesn't do anything, OnSharedPreferenceChangeListener ignores it.
A possible solution would be to set a clickListener to it like this:
findPreference("pkb").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
Log.i("SettingsActivity", "!pref PKB called!");
return false;
}
});

Categories

Resources