Use Preference as Androidx

The cause of

  1. Probably because of targetApi=29, when USING traditional PreferenceActivity, AS reminded me that some of the methods in it had been deprecated, and AS a very aggressive amateur rookie developer, my compulsion pushed me to find a solution
  2. Recently, I received feedback from some users that the second level of my small software AndroCode cannot be opened, so there is no response when I click it

Looking for the wheel

I started searching for wheels on baidu, and learned that android10 uses androidx to replace them completely. After looking at the corresponding relationship of migration, I then searched baidu androidx.preference, but the result is very few. Only androidx PreferenceDialogFragmentCompat DialogPreference and the application of this article has some records, but was not friendly to us as a rookie, there is no use method on the basis of the speaking or post code, and inside wall of reference documents have also been won’t open.

I had to go to the official API and finally found the user guide, which is in Chinese!! Still so simple, I overjoyed, quickly start the operation

Import dependence
implementation 'androidx. Preference: preference: 1.1.0'
implementation 'androidx. Core: the core: 1.2.0 - beta01'
implementation 'androidx. Fragments: fragments: 1.2.0 - rc01'
Copy the code
The official 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>
Copy the code
public class MySettingsFragment extends PreferenceFragmentCompat {
    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { setPreferencesFromResource(R.xml.preferences, rootKey); }}Copy the code
public class MySettingsActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.settings_container, newMySettingsFragment()) .commit(); }}Copy the code

First of all, there is no header, but my APP still needs this layout for the time being, so I used RecyclerView to simulate one

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>
Copy the code
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>
Copy the code

Here’s a sneaky RecycerView to make room for the Fragment

Since PreferenceScreen also displays fragments, you can use recyclerView in AppCompatActivity to trigger events to display fragments

onCreate:
headers.add(new SettingHeader("Application"."Configure application Topics and sessions".new SettingFragment(R.xml.settings_app)));
        headers.add(new SettingHeader("Editor"."Configure editor, code, Save".new SettingFragment(R.xml.settings_editor)));
        headers.add(new SettingHeader("Build and run"."Configuration engineering build and Run Settings".new SettingFragment(R.xml.settings_build)));
        headers.add(new SettingHeader("About"."Introduction, etc.".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));
  
Copy the code

To reduce the code, I cleverly reuse a SettingFragment to load different XML

 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(a);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); }}Copy the code

So I confidently ran with AS, and it all looked perfect

No problem. Open up Apply Item

????? What the hell is this

Find the cause of the error

Because I used a skin frame, I had some compatibility problems. At first I thought it was because the font color was the same as the background, so I started tinkering with the theme and disabling the frame, but nothing happened

Finally, under the coincidence, and log me the custom is a problem with the Preference DialogPreference no longer provide default new Dialog operation, to by onDisplayPreferenceDialog Settings, After fixing it, the log tells me that I have no Preference have no Key!

But I clearly have a definition, is completely in accordance with the official tutorial ah! After thinking for a long time, I tried to replace app: with Android:, and finally ran as follows

Official documentation is wrong! I wrote it down!!

Support icon, reserve an ImageView

conclusion

There is something wrong with the official document, I still use Android: instead of app:, I guess it is because the update lib forgot to synchronize or I made a mistake?

This article is linked to github