I am working with a PreferenceActivity that will be fully compatible with tablets.
For this, I will work as advised by Google in this page.
#Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.preference_headers, target);
}
My problem is that I would like to be able to select the default header when the activity is launched.
For instance, I have several headers;
General Settings
UI Settings
Network settings
And depending on which activity I come from, I would like to display the correct settings.
Is there a way to achieve that?
When creating the Intent to invoke the PreferenceActivity, you can add the extra string 'EXTRA_SHOW_FRAGMENT' to specify which fragment should be initially displayed. You pass the name of the fragment you would like to select.
For instance, if you would like to select the General Settings header (and its contents) you can use the following code:
final Intent intent = new Intent(this, ExtendedPreferenceActivity.class); // Assume we call it from an other activty
intent.putExtra(EXTRA_SHOW_FRAGMENT, GeneralSettingsFragment.class.getName());
startActivity(intent);
More information on this can be found here: http://developer.android.com/reference/android/preference/PreferenceActivity.html
In an issue report to Google it is reported that for Android version 3.0 the correct header will not be automatically selected as well. For the issue report and its workaround look here: issue report.
You can create PreferenceHeaders dynamically using PreferenceActivity.Header class
http://developer.android.com/reference/android/preference/PreferenceActivity.Header.html
You can use a fragment by default:
Here is what I've done:
public class PreferencesActivity extends SherlockPreferenceActivity {
/** Variables **/
/** Constants **/
private static final String CLASSTAG = PreferencesActivity.class.getSimpleName();
/** Class Methods **/
#Override
public void onCreate(Bundle savedInstanceState) {
Log.v(CLASSTAG, "onCreate");
super.onCreate(savedInstanceState);
initializeUI();
}
#Override
public Intent getIntent() {
Log.v(CLASSTAG, "getIntent");
final Intent modIntent = new Intent(super.getIntent());
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, SettingsFragment.class.getName());
modIntent.putExtra(EXTRA_NO_HEADERS, true);
return modIntent;
}
/** Private Functions **/
private void initializeUI() {
getSupportActionBar().hide();
}
/** Classes **/
public static class SettingsFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.settings_preference);
initializeUI();
}
private void initializeUI() { }
}
}
and the default xml (as prior HoneyComb versions...):
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="#string/preferences_category_1">
<com.taptime.ui.preferences.ClickPreference
android:key="#string/preferences_conditions_key"
android:title="#string/preferences_conditions_title"/>
</PreferenceCategory>
<PreferenceCategory
android:title="#string/preferences_category_2">
<com.newin.android.ui.widget.ClickPreference
android:key="#string/preferences_logout_key"
android:title="#string/preferences_logout_title"
android:summary="#string/preferences_logout_summary"/>
</PreferenceCategory>
</PreferenceScreen>
Related
I am trying to open the android default TTS settings whenever I click on the particular preference in my App settings. My pref_settings.xml looks like this:
<PreferenceScreen
android:key="Lang_Select"
android:title="Language"
android:summary="Select a Language">
</PreferenceScreen>
This is my list in android settings. and my SettingsActivity.java looks like this:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
}
public static class ChatSettingsFragment extends PreferenceFragmentCompat {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.pref_settings);
}
}
#Override
public void onBackPressed() {
super.finish();
}
}
How can I start the android default TTS settings whenever the language button is clicked?
Thanks.
I have not worked with PreferenceFragmentCombat only with normal PreferenceFragment, but I guess it´s not that much difference in the basic implementations. So please, be noticed that this is maybe not the answer for your problem, but I try to help you a little bit and have to show some code. I have done it in my onCreate() method like this:
public class PreferenceFragment extends android.preference.PreferenceFragment {
private Preference mYourPreference;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preference_layout);
//initialize your preference with the key you used in xml layout
mYourPreference=(Preference)getPreferenceManager().findPreference(yourPreferenceKey);
//set on click listener
mYourPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
//start the activity
startActivity(new Intent(android.provider.Settings.ACTION_VOICE_INPUT_SETTINGS), 0);
return true;
}
});
}
}
I don´t know if ACTION_VOICE_INPUT_SETTINGS will work, just try it.
Try this:
startActivity(Intent("com.android.settings.TTS_SETTINGS"))
See: https://cs.android.com/android/platform/superproject/+/master:cts/apps/CtsVerifier/src/com/android/cts/verifier/speech/tts/TtsTestActivity.java;l=21?q=TTS_SETTINGS
I've read a few questions about this, but I wasn't happy with the answers, so I decided do ask about my particular example.
I'm developing and Android App that has a Settings screen with a few configurable integer parameters. All these parameters have a maximum and minimum value. Therefore, everytime the user sets a new value for those parameters, I want to validate them. If the new value is out of the defined bounds, I want to show a Toast informing the user of what went wrong.
On the other hand, because in some situations in my App the user can "spam" a button that may show a Toast, in order to avoid having Toast showing repetedly for a while, I created an Application class with a static Toast that is shown everytime I want to show a toast:
public class MyApplication extends Application {
private static Toast toast;
public static void showToast(Context context, String string){
//(...)
}
}
Back to the Settings page, here's how I implemented it:
public class SettingsActivity extends PreferenceActivity {
private Context context;
static SharedPreferences sharedPreferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
}
public static class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
setListeners();
}
public void setListeners() {
setListenerA();
//(other listeners to other settings)
}
private void setListenerA() {
findPreference(KEY_PREF_A).setOnPreferenceChangeListener(
new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean isEmpty = newValue.toString().isEmpty();
//(other validations)
boolean isValid = !isEmpty; //&& (other validations)
if(!isValid){
if(isEmpty){
MyApplication.showToast(context, MyApplication.getResources().getString(R.string.toastPreferenceNullValue));
} else if(isAnotherReasonToFail1){
// another Toast
} // else if(other reasons to fail)
}
return isValid;
}
}
);
}
}
}
And here are my problems: MyApplication.getResources() is a non-static method and cannot be called from the static context of class SettingsFragment. Also context is not static (as it should not be) and can't also be referenced there.
I need to show that Toast because otherwise the user wouldn't have a clue why his settings weren't being applied. On the other hand, I need the error message to be stored in the strings.xml file, not only because that's how you do it, but also for future multi-language purposes.
I am not familiar with how Fragments work, and I made the Settings screen like this after reading a few articles (like this one) and some questions here. There might be a different way to make a Settings screen that allows me to do what I want, I just don't know any.
Can someone suggest an approach that fits my problem?
Thanks
EDIT: emerssso solved the resources part. Now the problem is only how to call the Toast without having a context.
Fragment has a getResources() method that is equivalent to calling Application::getResources(). The only caveat is that you have to make sure that the fragment is attached to an activity (i.e. getActivity() != null) or you risk throwing an exception.
See: https://developer.android.com/reference/android/app/Fragment.html#getResources()
More generally, getActivity() can be used to get a valid context whenever the fragment is attached to the activity, as Activity is an implementation of Context.
If you want to have a context reference even after a fragment has detached, you can store a reference to getActivity().getApplicationContext() safely in the fragment for later use, but this is probably not ideal.
I have an AppCompatPreference SettingsActivity with a PreferenceFragment, like this:
public class SettingsActivity extends AppCompatPreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "activity onCreate called");
setupActionBar();
String userString = getIntent().getStringExtra(LoginActivity.USER);
Log.v(TAG, "UserString: " + userString);
...
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GeneralPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "GeneralPreferenceFragment onCreate called");
addPreferencesFromResource(R.xml.pref_general);
setHasOptionsMenu(true);
}
}
}
When I start the app, a LoginActivity authenticates with a server and passes user data (userString) to the SettingsActivity. It then starts a service with that data.
Everything is peachy and the service starts with no problem.
D/SettingsActivity: activity onCreate called
V/SettingsActivity: UserString: {some string of JSON user data}
But then I tap on General Preferences. As soon as I do so, this gets logged:
D/SettingsActivity: activity onCreate called
V/SettingsActivity: UserString: null
Because it logs activity onCreate called instead of GeneralPreferenceFragment onCreate called, it seems like the wrong onCreate() is being called. The app then crashes with a NullPointException trying to start the service with a null user.
I am trying to figure this out. Maybe the entire activity is restarting for some reason? Any suggestions on diagnosing this problem would help.
As your log shows, a new instance of activity is created.
This is the expected behaviour of the PreferenceActivity on a phone. Tablets use a two-pane layout and keep a single activity. But phones start a new activity.
AppCompat behaves the same.
You can however pass more data to the fragment with
public class MySettingsActivity extends PreferenceActivity {
#Override
public void onBuildHeaders(List<Header> target) {
super.onBuildHeaders(target);
// You can build with xml settings that don't depend from UserString
loadHeadersFromResource(R.xml.preferences, target);
// For Settings that depend on UserString:
Header userHeader = new Header();
userHeader.title = ""; // TODO
user.fragment = UserFragment.class;
Bundle args = new Bundle(1);
// TODO Pass a User parcelable instead
args.putString(EXTRA_USER, userString);
userHeader.fragmentArguments = args;
}
}
I am doing an app with preferences but I have used a method that is deprecated and it says :
"This function is not relevant for a modern fragment-based PreferenceActivity". My code is this:
public class Settings extends PreferenceActivity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
How can I update this to not deprecated function. Thank you very much.
The new way is to do the Preferences in an Fragment instead of an Activity. This is espacially true for large screens and tablets. Fragments can be shown separate or next to each other over an Activity according to screen size. Use them like this:
public static class YourPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
}
}
and instead of calling the PreferenceActivity you make a call to the Fragment in your Activity:
YourPreferenceFragment prefFragment = new YourPreferenceFragment();
prefFragment.show(getFragmentManager(), "someFragmentId");
Try to use PreferenceFragment instead.
Check this: http://developer.android.com/guide/topics/ui/settings.html
PreferenceActivity is depricated, you can use PreferenceFragment instead.
here are some tutorials
Link 1
Link 2
Here is the documenattion for PreferenceFragment
I want to have an "option" set before the Activity is created or at least before it starts. If there is a way to do this via the AndroidManifest? Consider this example where we have a global config class that is used in onCreate to instantiate an object (not fully OO for brevity)
public class Global {
public static boolean visible = false;
}
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// here is where we want the most up-to-date value of visible
MyObject obj = new MyObject(Global.visible);
}
}
Obviously in this case "visible" would be "false". If this were some sort of API library, we would like to provide the option for users to set "visible" to "true".
Update 1
The objective is to have the global class in a pre-compiled library and have its value set by a developer utilizing the library. I am looking for easiest way for the developer to do this when they create their application; I think the manifest is the probably the way to go but I don't know how to inject the value for "visible" via the xml. The answers below using preferences are good but only cover the users point-of-view.
Update 2
IMHO using resources works best here.
<bool name="visible">true</bool>
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// here is where we want the most up-to-date value of visible
Resource res = getResource();
MyObject obj = new MyObject(res.getBoolean(R.bool.visible));
}
}
I think using SharedPreferences would do what you are looking for, using Global.visible as the default value. Then if the user changes it to true, it will use that value.
boolean makeVisible = PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
"MyVisiblePreference",
Global.visible);
MyObject obj = new MyObject(makeVisible);
To allow the preference to be updatable without re-compiling or setting (through a Preferences activity), you can load the default preference from resources:
<bool name="MyVisiblePreference">true</bool>
And reference it similarly with:
boolean makeVisible = PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
"MyVisiblePreference",
getResources().getBoolean(R.bool.MyVisiblePreference));
If the developer does not set the preference to false, it will default to true (based upon the resources value).
For simple objects you can create them like this: (Based off of your code example)
public static boolean visible = false;
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// here is where we want the most up-to-date value of visible
MyObject obj = new MyObject(Global.visible);
}
}
For a more complex object you can initialize it with a static initializer like this:
public static boolean visible;
static {
visible = false;
}
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// here is where we want the most up-to-date value of visible
MyObject obj = new MyObject(Global.visible);
}
}
You can subclass android.app.Application, this class has method onCreate that you can override. Your subclass have to be defined in AndroidManifest.xml in <application name="YourApplication">. onCreate of application is called before all other components in your application are created (before any Activity or Service).