PreferenceActivity Android 4.0 及更早版本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10186697/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 02:48:35  来源:igfitidea点击:

PreferenceActivity Android 4.0 and earlier

androidpreferenceactivity

提问by just_user

Trying the different preference activities in the ApiDemos for Android 4.0, I see in the code that some methods are deprecated in PreferencesFromCode.java, for example.

在 Android 4.0 的 ApiDemos 中尝试不同的偏好活动,我在代码中看到一些方法在 PreferencesFromCode.java 中被弃用,例如。

So my question is: if I use PreferenceFragment, will it work for all version or only 3.0 or 4.0 and up?

所以我的问题是:如果我使用 PreferenceFragment,它是否适用于所有版本或仅适用于 3.0 或 4.0 及更高版本?

If so, what should I use that works for 2.2 and 2.3 as well?

如果是这样,我应该使用什么也适用于 2.2 和 2.3?

回答by Leo

PreferenceFragmentwill not work on 2.2 and 2.3 (only API level 11 and above). If you want to offer the best user experience and still support older Android versions, the best practice here seems to be to implement two PreferenceActivityclasses and to decide at runtime which one to invoke. However, this method still includes calling deprecated APIs, but you can't avoid that.

PreferenceFragment不适用于 2.2 和 2.3(仅 API 级别 11 及以上)。如果你想提供最好的用户体验并仍然支持旧的 Android 版本,这里的最佳实践似乎是实现两个PreferenceActivity类并在运行时决定调用哪一个。但是,此方法仍然包括调用已弃用的 API,但您无法避免这种情况。

So for instance, you have a preference_headers.xml:

例如,您有一个preference_headers.xml

<preference-headers xmlns:android="http://schemas.android.com/apk/res/android" > 
    <header android:fragment="your.package.PrefsFragment" 
        android:title="...">
        <extra android:name="resource" android:value="preferences" />
    </header>
</preference-headers>

and a standard preferences.xml(which hasn't changed much since lower API levels):

和一个标准preferences.xml(自从降低 API 级别后没有太大变化):

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:title="...">
    ...
</PreferenceScreen>

Then you need an implementation of PreferenceFragment:

然后你需要一个实现PreferenceFragment

public static class PrefsFragment extends PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
    }
}

And finally, you need two implementations of PreferenceActivity, for API levels supporting or not supporting PreferenceFragments:

最后,PreferenceActivity对于支持或不支持的 API 级别,您需要 , 的两个实现PreferenceFragments

public class PreferencesActivity extends PreferenceActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
        addPreferencesFromResource(R.xml.other);
    }
}

and:

和:

public class OtherPreferencesActivity extends PreferenceActivity {
    @Override
    public void onBuildHeaders(List<Header> target) {
        loadHeadersFromResource(R.xml.preference_headers, target);
    }
}

At the point where you want to display the preference screen to the user, you decide which one to start:

在您希望向用户显示首选项屏幕时,您决定从哪个开始:

if (Build.VERSION.SDK_INT < 11) {
    startActivity(new Intent(this, PreferencesActivity.class));
} else {
    startActivity(new Intent(this, OtherPreferencesActivity.class));
}

So basically, you have an xml file per fragment, you load each of these xml files manually for API levels < 11, and both Activities use the same preferences.

所以基本上,每个片段都有一个 xml 文件,您为 API 级别 < 11 手动加载这些 xml 文件中的每一个,并且两个活动使用相同的首选项。

回答by Uncle Code Monkey

@Mef Your answer can be simplified even more so that you do not need both of the PreferencesActivity and OtherPreferencesActivity (having 2 PrefsActivities is a PITA).

@Mef您的答案可以进一步简化,这样您就不需要 PreferencesActivity 和 OtherPreferencesActivity (有 2 个 PrefsActivities 是一个 PITA)。

I have found that you can put the onBuildHeaders() method into your PreferencesActivity and no errors will be thrown by Android versions prior to v11. Having the loadHeadersFromResource() inside the onBuildHeaders did not throw and exception on 2.3.6, but did on Android 1.6. After some tinkering though, I found the following code will work in all versions so that only one activity is required (greatly simplifying matters).

我发现您可以将 onBuildHeaders() 方法放入 PreferencesActivity 中,v11 之前的 Android 版本不会抛出任何错误。在 onBuildHeaders 中使用 loadHeadersFromResource() 并没有在 2.3.6 上抛出异常,但在 Android 1.6 上有。但是经过一些修补后,我发现以下代码适用于所有版本,因此只需要一项活动(大大简化了问题)。

public class PreferencesActivity extends PreferenceActivity {
    protected Method mLoadHeaders = null;
    protected Method mHasHeaders = null;

