在PreferenceActivity中使用什么代替“ addPreferencesFromResource”?


360

我刚刚注意到一个事实,该方法在Android文档(参考条目)中addPreferencesFromResource(int preferencesResId)被标记为已弃用

不幸的是,该方法的说明中没有提供替代方法。

为了将preferenceScreen.xml连接到匹配的PreferenceActivity,应该使用哪种方法呢?



那里的解决方案仍然使用addPreferencesFromResource(int preferencesResId)。我想念什么吗?
Jammo 2015年

@Jammo是的,但已将其从“活动”移至“片段”以反映执行此操作的新方法->“片段”。
WannaGetHigh 2015年

Answers:


332

方法的描述中未提供任何替代方法,因为首选方法(从API级别11开始)是实例化PreferenceFragment对象,以从资源文件加载您的首选项。请参阅此处的示例代码:PreferenceActivity


非常感谢您的回答。我只是遵循“ Video2Brain-Android开发”中不推荐使用的说明,这使我不得不使用PreferenceActivity的方法版本。顺便说一句:如果可能的话,我想将您的回答评为有用。
mweisz 2011年

33
现在,仅当兼容性包中包含PreferenceFragment时,才有意义使用它 stackoverflow.com/questions/5501431/...
克里斯托夫

1
由于我使用Action Bar Sherlock,因此我关注了以下博客来解决此问题,请参阅... commonsware.com/blog/2012/10/16/…
某处某人

2
如果您希望应用程序向后兼容api级别低于11(Android 3.0)的api,则仍然需要调用addPreferencesFromResource(int PreferencesID)。但是我想您也可以考虑淘汰那些旧设备。
Einar Sundgren

5
@EinarSundgren我是Nexus One所有者,我的最高可用版本是2.2:您不会阻止我!我永远不会被弃用!通过Grayskull的力量...我拥有力量!
TechNyquist

186

为了向上面的正确答案添加更多信息,在阅读了Android-er示例后,我发现您可以轻松地将您的偏好活动转换为偏好片段。如果您有以下活动:

public class MyPreferenceActivity extends PreferenceActivity
{
    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.my_preference_screen);
    }
}

您要做的唯一更改是创建一个内部片段类,将其addPreferencesFromResources()移入片段,然后从活动中调用片段,如下所示:

public class MyPreferenceActivity extends PreferenceActivity
{
    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit();
    }

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

从片段中选择更复杂的首选项可能还有其他一些细微之处。如果是这样,我希望有人在这里注明。


6
很好,谢谢你。Java和这种类型的思考与我的小.net世界相去甚远:)
汤姆(Tom)

44
他们为什么会addPreferencesFromResources()在PreferenceFragment的交易中贬值?从初学者的角度看,它看起来是不必要的。
Howdy_McGee

4
通话需要API级别11
mehmet

1
那么如果API处于第9级呢?@mehmet
gumuruh 2014年

2
很棒的答案!有没有一种方法可以实现而无需更改android.R.id.content?出于某种原因似乎对我不雅...(如果我做错了,请纠正我)
tomer.z 2014年

37

@Garret Wilson非常感谢!作为android编码的新手,我一直困扰着首选项不兼容问题达数小时之久,但令我失望的是,他们不赞成将某些方法/方法用于较旧的API不支持的新方法/方法必须采取各种变通办法来使您的应用在各种设备上运行。真令人沮丧!

您的课程很棒,因为它使您可以按照喜好使用新的API继续使用新的API,但它不是向后兼容的。由于我尝试使用多种设备,因此我对其进行了一些修补,以使其能够在API 11之前的设备以及较新的API中运行:

import android.annotation.TargetApi;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;

public class MyPrefsActivity extends PreferenceActivity
{
    private static int prefs=R.xml.myprefs;

    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        try {
            getClass().getMethod("getFragmentManager");
            AddResourceApi11AndGreater();
        } catch (NoSuchMethodException e) { //Api < 11
            AddResourceApiLessThan11();
        }
    }

    @SuppressWarnings("deprecation")
    protected void AddResourceApiLessThan11()
    {
        addPreferencesFromResource(prefs);
    }

    @TargetApi(11)
    protected void AddResourceApi11AndGreater()
    {
        getFragmentManager().beginTransaction().replace(android.R.id.content,
                new PF()).commit();
    }

    @TargetApi(11)
    public static class PF extends PreferenceFragment
    {       
        @Override
        public void onCreate(final Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(MyPrefsActivity.prefs); //outer class
            // private members seem to be visible for inner class, and
            // making it static made things so much easier
        }
    }
}

在两个仿真器(2.2和4.2)中测试成功。

为什么我的代码如此糟糕:

我是android编码的菜鸟,我不是最伟大的Java迷。

为了避免过时的警告并迫使Eclipse允许我进行编译,我不得不诉诸于注释,但是注释似乎只影响类或方法,因此我不得不将代码移至两个新方法上以利用此注释。

