[Android Software Development] Fr4gg0r:
Hi,

since the compability package does not ship PreferenceListFragment, I built my own one, which I am using in my gtalk widget app.

I was asked for the source, so here it is. It's quite a hacky workaround.. ;)

Edit: Someone asked about the license: Use it however you like ;)

public class PreferenceListFragment extends ListFragment{

private PreferenceManager mPreferenceManager;

/**
* The starting request code given out to preference framework.
*/
private static final int FIRST_REQUEST_CODE = 100;

private static final int MSG_BIND_PREFERENCES = 0;
private Handler mHandler = new Handler() {
[MENTION=439709]override[/MENTION]
public void handleMessage(Message msg) {
switch (msg.what) {

case MSG_BIND_PREFERENCES:
bindPreferences();
break;
}
}
};
private ListView lv;
private int xmlId;

public PreferenceListFragment(int xmlId){
this.xmlId = xmlId;
}
//must be provided
public PreferenceListFragment(){

}

[MENTION=439709]override[/MENTION]
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle b){
postBindPreferences();
return lv;
}

[MENTION=439709]override[/MENTION]
public void onDestroyView(){
super.onDestroyView();
ViewParent p = lv.getParent();
if(p != null)
((ViewGroup)p).removeView(lv);
}

[MENTION=439709]override[/MENTION]
public void onCreate(Bundle b) {
super.onCreate(b);
if(b != null)
xmlId = b.getInt("xml");
mPreferenceManager = onCreatePreferenceManager();
lv = (ListView) LayoutInflater.from(getActivity()).inflate(R.layout.preference_list_content, null);
lv.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
addPreferencesFromResource(xmlId);
postBindPreferences();
((OnPreferenceAttachedListener)getActivity()).onPreferenceAttached(getPreferenceScreen(), xmlId);
}

[MENTION=439709]override[/MENTION]
public void onStop(){
super.onStop();
try{
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityStop");
m.setAccessible(true);
m.invoke(mPreferenceManager);
}catch(Exception e){
e.printStackTrace();
}
}

[MENTION=439709]override[/MENTION]
public void onDestroy() {
super.onDestroy();
lv = null;
try{
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityDestroy");
m.setAccessible(true);
m.invoke(mPreferenceManager);
}catch(Exception e){
e.printStackTrace();
}
}

[MENTION=439709]override[/MENTION]
public void onSaveInstanceState(Bundle outState) {
outState.putInt("xml", xmlId);
super.onSaveInstanceState(outState);

}

[MENTION=439709]override[/MENTION]
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
try{
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityResult", int.class, int.class, Intent.class);
m.setAccessible(true);
m.invoke(mPreferenceManager, requestCode, resultCode, data);
}catch(Exception e){
e.printStackTrace();
}
}

/**
* Posts a message to bind the preferences to the list view.
* <p>
* Binding late is preferred as any custom preference types created in
* {@link #onCreate(Bundle)} are able to have their views recycled.
*/
private void postBindPreferences() {
if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
}

private void bindPreferences() {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
preferenceScreen.bind(lv);
}
}

/**
* Creates the {@link PreferenceManager}.
*
* [MENTION=2056652]return[/MENTION] The {@link PreferenceManager} used by this activity.
*/
private PreferenceManager onCreatePreferenceManager() {
try{
Constructor<PreferenceManager> c = PreferenceManager.class.getDeclaredConstructor(Activity.class, int.class);
c.setAccessible(true);
PreferenceManager preferenceManager = c.newInstance(this.getActivity(), FIRST_REQUEST_CODE);
return preferenceManager;
}catch(Exception e){
e.printStackTrace();
return null;
}
}

/**
* Returns the {@link PreferenceManager} used by this activity.
* [MENTION=2056652]return[/MENTION] The {@link PreferenceManager}.
*/
public PreferenceManager getPreferenceManager() {
return mPreferenceManager;
}

/**
* Sets the root of the preference hierarchy that this activity is showing.
*
* [MENTION=955119]param[/MENTION] preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
*/
public void setPreferenceScreen(PreferenceScreen preferenceScreen){
try{
Method m = PreferenceManager.class.getDeclaredMethod("setPreferences", PreferenceScreen.class);
m.setAccessible(true);
boolean result = (Boolean) m.invoke(mPreferenceManager, preferenceScreen);
if (result && preferenceScreen != null) {
postBindPreferences();
}
}catch(Exception e){
e.printStackTrace();
}
}

/**
* Gets the root of the preference hierarchy that this activity is showing.
*
* [MENTION=2056652]return[/MENTION] The {@link PreferenceScreen} that is the root of the preference
* hierarchy.
*/
public PreferenceScreen getPreferenceScreen(){
try{
Method m = PreferenceManager.class.getDeclaredMethod("getPreferenceScreen");
m.setAccessible(true);
return (PreferenceScreen) m.invoke(mPreferenceManager);
}catch(Exception e){
e.printStackTrace();
return null;
}
}

