用Androidx的方式使用Preference-記一次官方文檔錯誤

用Androidx的方式使用Preference

原由

  1. 多是由於targetApi=29的緣由,在使用傳統的PreferenceActivity的時候AS提醒我裏面的一些方法已經被棄用,做爲一個很是激進的業餘菜鳥開發者,個人強迫症促使我去尋找其解決方案
  2. 近期收到個人小軟件AndroCode有些用戶反饋設置的第二級打不開,點擊沒有反應

找輪子

我開始百度找輪子,得知android10使用androidx全面替代,看了一下遷移的對應關係migrate,因而又百度androidx.preference,但結果寥寥無幾,只有androidx PreferenceDialogFragmentCompat 和 DialogPreference的配合應用這一篇有一些記載,但對於咱們這樣的菜鳥很不友好,沒有講基礎的使用方法或貼代碼,裏面的參考文檔還被牆打不開。html

不得已去看官方API,終於找到了使用方法指南,居然有中文!!!還這麼簡潔,我大喜過望,趕忙上手操做java

官方DEMO

導入依賴
implementation 'androidx.preference:preference:1.1.0'
implementation 'androidx.core:core:1.2.0-beta01'
implementation 'androidx.fragment:fragment:1.2.0-rc01'
官方Demo
<PreferenceScreen
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <SwitchPreferenceCompat
        app:key="notifications"
        app:title="Enable message notifications"/>

    <Preference
        app:key="feedback"
        app:title="Send feedback"
        app:summary="Report technical issues or suggest new features"/>

</PreferenceScreen>
public class MySettingsFragment extends PreferenceFragmentCompat {
    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.preferences, rootKey);
    }
}
public class MySettingsActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.settings_container, new MySettingsFragment())
                .commit();
    }
}

首先是沒有了header的方式,但個人APP暫時仍是須要這種佈局,因而用RecyclerView模擬了一個android

activity_settings_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:attr/selectableItemBackground"
    android:clickable="true"
    android:focusable="true"
    android:orientation="vertical"
    android:paddingStart="15dp"
    android:paddingTop="10dp"
    android:paddingEnd="15dp"
    android:paddingBottom="10dp">
    <!--actionBarItemBackground -->
    <TextView
        android:id="@+id/activity_settings_label"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="true"
        android:textStyle="bold"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium" />

    <TextView
        android:id="@+id/activity_settings_message"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</LinearLayout>
activity_settings.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:id="@+id/activity_settings_layout"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/activity_settings_recyclerv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <FrameLayout
        android:id="@+id/activity_settings_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

這裏偷了個懶,用顯示隱藏RecycerView的方式來給Fragment騰地方git

因爲PreferenceScreen還要用Fragment顯示, 因而在AppCompatActivity中用recyclerview來觸發事件顯示fragmentgithub

onCreate:
headers.add(new SettingHeader("應用", "配置應用主題、會話", new SettingFragment(R.xml.settings_app)));
        headers.add(new SettingHeader("編輯器", "配置編輯器、代碼、保存", new SettingFragment(R.xml.settings_editor)));
        headers.add(new SettingHeader("構建、運行", "配置工程構建和運行設置", new SettingFragment(R.xml.settings_build)));
        headers.add(new SettingHeader("關於", "介紹等", new SettingFragment(R.xml.settings_about)));
        recyclerv.setAdapter(new BaseRecyclerAdapter<SettingHeader>(headers) {
            @Override
            protected int getItemLayoutId(int viewType) {
                return R.layout.activity_settings_item;
            }

            @Override
            protected void bindData(@NonNull RecyclerViewHolder holder, int position, SettingHeader item) {
                holder.getTextView(R.id.activity_settings_label).setText(item.label);
                holder.getTextView(R.id.activity_settings_message).setText(item.message);
                holder.itemView.setOnClickListener(v -> {
                    getSupportFragmentManager()
                            .beginTransaction()
                            .replace(R.id.activity_settings_container, item.fragmentCompat)
                            .commit();
                    recyclerv.setVisibility(View.GONE);
                });
            }
        });
        recyclerv.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false));

爲了減小代碼,我機智地複用一個SettingFragment來加載不一樣xmlapp

public static class SettingHeader {
        public String label;
        public String message;
        public PreferenceFragmentCompat fragmentCompat;

        public SettingHeader(String label, String message, PreferenceFragmentCompat fragmentCompat) {
            this.label = label;
            this.message = message;
            this.fragmentCompat = fragmentCompat;
        }
    }

    public static class SettingFragment extends PreferenceFragmentCompat {
        private final int id;

        public SettingFragment(int xmlId) {
            super();
            this.id = xmlId;
        }

        @Override
        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
            setPreferencesFromResource(id, rootKey);
        }

        @Override
        public void onDisplayPreferenceDialog(Preference preference) {
            if (preference instanceof GenKeystorePreference) {
                ((GenKeystorePreference) preference).showDialog();
            } else
                super.onDisplayPreferenceDialog(preference);
        }
    }

因而我滿懷信心地用AS跑了起來,一塊兒看起來是那麼地完美框架

沒問題,打開應用item編輯器

???這是什麼鬼ide

尋找錯誤緣由

由於用到了一個換膚框架,有些兼容問題,起初我覺得是字體顏色和背景同樣,因而開始搗鼓主題,禁用框架,但毫無結果佈局

終於,機緣巧合之下,log提示我自定義的Preference有問題,DialogPreference再也不提供默認的新建Dialog操做,要經過onDisplayPreferenceDialog來設置,將其修復後log提示我沒有Preference have no Key!

但我明明有定義,徹底是按照官方的教程來的啊!思考半天,我嘗試用android:替換app:,最後運行以下

官方文檔有錯!本人記下了!!!

看這架勢應該是支持icon,預留了一個ImageView

結論

官方文檔有錯,仍是用android:而不是app:,估計是升級lib忘了同步仍是寫錯了?

本文章github連接

相關文章
相關標籤/搜索