Android’s PreferenceActivity for all API versions

简介: Android’s PreferenceActivity for all API versions

官方文档


I have spent the last few days learning about how to use the new Android PreferenceFragment which requires PreferenceActivity to override a new v11 (Honeycomb) method called onBuildHeaders(). Unfortunately, the documentation is not very clear how one would create a single PreferenceActivity that could play well in all versions, utilizing the newest features if you have it and avoiding an app crash on older Android versions. I encountered several solutions to this issue by creating two different activities for the two different mechanisms requiring two entries in your AndroidManifest.xml file. Having two different PreferenceActivities means if you have library code that extends that class, you now have to duplicate it. Then, if your app descends your library class, now has to be duplicated yet again. The end result is … less than ideal.


Thankfully, after spending a great deal of time on the subject, I have come up with a single class solution that will work in all Android versions. A couple of the newer methods need to be found using reflection and based off of them, in addition to using the newly introduced xml file of , allow for a single class solution.


First, take your old xml layouts and break them up into several files based on how you would like to see them categorized using the new header format. Simply breaking them apart so that each PreferenceCategory has its own file is a good start. For our example here, we shall assume there are 3 such files, all in the res/xml folder: app_prefs_cat1.xml, app_prefs_cat2.xml, and app_prefs_cat3.xml


Now let us create the descendant PrefsActivity class:


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
public class PrefsActivity extends PreferenceActivity {
    protected Method mLoadHeaders = null;
    protected Method mHasHeaders = null;
    /**
     * Checks to see if using new v11+ way of handling PrefsFragments.
     * @return Returns false pre-v11, else checks to see if using headers.
     */
    public boolean isNewV11Prefs() {
        if (mHasHeaders!=null && mLoadHeaders!=null) {
            try {
                return (Boolean)mHasHeaders.invoke(this);
            } catch (IllegalArgumentException e) {
            } catch (IllegalAccessException e) {
            } catch (InvocationTargetException e) {
            }
        }
        return false;
    }
    @Override
    public void onCreate(Bundle aSavedState) {
        //onBuildHeaders() will be called during super.onCreate()
        try {
            mLoadHeaders = getClass().getMethod("loadHeadersFromResource", int.class, List.class );
            mHasHeaders = getClass().getMethod("hasHeaders");
        } catch (NoSuchMethodException e) {
        }
        super.onCreate(aSavedState);
        if (!isNewV11Prefs()) {
            addPreferencesFromResource(R.xml.app_prefs_cat1);
            addPreferencesFromResource(R.xml.app_prefs_cat2);
            addPreferencesFromResource(R.xml.app_prefs_cat3);
        }
    }
    @Override
    public void onBuildHeaders(List<Header> aTarget) {
        try {
            mLoadHeaders.invoke(this,new Object[]{R.xml.pref_headers,aTarget});
        } catch (IllegalArgumentException e) {
        } catch (IllegalAccessException e) {
        } catch (InvocationTargetException e) {
        }   
    }
    static public class PrefsFragment extends PreferenceFragment {
        @Override
        public void onCreate(Bundle aSavedState) {
            super.onCreate(aSavedState);
            Context anAct = getActivity().getApplicationContext();
            int thePrefRes = anAct.getResources().getIdentifier(getArguments().getString("pref-resource"),
                    "xml",anAct.getPackageName());
            addPreferencesFromResource(thePrefRes);
        }
    }
}

On older Android versions, the reflected methods will be null and thus avoids calling the newer methods, using the older mechanism of adding the various preference xml files in onCreate(). In order to use the new Honeycomb (v11+) preference mechanism, we need to create one more xml file – the newer <preference-headers> xml file that ties all the category files together. The res/xml resource file “pref_headers.xml”:

<?xml version="1.0" encoding="utf-8"?>
<preference-headers
    xmlns:android="http://schemas.android.com/apk/res/android" >
<header android:fragment="my.domain.app.PrefsActivity$PrefsFragment"
    android:icon="@android:drawable/ic_menu_sort_by_size"
    android:title="Category 1 prefs" >
    <extra android:name="pref-resource" android:value="app_prefs_cat1" />
