AndroidX前后DialogPreference的区别

Difference between DialogPreference before and after AndroidX

我们目前正在将我们的 Android 应用程序项目迁移到 Androidx 命名空间。但是我注意到不仅名称空间似乎发生了变化。对于 DialogPreference,现在还缺少一些以前使用的接口

例如,似乎缺少以下方法:onBindDialogView、showDialog、onDialogClosed。

由于我们使用其中一些方法来影响对话框的默认行为,所以我不清楚现在应该如何实现此功能。例如,我们在关闭对话框之前验证输入,我们将值保存在数据库中而不是共享首选项中,并向对话框添加一些动态元素。

有没有其他人遇到过这个问题并找到了解决方案?我错过了文档中的任何内容吗?我们可以/应该使用另一个概念吗?

可以使用 Fragments 而不是 DialogPreference,但是对于少量内容(例如,用户可以从中选择的树项目列表),这对我来说似乎是一个很大的开销...

从 androidx 源文件开始,我已将基于旧 DialogPreference 的自定义 classes 迁移到新 androidx.preference.DialogPreference 使用以下程序:

第 1 步

基于旧版 DialogPreference 的旧自定义对话框 class(例如 CustomDialogPreference)应拆分为两个单独的 classes:

  1. 一个 class(例如 CustomPreference)应该扩展 androidx.preference.DialogPreference 并且只包含与偏好处理(数据管理)相关的代码。
  2. 另一个 class(例如 CustomDialog)应该扩展 androidx.preference.PreferenceDialogFragmentCompat 并且将只包含与对话框处理(用户界面)相关的代码,包括 onDialogClosed。此 class 应将静态方法 newInstance 公开给 return 此 class.
  3. 的实例

第 2 步

在基于 PreferenceFragmentCompat 的主要片段处理首选项中,应覆盖 onDisplayPreferenceDialog 方法以显示自定义对话框,例如:

    private static final String DIALOG_FRAGMENT_TAG = "CustomPreference";

    @Override
    public void onDisplayPreferenceDialog(Preference preference) {
        if (getParentFragmentManager().findFragmentByTag(DIALOG_FRAGMENT_TAG) != null) {
            return;
        }

        if (preference instanceof CustomPreference) {
            final DialogFragment f = CustomDialog.newInstance(preference.getKey());
            f.setTargetFragment(this, 0);
            f.show(getParentFragmentManager(), DIALOG_FRAGMENT_TAG);
        } else {
            super.onDisplayPreferenceDialog(preference);
        }
    }

对于(像我一样)不完全理解我们应该如何结合 androidx.preference.DialogPreferenceandroidx.preference.PreferenceDialogFragmentCompat 的每个人的小窍门:

第 1 步:

在你的 DialogFragmentonAttach() 方法中获取你想要的 SharedPreference 的值(从 newInstance() 方法获取密钥或者只是在里面硬核它)和将其保存为变量。另一方面,在关闭 DialogFragment 之前将新值保存在 SharedPreference 中。通过这样做,您已经创建了 "custom Preference"。

第 2 步:

创建空 androidx.preference.DialogPreference 并在您的 PreferenceScreen 中使用它。然后将它与您的 DialogFragment 结合起来,如@Livio 在第二步中所述:

private static final String DIALOG_FRAGMENT_TAG = "CustomPreference";

@Override
public void onDisplayPreferenceDialog(Preference preference) {
    if (getFragmentManager().findFragmentByTag(DIALOG_FRAGMENT_TAG) != null) {
        return;
    }

    if (preference instanceof CustomPreference) {
        final DialogFragment f = CustomDialog.newInstance(preference.getKey());
        f.setTargetFragment(this, 0);
        f.show(getFragmentManager(), DIALOG_FRAGMENT_TAG);
    } else {
        super.onDisplayPreferenceDialog(preference);
    }
}

通过这样做,您将获得相同的结果,唯一不同的是您需要在 DialogFragment.

中自己处理 SharedPreference

您可以使用 AlertDialog 编写您自己的自定义 Preference,而不是使用 DialogPreference。 对于那些不想处理 DialogPreferencePreferenceDialogFragmentCompat.

的人来说,这可能是一种解决方法
import android.content.Context;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.Preference;

public class CustomDialogPreference extends Preference {
    private final Context context;
    public CustomDialogPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }
    
    @Override
    protected void onClick() { //what happens when clicked on the preference
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle("TITLE")
                .setMessage("message")
                .setPositiveButton("OK", (dialog, which) -> {
                    String preferenceKey = getKey(); //You can update the SharedPreference with the key
                    //....
               })
                .setNegativeButton("CANCEL", (dialog, which) -> {
                    //....
                })
                .create().show();
    }
}

onClick()getKey()方法属于Preferenceclass。 context对象自带构造函数等等..

密钥可以像其他首选项一样在 xml 文件中或以编程方式在 PreferenceFragment 中定义。

<com.myApp.CustomDialogPreference
    android:key="my_preference_key"
    android:summary="..."
    android:title="..." />