    /**
     * Checks to see if using new v11+ way of handling PrefFragments.
     * @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.preferences);
            addPreferencesFromResource(R.xml.other);
        }
    }

    @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) {
        }   
    }
}

This way you only need one activity, one entry in your AndroidManifest.xml and one line when you invoke your preferences:

这样你只需要一个活动,在你的 AndroidManifest.xml 中的一个条目和你调用首选项时的一行:

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

UPDATE Oct 2013: Eclipse/Lint will warn you about using the deprecated method, but just ignore the warning. We are using the method only when we have to, which is whenever we do not have v11+ style preferences and must use it, which is OK. Do not be frightened about Deprecated code when you have accounted for it, Android won't remove deprecated methods anytime soon. If it ever did occur, you won't even need this class anymore as you would be forced to only target newer devices. The Deprecated mechanism is there to warn you that there is a better way to handle something on the latest API version, but once you have accounted for it, you can safely ignore the warning from then on. Removing all calls to deprecated methods would only result in forcing your code to only run on newer devices — thus negating the need to be backward compatible at all.

2013 年 10 月更新:Eclipse/Lint 将警告您使用已弃用的方法,但只需忽略该警告。我们只在必须的时候使用该方法,也就是当我们没有 v11+ 样式偏好并且必须使用它时,这没关系。考虑到弃用代码后不要害怕,Android 不会很快删除弃用的方法。如果确实发生过,您甚至不再需要此类,因为您将被迫仅针对较新的设备。Deprecated 机制是为了警告您在最新的 API 版本上有更好的方法来处理某些事情,但是一旦您考虑到它,您就可以安全地忽略该警告。

回答by scottyab

There's a newish libthat might help.

有一个新的库可能会有所帮助。

UnifiedPreference is a library for working with all versions of the Android Preference package from API v4 and up.

UnifiedPreference 是一个库,用于处理 API v4 及更高版本的所有版本的 Android Preference 包。

回答by David Vávra

Problem with previous answers is that it will stack all preferences to a single screen on pre-Honecomb devices (due to multiple calls of addPreferenceFromResource()).

先前答案的问题在于,它会将所有首选项堆叠到 Honecomb 之前的设备上的单个屏幕上(由于多次调用addPreferenceFromResource())。

If you need first screen as list and then the screen with preferences (such as using preference headers), you should use Official guide to compatible preferences

如果您需要第一个屏幕作为列表,然后是带有首选项的屏幕(例如使用首选项标题),您应该使用官方指南来兼容首选项

回答by EnzoAtari

I wanted to point out that if you start at http://developer.android.com/guide/topics/ui/settings.html#PreferenceHeadersand work your way down to the section for "Supporting older versions with preference headers" it will make more sense. The guide there is very helpful and does work well. Here's an explicit example following their guide:

我想指出的是,如果您从http://developer.android.com/guide/topics/ui/settings.html#PreferenceHeaders开始,然后逐步进入“支持具有首选项标头的旧版本”部分,它将更有意义。那里的指南非常有帮助,而且效果很好。这是遵循他们的指南的明确示例:

So start with file preference_header_legacy.xmlfor android systems before HoneyComb

所以从HoneyComb之前的android系统文件preference_header_legacy.xml开始

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<Preference 
    android:title="OLD Test Title"
    android:summary="OLD Test Summary"  >
    <intent 
        android:targetPackage="example.package"
        android:targetClass="example.package.SettingsActivity"
        android:action="example.package.PREFS_ONE" />
</Preference>

Next create file preference_header.xmlfor android systems with HoneyComb+

接下来使用 HoneyComb+ 为 android 系统创建文件首选项

<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<header 
    android:fragment="example.package.SettingsFragmentOne"
    android:title="NEW Test Title"
    android:summary="NEW Test Summary" />
</preference-headers>

Next create a preferences.xmlfile to hold your preferences...

接下来创建一个首选项.xml文件来保存您的首选项...

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
        <CheckBoxPreference
        android:key="pref_key_auto_delete"
        android:summary="@string/pref_summary_auto_delete"
        android:title="@string/pref_title_auto_delete"
        android:defaultValue="false" />
</PreferenceScreen>

Next create the file SettingsActivity.java

接下来创建文件SettingsActivity.java

package example.project;
import java.util.List;
import android.annotation.SuppressLint;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceActivity;

public class SettingsActivity extends PreferenceActivity{
final static String ACTION_PREFS_ONE = "example.package.PREFS_ONE";

@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    String action = getIntent().getAction();
    if (action != null && action.equals(ACTION_PREFS_ONE)) {
        addPreferencesFromResource(R.xml.preferences);
    }
    else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
        // Load the legacy preferences headers
        addPreferencesFromResource(R.xml.preference_header_legacy);
    }
}

@SuppressLint("NewApi")
@Override
public void onBuildHeaders(List<Header> target) {
    loadHeadersFromResource(R.xml.preference_header, target);
}
}

Next create the class SettingsFragmentOne.java

接下来创建类SettingsFragmentOne.java

package example.project;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.preference.PreferenceFragment;

@SuppressLint("NewApi")
public class SettingsFragmentOne extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.preferences);
}
}

AndroidManifest.xml, added this block between my <application>tags

AndroidManifest.xml,在我的<application>标签之间添加了这个块

<activity 
   android:label="@string/app_name"
   android:name="example.package.SettingsActivity"
   android:exported="true">
</activity>

and finally, for the <wallpaper>tag...

最后,对于<wallpaper>标签......

<wallpaper xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/description"
android:thumbnail="@drawable/ic_thumbnail"
android:settingsActivity="example.package.SettingsActivity"
/>

回答by theblang

I am using this library, which has an AARin mavenCentralso you can easily include it if you are using Gradle.

我正在使用这个库,它有一个AARin,mavenCentral所以如果你使用Gradle.

compile 'com.github.machinarius:preferencefragment:0.1.1'

compile 'com.github.machinarius:preferencefragment:0.1.1'