I'm writing an app for the Sony Smartwatch, using their SDK. Here's part of the main activity:
class SmartTickerActivity extends ControlExtension {
private Handler mHandler;
SmartTickerActivity(final String hostAppPackageName, final Context context, Handler handler) {
super(context, hostAppPackageName);
if (handler == null) {
throw new IllegalArgumentException("handler == null");
}
}
#Override
public void onStart() {
//do some stuff
PreferenceManager.setDefaultValues(mContext, R.xml.preference, false);
}
The problem is that the saved preferences aren't being applied on the Smartwatch when the application launches. Nor are the default preference values from XML. However, if I click on any of the app's preferences on the phone, the saved preference values are immediately applied to the Smartwatch.
Note that the main class has no onCreate() method, and that's throwing me for a loop.
Here's part of the Preference activity:
public class MyPreferenceActivity extends PreferenceActivity {
private OnSharedPreferenceChangeListener mListener = new OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preference pref = findPreference(key);
if (pref instanceof ListPreference) {
ListPreference listPref = (ListPreference) pref;
pref.setSummary(listPref.getEntry().toString());
}
if (pref instanceof EditTextPreference) {
EditTextPreference editTextPref = (EditTextPreference) pref;
pref.setSummary(editTextPref.getText().toString());
}
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preference);
setSummaries();
setTypeface(SmartTickerActivity.mainLayout);
if (previewLayout != null) setTypeface(previewLayout);
// Handle read me
Preference readMe = findPreference(getText(R.string.preference_key_read_me));
readMe.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference readMe) {
showDialog(DIALOG_READ_ME);
return true;
}
});
// Handle about
Preference about = findPreference(getText(R.string.preference_key_about));
about.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference about) {
showDialog(DIALOG_ABOUT);
return true;
}
});
// Handle preview
Preference preview = findPreference(getText(R.string.preference_key_preview_dialog));
preview.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preview) {
showDialog(DIALOG_PREVIEW);
return true;
}
});
}
I'm rather inexperienced at Android development, so the problem might very well have nothing to do whatsoever with the Sony SDK. Can anyone help?
You are correct, the preferences of the official sample extensions are not loaded until the PreferenceActivity is shown for the first time. If you use correct default values when accessing the preferences, this should not be a problem.
If you would like for the preferences to be loaded when the extension is initiated the first time, you could extend the android.app.Application class, and the onCreate method.
For example:
public class MySmartWatchApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
PreferenceManager.setDefaultValues(this, R.xml.app_preferences, false);
}
}
Related
Changing night-light mode perfectly works in my emulator, but when i try to do the same on physical device(xiaomi) I get next exception:
E/ActivityInjector: get life cycle exception
java.lang.ClassCastException: android.os.BinderProxy cannot be cast to android.app.servertransaction.ClientTransaction
at android.app.ActivityInjector.checkAccessControl(ActivityInjector.java:24)
at android.app.Activity.onResume(Activity.java:1859)
at androidx.fragment.app.FragmentActivity.onResume(FragmentActivity.java:456)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1454)
at android.app.Activity.performResume(Activity.java:8050)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4269)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4311)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ClientTransactionHandler.executeTransaction(ClientTransactionHandler.java:57)
at android.app.ActivityThread.handleRelaunchActivityLocally(ActivityThread.java:5353)
Here is my code in activity and presenter where i change mode of my my application:
public class MoviesListActivity extends AppCompatActivity implements MovieListView {
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
if (item.getItemId() == R.id.darkMode) {
presenter.changeToDarkMode();
}
else if(item.getItemId() == R.id.lightMode) {
presenter.changeToLightMode();
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.movie_list);
presenter = new MoviesListPresenter(this, getApplicationContext());
if (presenter.getCurrentMode() == 0) {
presenter.changeToLightMode();
} else {
presenter.changeToDarkMode();
}
}
//Other code...
}
Presenter:
public class MoviesListPresenter {
public void changeToLightMode() {
currentMode = context.getSharedPreferences(Constants.MODE, Context.MODE_PRIVATE);
currentMode.edit().putInt(Constants.MODE, 0).apply();
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
public void changeToDarkMode() {
currentMode = context.getSharedPreferences(Constants.MODE, Context.MODE_PRIVATE);
currentMode.edit().putInt(Constants.MODE, 1).apply();
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
}
public int getCurrentMode() {
currentMode = context.getSharedPreferences(Constants.MODE, Context.MODE_PRIVATE);
return currentMode.getInt(Constants.MODE, 0);
}
}
I will be thankful for any help!
This seem caused by calling Activity.recreate() in Xiaomi's firmware. This problem also happen to my library which recreate the activity to apply the language changing.
See https://github.com/akexorcist/Localization/issues/89
In my case, no app crashing and code working properly. So I skipped this problem.
Related questions
MIUI 11/12 Theme Switch Results in LifeCycleException, ClassCastException
Getting Lifecycle Exception While Recreating The Activity
In my app once user provide three inputs, AsyncTask starts which connects to the server and gets info for two more fields. Once AsyncTask is finished, I want to set those two received values in opened setting page.
I searched and try this code, but not updating summary for fields for which value has fetched from server.
Problem is I'm not able to set values received from server as summary to EditTextPreference. If I reopen settngs page it shows value not without reopening.
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
updatePreference(key);
}
private void updatePreference(String key) {
if (key.equals("id")) {
Preference preference = findPreference(key);
if (preference instanceof EditTextPreference) {
EditTextPreference editTextPreference = (EditTextPreference) preference;
if (editTextPreference.getText().trim().length() > 0) {
editTextPreference.setSummary(editTextPreference.getText());
} else {
editTextPreference.setSummary("");
}
}
} else if (key.equals("sclass")) {
Preference preference = findPreference(key);
if (preference instanceof EditTextPreference) {
EditTextPreference editTextPreference = (EditTextPreference) preference;
if (editTextPreference.getText().trim().length() > 0) {
editTextPreference.setSummary(editTextPreference.getText());
} else {
editTextPreference.setSummary("");
}
}
}
}
Create a listener and call it in your onCreate
sharedPrefYourObj.registerOnSharedPreferenceChangeListener(this);
try to register you listener onResume and unregister it onPause though rather than onCreate!
example :
protected void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
protected void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
}
I have Preferences activity in my app that has ListPreference so the user can choose language for the app.
The app displays the new language just after the user close the Preferences activity.
I want to create a listener to the ListPreference so the app will restart when the Listener is triggers (just after the user choose a language/choose item from the ListPreference).
How can I do that?
SettingsActivity:
public class SettingsActivity extends AppCompatPreferenceActivity {
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object value) {
String stringValue = value.toString();
if (preference instanceof ListPreference) {
// For list preferences, look up the correct display value in
// the preference's 'entries' list.
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(stringValue);
// Set the summary to reflect the new value.
preference.setSummary(
index >= 0
? listPreference.getEntries()[index]
: null);
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
preference.setSummary(stringValue);
}
return true;
}
};
/**
* Binds a preference's summary to its value. More specifically, when the
* preference's value is changed, its summary (line of text below the
* preference title) is updated to reflect the value. The summary is also
* immediately updated upon calling this method. The exact display format is
* dependent on the type of preference.
*
* #see #sBindPreferenceSummaryToValueListener
*/
private static void bindPreferenceSummaryToValue(Preference preference) {
// Set the listener to watch for value changes.
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
// Trigger the listener immediately with the preference's
// current value.
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.getContext())
.getString(preference.getKey(), ""));
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupActionBar();
setTitle(R.string.action_settings);
}
/**
* Set up the {#link android.app.ActionBar}, if the API is available.
*/
private void setupActionBar() {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
// Show the Up button in the action bar.
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
#Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
if (!super.onMenuItemSelected(featureId, item)) {
NavUtils.navigateUpFromSameTask(this);
}
return true;
}
return super.onMenuItemSelected(featureId, item);
}
/**
* This method stops fragment injection in malicious applications.
* Make sure to deny any unknown fragments here.
*/
protected boolean isValidFragment(String fragmentName) {
return PreferenceFragment.class.getName().equals(fragmentName)
|| GeneralPreferenceFragment.class.getName().equals(fragmentName);
}
/**
* This fragment shows general preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GeneralPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_general);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("example_text"));
bindPreferenceSummaryToValue(findPreference(getString(R.string.language_shared_pref_key)));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
Intent intent = new Intent(getActivity(), MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
getActivity().finish();
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
}
}
pref_general.xml:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<ListPreference
android:defaultValue="#string/language_code"
android:entries="#array/pref_languages_list_titles"
android:entryValues="#array/pref_languages_list_values"
android:key="#string/language_shared_pref_key"
android:negativeButtonText="#null"
android:positiveButtonText="#null"
android:title="#string/pref_title_language" />
</PreferenceScreen>
Thank you!!!
Here is some real quick sample code for a shared prefs chaneg listener I have set-up in one of my projects; it's located in the onCreate of a Service but obviously can detect changes to my shared prefs that originate from anywhere in my app.
private SharedPreferences.OnSharedPreferenceChangeListener listener;
//Loads Shared preferences
prefs = PreferenceManager.getDefaultSharedPreferences(this);
//Setup a shared preference listener for hpwAddress and restart transport
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals(/*key for shared pref you're listening for*/) {
//Do stuff; restart activity in your case
}
};
prefs.registerOnSharedPreferenceChangeListener(listener);
One possible solution is to keep everything together, and implement the OnSharedPreferenceChangeListener interface inside your own GeneralPreferenceFragment.
You can do that by declaring that GeneralPreferenceFragment both inherits from PreferenceFragment, and implements SharedPreferences.OnSharedPreferenceChangeListener interface. This means that you need to define override for onSharedPreferenceChanged in GeneralPreferenceFragment.
Because preferences can change only if the fragment in question is active, you can register your fragment as listener in onResume for a fragment (via registerOnSharedPreferenceChangeListener), and unregister it on onStop.
The following example code is in Kotlin, not in Java, but it should be fairly easy to translate it.
class SettingsActivity : AppCompatActivity() {
// ...
class SettingsFragment : PreferenceFragmentCompat(),
SharedPreferences.OnSharedPreferenceChangeListener
{
// ...
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?,
key: String?) {
if (key == "<something>")
// do something
}
override fun onResume() {
super.onResume()
preferenceScreen.sharedPreferences
?.registerOnSharedPreferenceChangeListener(this)
}
override fun onPause() {
super.onPause()
preferenceScreen.sharedPreferences
?.unregisterOnSharedPreferenceChangeListener(this)
}
}
I have a couple of CheckBoxPreferences set up, my preference class extends PreferenceActivity and implements OnSharedPreferenceChangeListener
This is what I'm using to respond to people checking/unchecking the CheckBoxPreferences:
public void onSharedPreferenceChanged(SharedPreferences P, String K) {
if (K.equals(CheckBoxPref_KEY_HERE)) {
MyClass.BooleanVariable = P.getBoolean("CheckBoxPref_KEY_HERE", true);
}
}
As far as I can tell, the onSharedPreferenceChanged method above is never even getting called?
Here is the soln if you want to do something on all the preferences:
Create a class member:
SharedPreferences settings;
in your onCreate method:
settings = getSharedPreferences(<your_pref_name>, 0);
settings.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged (SharedPreferences sharedPreferences, String key) {
// Do whatever
}
});
checkBoxPreference = (CheckBoxPreference) this.findPreference("CheckBoxPref_KEY_HERE");
checkBoxPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// do your work here
return true;
}
});
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.