I have a PreferenceScreen that is defined in XML that serves all the preferences for my application. This PreferenceScreen also has a child PreferenceScreen nested within it. My implementing class is called PreferencesActivity. I know I can open the main Preferences window via startActivity(new Intent(this, PreferencesActivity.class)); but how do I go about opening the child PreferenceScreen via an Intent?
i researched a while on this topic for my project Theft Aware (http://www.theftaware.com) (a little bit advertisement... :-) and i found the solution:
PreferenceScreen screen = getPreferenceScreen(); // gets the main preference screen
screen.onItemClick(null, null, INDEX , 0); // click on the item
where INDEX is the position of the item you want to open on the screen
see this question for a more general solution based on Reinhard's idea, finally!
Related
I've implemented my own PreferenceFragment subclass (detailed here), and want to listen for preference changes within it. PreferenceFragment provides you with two ways of doing this:
getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
and
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
Which one should be used? What's the difference? I don't really understand the distinction made in the Android docs.
The core difference is in their names, PreferenceManger grants access to different functionalities to the developer for managing SharedPreferences, such as retrieving the map of current preference values or setting user preferences. to their default values. PreferenceScreen handles displaying a screen of user preferences, so that the user can assign values to them. Sometimes this means displaying a list item on a screen with other preferences, that opens another screen with more preferences when clicked, as is the case when PreferenceScreens are nested.
Your question implies that you think there is a difference between what PreferenceManager.getSharedPreferences() and PreferenceScreen.getSharedPreferences() does, but according to the source code, they are identical.
PreferenceScreen:
public SharedPreferences getSharedPreferences() {
if (mPreferenceManager == null) {
return null;
}
return mPreferenceManager.getSharedPreferences();
}
So the PreferenceManger and PreferenceScreen are different entities, but the SharedPreference those method return should be the same object, since PreferenceScreen calls the method from PreferenceManager. I hope that is the answer you've been seeking.
If you have a choice, go with PreferenceManager.getSharedPreferences(), it's more obvious and one fewer method call internally.
Fun fact:
PreferenceFragment:
public PreferenceManager getPreferenceManager() {
return mPreferenceManager;
}
public PreferenceScreen getPreferenceScreen() {
return mPreferenceManager.getPreferenceScreen();
}
The first one gets the shared preferences from the PreferenceManager. The second one, from the PreferenceScreen, that inherits this method from Preference class.
I think this is not a functional difference, because both return probably the same instance of the SharedPreferences objects, but I think it's clearer to use the first one (using PreferenceManager instead of PreferenceScreen).
PreferenceScreen see domentation here
PreferenceScreen class can appear in two places:
When a PreferenceActivity points to this, it is used as the root and
is not shown (only the contained preferences are shown).
When it appears inside another preference hierarchy, it is shown and
serves as the gateway to another screen of preferences (either by
showing another screen of preferences as a Dialog or via a
startActivity(android.content.Intent) from the getIntent()). The
children of this PreferenceScreen are NOT shown in the screen that
this PreferenceScreen is shown in. Instead, a separate screen will be
shown when this preference is clicked.
PreferenceManager see documentation here:
Difference :
getPreferenceManager () returns the current preference manager associated with the fragment.
getPreferenceScreen () returns the root PreferenceScreen i.e. root preference screen used in the fragment from preference xml file(preferences.xml).
I will start with an example... If you go to Settings > Applications > Manage applications, a new screen will open with a list of the installed applications: if you click on any application of the list, it will open a new screen containing information about the application.
Well, some settings of my application must be managed through a list, and this list should behave like the above example. I have already created a PreferenceActivity with some categories, each of which has some items: when I click on one of these items, I would like it to open a new screen where the new data is placed on a list, just like the list of the applications of the above example. Moreover, when I click on any entry of this list, it will open a new screen in order to set some data.
How should I proceed? Should I create an activity for each screen?
Android was created this way, according to the documentation "An activity is a single, focused thing that the user can do.", so yes, you should have an activity for each screen.
This changed a little with Honeycomb with the introduction of Fragments, but if you're not developing for tablets you should keep the one page, one activity mindset on Android.
Generally you have each activity call by another, the caller is pushed onto a stack (unless the calling activity ask's to be removed) and goes dormant until it returns
Basically you create an Intent in Activity A to start Activity B, you can pass data by using startActivityForResult with extras in the intents Example: How to pass data between activities
When you press the back button then that previous activity becomes active again and the result handler you set up can get any return data.
You might also look at fragments in the support API if you want to provide tablet support that looks and behaves better.
That is propably the best way to do it, at least if you're not working on a wizard style activity.
Use a ListActivity to show your list, and pass data to and from this activity using intents.
I was able to implement this at work, I don't remember right now in the head how I implemented it, was long time ago. If nobody has a good answer for you I will post it tomorrow, however: I remember putting a Preference, which will act as a button, then I added a preferenceClickListener in order to open a new PreferenceScreen on click.
But like I said, I'll post it for you tomorrow if you don't get a satisified answer.
Good luck!
UPDATE:
?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="Personal"
android:key="personal_category">
<Preference
android:key="birth"
android:title="Birth"
android:summary="Choose your birthday"/>
<PreferenceScreen
android:key="height_imp"
android:title="Height"
android:summary="Enter your height">
<EditTextPreference
android:key="foot"
android:title="Foot"
android:summary="foot"
android:numeric="integer"
android:dialogTitle="Foot"/>
<EditTextPreference
android:key="inch"
android:title="Inch"
android:summary="inch"
android:numeric="integer"
android:dialogTitle="Inch"/>
</PreferenceScreen>
<EditTextPreference
android:key="weight"
android:title="Weight"
android:summary="Enter your weight"
android:numeric="integer"
android:dialogTitle="Weight"/>
</PreferenceCategory>
</PreferenceScreen>
That's it! When you click on it, it will take you to the second PreferenceScreen and so on, then finally when you need to customize your layout you'll need to open an Activity.
You could then use a Preference and add onPreferenceClick:
#Override
public boolean onPreferenceClick(Preference preference) {
if(preference == birth){
startActivity(new Intent(getBaseContext(), Birth.class));
}
if(preference == height_imp){
PreferenceScreen a = (PreferenceScreen) preference;
a.getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.WHITE));
return false;
}
return true;
}
If you need to change the background or something else with the preferenceScreen, then add a preferenceClickListener as well: height_imp = (PreferenceScreen)getPreferenceScreen().findPreference("height_imp");
height_imp.setOnPreferenceClickListener(this);
See... if once the user wants to return from certain point to previous position... if you had created a seperate activity for each of them... the present activity will be popped off the stack... letting the previous activity to be displayed...If you are changing the content of the list for every new screen...instead of creating new activity... then it will be difficult for the user to come back... you should again and again change the content of adapter..
So I think.. creating seperate activity for each screen is better..( and you can use same [any custom layout if you have]layout file for all activities..)
I have a class which extends from ListView. I added some extra functionality(drag and drop) for this new class. My question is there any way i can use this extended ListView class in a preference activity.
I need to provide drag and drop functionality for a legacy preference activity.
Are you asking if it's possible to open an arbitrary activity from a clicked item in a preference activity? If so, you need to do two things. First, add a PreferenceScreen item to your preferences xml file:
<PreferenceScreen
android:key="CUSTOM_ACTIVITY_KEY"
android:title="Title"
android:summary="Summary" />
Then in your settings activity's onCreate:
Preference pref = getPreferenceScreen().findPreference("CUSTOM_ACTIVITY_KEY");
final Intent intent = new Intent(this, CustomActivity.class);
if (pref != null)
{
pref.setOnPreferenceClickListener(new OnPreferenceClickListener()
{
public boolean onPreferenceClick(final Preference preference)
{
startActivity(intent);
return false;
}
});
}
If running a custom activity off of a PreferenceScreen item isn't enough, the only other option I could think of is to roll your own Preferences implementation. Someone else should correct me if I'm mistaken, but I think it might be possible to pull the Preferences source and modify accordingly.
I came across another API in
android.preference.PreferenceScreen.bind(ListView listView)
Binds a ListView to the preferences contained in this PreferenceScreen via getRootAdapter().
So after inflating the layout file, we will be able to attach the our custom listview to this the preferenceScreen of the activity.
I'd like to recreate a functionality similar to a Swing GlassPane to be able to display animations while the user uses the app "below" normally. I cannot simply create a separate layout and attach it to each activity since the animation state would be lost when switching activities.
Is there a way to keep a persistent view over all the activities of an Android application ?
Thanks.
No its not. Every Activity runs in its own thread and is by design supposed to be runnable standalone.
But you could persist the animation state into the DB or into sharedPreferences and start it over at the new activity.
What you could also do is to use a Spinner or another control instead of seperate activitys. Then you could have a persistent view.
why not think in a TabActivity?
hi! i do this before with a TabActivity, never with an only activity, always with many activitys wich i started, get theirs windows and setting as my TabActivity window´s decor view... i dont tested the code below, since is an idea, but maybe more lately (when i'll be on home) i'll write an example...
So, my idea...
a TabActivity is composed by a TabWidget and a FrameLayout where the activity´s windows is allocated.
the TabWidget can be any view, so, you can put the animated view here.
the most difficult thing is the fact that, if you start an activity from the TabActivity´s child, then the new activity will be on top of the TabActivity. In order to overrides this behavior the TabActivity must know when a nested activity wants to start another activity. When this happens the TabActivity must clear his decor view (with the old window activity) and put the decor view of new one. Something like this:
on the child activity, launch a new activity when we click on a button:
... on click listener...
((MyTabActivity)getParent()).createNewActivity("NewActivity", NewActivity.class);
now, we´re saying the TabActivity that it has to start a new activity, get the new activity decor view and put that view inside the TabActivity decor view... so, the createNewActivity will perform something like this:
public void createNewActivity(String activityId, Class<?> class1) {
Intent intent = new Intent( getIntent().getAction() ).setClass(MyTabActivity.this, class1);
Window wList = getLocalActivityManager().startActivity(activityId, intent);
getWindow().setContentView(wList.getDecorView());
}
hope you understand me.
i'll write an example later
Im in the conceptualizing/design phase of building an app and i've hit a bit of a snag. Essentially i was looking for a way to embed one activity into the UI of another similar to how a TabHost/TabActivity. There would be a window at the top of the screen which would contain the other activity, and below that would be buttons and controls that are independent of the above activity and should always be visible. The user would be able to navigate from one activity to another in the window without causing any change to the below controls.
While looking into the issue i ran across ActivityGroup, which looked like it would be useful, but how would i implement it? Anyone have experience with ActivityGroup or have another idea?
Yes, you'd implement an ActivityGroup, which will be the container of your other Activities. When the user clicks one of the buttons, you'd get a reference to the LocalActivityManager, and use it to start, and embed the inner activity. Something like this:
LocalActivityManager mgr = getLocalActivityManager();
Intent i = new Intent(this, SomeActivity.class);
Window w = mgr.startActivity("unique_per_activity_string", i);
View wd = w != null ? w.getDecorView() : null;
if(wd != null) {
mSomeContainer.addView(wd);
}
Note, using this method can be pretty complicated, because unless the focus is just right, pressing the hardware buttons (like the menu button) will only only trigger events on the ActivityGroup instead of the inner Activity. You have to find some way to focus the inner activity after you add it to the container view, at which point the even will happen in the inner activity and propagate to the container activity.
It can be done, I've done it... and it works. It's just a bit more complicated than I think it should be.
Anyway, I got most of this information by looking at the TabHost code, which can be found here