/**
* Adds preferences from activities that match the given {@link Intent}.
*
* [MENTION=955119]param[/MENTION] intent The {@link Intent} to query activities.
*/
public void addPreferencesFromIntent(Intent intent) {
throw new RuntimeException("too lazy to include this bs");
}

/**
* Inflates the given XML resource and adds the preference hierarchy to the current
* preference hierarchy.
*
* [MENTION=955119]param[/MENTION] preferencesResId The XML resource ID to inflate.
*/
public void addPreferencesFromResource(int preferencesResId) {
try{
Method m = PreferenceManager.class.getDeclaredMethod("inflateFromResource", Context.class, int.class, PreferenceScreen.class);
m.setAccessible(true);
PreferenceScreen prefScreen = (PreferenceScreen) m.invoke(mPreferenceManager, getActivity(), preferencesResId, getPreferenceScreen());
setPreferenceScreen(prefScreen);
}catch(Exception e){
e.printStackTrace();
}
}

/**
* Finds a {@link Preference} based on its key.
*
* [MENTION=955119]param[/MENTION] key The key of the preference to retrieve.
* [MENTION=2056652]return[/MENTION] The {@link Preference} with the key, or null.
* [MENTION=690402]see[/MENTION] PreferenceGroup#findPreference(CharSequence)
*/
public Preference findPreference(CharSequence key) {
if (mPreferenceManager == null) {
return null;
}
return mPreferenceManager.findPreference(key);
}

public interface OnPreferenceAttachedListener{
public void onPreferenceAttached(PreferenceScreen root, int xmlId);
}

}

How to use:

public class Settings extends FragmentActivity implements OnPreferenceAttachedListener, OnPreferenceChangeListener, OnPreferenceClickListener{
private Preference filterPref;
private ViewPager viewPager;

public void onCreate(Bundle b){
super.onCreate(b);
setContentView(R.layout.settings);
viewPager = (ViewPager) findViewById(R.id.pager);
PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager(), this);
viewPager.setAdapter(adapter);

TitlePageIndicator titleIndicator = (TitlePageIndicator) findViewById(R.id.titles);
titleIndicator.setViewPager(viewPager);
titleIndicator.setFooterIndicatorStyle(IndicatorStyle.Underline);

viewPager.setCurrentItem(1);

}

//setup your onPreferenceClickListener/onPreferenceChangeListener here
[MENTION=439709]override[/MENTION]
public void onPreferenceAttached(PreferenceScreen root, int xmlId){
if(root == null)
return; //for whatever reason in very rare cases this is null
if(xmlId == R.xml.widget_settings){ //example id
root.findPreference("somePreference").setOnPreferenceClickListener(this);
}
}

//handle your preferenceChanged events here (if needed)
[MENTION=439709]override[/MENTION]
public boolean onPreferenceChange(Preference preference, Object newValue) {
return true;
}

//handle your preferenceClick events here (if needed)
[MENTION=439709]override[/MENTION]
public boolean onPreferenceClick(Preference pref){
return true;
}

}

and the adapter I am using:

public class PagerAdapter extends FragmentPagerAdapter implements TitleProvider{

PreferenceListFragment[] fragments;
String[] titles;

public PagerAdapter(FragmentManager fm, Context context) {
super(fm);
fragments = new PreferenceListFragment[4];
fragments[0] = new PreferenceListFragment(R.xml.settings);
fragments[1] = new PreferenceListFragment(R.xml.widget_settings);
fragments[2] = new PreferenceListFragment(R.xml.s_widget_settings);
fragments[3] = new PreferenceListFragment(R.xml.color_settings);

titles = new String[4];
titles[0] = context.getString(R.string.main_settings);
titles[1] = context.getString(R.string.widget_settings);
titles[2] = context.getString(R.string.s_widget_settings);
titles[3] = context.getString(R.string.color_settings_main);

}

[MENTION=439709]override[/MENTION]
public Fragment getItem(int position){
return fragments[position];
}

[MENTION=439709]override[/MENTION]
public int getCount() {
return fragments.length;
}

[MENTION=439709]override[/MENTION]
public String getTitle(int position) {
return titles[position];
}

}

Lastly you will need this xml file: preference_list_content.xml (belongs into /res/layout/) (pulled from aosp)

<?xml version="1.0" encoding="utf-8"?>
<!--
/* //device/apps/common/assets/res/layout/list_content.xml
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:drawSelectorOnTop="false"
android:scrollbarAlwaysDrawVerticalTrack="true"
/>