</header>        
<header android:fragment="my.domain.app.PrefsActivity$PrefsFragment"
    android:icon="@android:drawable/ic_menu_gallery"
    android:title="Category 2 prefs" >
    <extra android:name="pref-resource" android:value="app_prefs_cat2" />
</header>
<header android:fragment="my.domain.app.PrefsActivity$PrefsFragment"
    android:icon="@android:drawable/ic_menu_edit"
    android:title="Category 3 prefs" >
    <extra android:name="pref-resource" android:value="app_prefs_cat3" />
</header>
<header
    android:icon="@drawable/icon_question"
    android:title="Blackmoon Info Tech Services"
    android:summary="link to BITS blog">
    <intent android:action="android.intent.action.VIEW"
            android:data="http://www.blackmoonit.com/2012/07/all_api_prefsactivity/" />
</header>
</preference-headers>


The first three headers list the three standard category xml files we created, but you are also free to add more items as you see fit, just remember that those will only be visible on devices with Android 3.0 or later.


Now that we have our xml file and single preference activity, we can define it in our AndroidManifest.xml as usual. Note: do not use android:launchMode=”singleTop” for your prefs activity or else it will break phones using 4.0+ by never showing more than just the header list.

<activity android:name="PrefsActivity"
        android:label="Settings"
        android:enabled="true" >
        <intent-filter>
            <category android:name="android.intent.category.PREFERENCE" />
        </intent-filter>
    </activity>

We can have a menu call our prefs activity with just one line:

startActivity(new Intent(this, PrefsActivity.class);

Now that you have a descendant class like this one, you can freely use it in all versions of Android and it will automatically use the newer mechanism where appropriate.

查看这里

相关文章
|
6月前
|
Android开发
Android 11 修改libcore update-api 遇到的问题
Android 11 修改libcore update-api 遇到的问题
172 1
|
定位技术 API 开发工具
Android 按照步骤接入百度地图API,定位显示不了解决办法
Android 按照步骤接入百度地图API,定位显示不了解决办法
378 1
|
3月前
|
编译器 API Android开发
Android经典实战之Kotlin Multiplatform 中,如何处理不同平台的 API 调用
本文介绍Kotlin Multiplatform (KMP) 中使用 `expect` 和 `actual` 关键字处理多平台API调用的方法。通过共通代码集定义预期API,各平台提供具体实现,编译器确保正确匹配,支持依赖注入、枚举类处理等,实现跨平台代码重用与原生性能。附带示例展示如何定义跨平台函数与类。
107 0
|
5月前
|
API Android开发 开发者
`RecyclerView`是Android API 21引入的UI组件,用于替代ListView和GridView
【6月更文挑战第26天】`RecyclerView`是Android API 21引入的UI组件,用于替代ListView和GridView。它提供高效的数据视图复用,优化的布局管理,支持多种布局(如线性、网格),并解耦数据、适配器和视图。RecyclerView的灵活性、性能(如局部刷新和动画支持)和扩展性使其成为现代Android开发的首选,特别是在处理大规模数据集时。
65 2
|
5月前
|
Java Linux API
微信API:探究Android平台下Hook技术的比较与应用场景分析
微信API:探究Android平台下Hook技术的比较与应用场景分析
|
6月前
|
SQL API Android开发
Android API:Activity.managedQuery()
Android API:Activity.managedQuery()
48 2
|
6月前
|
API Android开发
Android Framework增加API 报错 Missing nullability on parameter
Android Framework增加API 报错 Missing nullability on parameter
331 1
|
6月前
|
API 定位技术 开发工具
Android Studio2021.1.1 高德地图api调用这一篇就够了
Android Studio2021.1.1 高德地图api调用这一篇就够了
|
6月前
|
API Android开发
对于应用研发平台EMAS中安卓 API 32 收不到 FCM 推送的问题
对于应用研发平台EMAS中安卓 API 32 收不到 FCM 推送的问题
106 3
|
API Android开发
mPaaS(移动跨平台框架)目前已经支持了Android API级别21
mPaaS(移动跨平台框架)目前已经支持了Android API级别21
146 2
下一篇
无影云桌面