我不想每次将类复制并粘贴到新的PreferenceActivity时都必须两次写入xml资源ID,所以我创建了一个新变量来存储此值。

我希望这对其他人有用。

PS:对不起,我的观点是对的,但是,当您初来乍到并发现此类障碍时,您会无奈地感到沮丧!


哦,好吧……我只是注意到我每次复制粘贴时都必须两次更改外部类名称。实际上,可以通过将prefs传递给innerclass来避免这种情况。您可能不会创建接受prefs作为参数的内部类构造函数,因为显然不建议将其用于PreferenceFragment派生类。同样,您可能无法在内部类中创建方法来获取偏好并立即调用addPreferencesFromResource,因为需要在调用super.onCreate之后调用addPreferencesFromResource,而在PreferenceFragment派生类具有调用之后就不会立即调用onCreate ...
ecv

...被实例化。因此,您需要在内部类中创建一个新变量,在内部类中为其创建一个公共设置方法,在调用super.onCreate之后在onCreate内实例化内部类,设置prefs之后将addPreferencesFromResource保留在该位置,并像以前一样在调用getFragmentManager()...中使用它。
ecv

2
您的代码已成为救命稻草!!我试图同时定位新旧手机,浪费了3天。答案很简单。谢谢
Devdatta Tengshe

22

我的方法非常接近Garret Wilson的方法(谢谢,我投票赞成;)

此外,它还提供与Android <3的向下兼容性。

我刚刚意识到我的解决方案更接近Kevin Remo的解决方案。它只是一点点的清洁(因为它不依赖于“ expection”反模式)。

public class MyPreferenceActivity extends PreferenceActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            onCreatePreferenceActivity();
        } else {
            onCreatePreferenceFragment();
        }
    }

    /**
     * Wraps legacy {@link #onCreate(Bundle)} code for Android < 3 (i.e. API lvl
     * < 11).
     */
    @SuppressWarnings("deprecation")
    private void onCreatePreferenceActivity() {
        addPreferencesFromResource(R.xml.preferences);
    }

    /**
     * Wraps {@link #onCreate(Bundle)} code for Android >= 3 (i.e. API lvl >=
     * 11).
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void onCreatePreferenceFragment() {
        getFragmentManager().beginTransaction()
                .replace(android.R.id.content, new MyPreferenceFragment ())
                .commit();
    }
}

有关“真实”(但更复杂)的示例,请参见NusicPreferencesActivityNusicPreferencesFragment


@SuppressLint("NewApi")-避免-更精确。您是否针对低API运行它?它将抛出VerifyError
Mr_and_Mrs_D 2013年

我在运行API级别10的模拟器上测试了以上内容,该APK是使用SDK版本19构建的。您使用哪个SDK版本构建的?您在哪个设备API级别上运行它?您是在模拟器上还是在物理设备上运行它?错误何时发生?如果Ur用SDK <= 16构建,请参阅此响应
schnatterer 2014年

您错过了要点-如果您想通知我,请添加@Mr_and_Mrs_D。对于VE,请阅读此处:stackoverflow.com/questions/20271593/…。这@SuppressLint("NewApi")只是不好的风格
Mr_and_Mrs_D 2014年

@M那么,关于@SuppressLint("NewApi")在这种特殊情况下如何避免的建议呢?
schnatterer 2014年

@TargetApi(Build.VERSION_CODES.HONEYCOMB)-并非所有api都有所有警告:)
Mr_and_Mrs_D 2014年

6

除了使用例外,还可以使用:

if (Build.VERSION.SDK_INT >= 11)

和使用

@SuppressLint("NewApi")

禁止显示警告。


1
因为它除了崩溃外没有其他作用:D
Ishtiaq 2014年

1
如果它崩溃了...那么尝试并抓住它:D
gumuruh 2014年

0

除了使用PreferenceActivity直接加载首选项外,还可以使用AppCompatActivity或等效的PreferenceFragmentCompat加载首选项来加载首选项。它是支持库(现在为Android Jetpack)的一部分,并提供与API 14的兼容性。

在您的中build.gradle,为首选项支持库添加一个依赖项:

dependencies {
    // ...
    implementation "androidx.preference:preference:1.0.0-alpha1"
}

注意:我们将假设您已经创建了首选项XML。

对于您的活动,创建一个新的活动类。如果您使用的是实质性主题,则应扩展一个AppCompatActivity,但是您可以通过以下方式灵活使用:

public class MyPreferencesActivity extends AppCompatActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_preferences_activity)
        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragment_container, MyPreferencesFragment())
                    .commitNow()
        }
    }
}

现在到重要部分:创建一个片段,从XML加载您的首选项:

public class MyPreferencesFragment extends PreferenceFragmentCompat {

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.my_preferences_fragment); // Your preferences fragment
    }
}

欲了解更多信息,请阅读Android开发者文档PreferenceFragmentCompat

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.