Экран предпочтения Пользовательский макет работает только со вторым щелчком

У меня есть экран предпочтений с использованием «пользовательского макета»:

android:layout="@layout/currencycodes" 

Эта проблема заключается в том, что при первой попытке не удается создать макет. Как вы видите из анимированного gif ниже, мне нужно отступить и повторить попытку еще раз, чтобы макет подошел. Теперь почему?

Введите описание изображения здесь

preferences.xml

 <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:key="application_preferences"> <PreferenceCategory> <PreferenceScreen android:key="url_settings" android:title="@string/url_settings" android:summary="@string/summary_url_settings"> </PreferenceScreen> <PreferenceScreen android:key="currency_codes" android:title="@string/left_handed" android:summary="@string/summary_left_handed"> <Preference android:key="currency_exchanges" android:layout="@layout/currencycodes"/> </PreferenceScreen> <EditTextPreference android:key="url_exchange_rate" android:title="@string/url_exchange_rate_settings" android:summary="@string/summary_url_exchange_rate" android:enabled = "false"/> </PreferenceCategory> </PreferenceScreen> 

Далее следует используемый пользовательский макет. Он содержит GridView.

currencycodes.xml

 <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:focusable="true" android:focusableInTouchMode="true" tools:context=".MainActivity"> <GridView android:layout_width="328dp" android:layout_height="479dp" android:layout_marginTop="16dp" app:layout_constraintTop_toTopOf="parent" android:layout_marginStart="16dp" app:layout_constraintLeft_toLeftOf="parent" android:layout_marginEnd="16dp" app:layout_constraintRight_toRightOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="16dp" android:id="@+id/grdExchanges" android:scrollbars="horizontal|vertical" android:smoothScrollbar="true" tools:textAlignment="center" android:verticalScrollbarPosition="defaultPosition"/> </android.support.constraint.ConstraintLayout> 

    Ну, в первую очередь вам нужно понять, как работает PreferenceScreen?

    Из [Документация для Android] [1]:

    Когда он появляется внутри другой иерархии предпочтений, он отображается и служит в качестве шлюза к другому экрану предпочтений (либо путем отображения другого экрана предпочтений как Диалог, либо через startActivity (android.content.Intent) из getIntent ()). Дети этого экрана предпочтений НЕ отображаются на экране, на котором показан этот экран предпочтений. Вместо этого при выборе этого предпочтения будет показан отдельный экран.

    В простых словах,

    Механизм предпочтений обрабатывает отображение этих других экранов из иерархии предпочтений. Этот тег PreferenceScreen служит в качестве разрыва экрана (аналогично разрыву страницы в обработке текста). Подобно другим типам предпочтений, мы назначаем ключ здесь, чтобы он мог сохранять и восстанавливать свое состояние экземпляра.

    В вашем случае то, что на самом деле происходит, это « application_preferences », будет использоваться как корень иерархии и задано для PreferenceActivity. На первом экране будут показаны настройки « Url_Setting » и « Currency Codes ». « Коды валют » – это « второй_режим экрана », и при нажатии будет показан другой экран настроек, который представляет собой « Обмен валюты » (поскольку он предпочитает дочерние элементы тега « second_preferencescreen », то есть « Коды валют» ).

    Итак, почему он не показывает первый клик …. но при втором нажатии мы надеемся, что экран настроек будет работать …

    Если у вас все еще есть сомнения … дайте мне знать … https://developer.android.com/reference/android/preference/PreferenceScreen.html

    Попробуйте изменить свой оператор if из

     (!mFragMngr.popBackStackImmediate(fragName, 0) && mFragMngr.findFragmentByTag(fragName) == null) 

    в

     (mFragMngr.findFragmentByTag(fragName) == null) 

    Я придумал обходной путь. Я заметил, что при раздувании макета в LayoutInflater.java статический хэш-файл используется для сбора объектов вида:

     private static final HashMap<String, Constructor<? extends View>> sConstructorMap 

    Что происходит, так это то, что первый щелчок вызывает LayoutInflater, но первый клик только добавляет вид gridview в статическом хэшмапе. Вы увидите, что с первого щелчка команда sConstructorMap.get(name) возвращает только null:

     public final View createView(String name, String prefix, AttributeSet attrs) throws ClassNotFoundException, InflateException { Constructor<? extends View> constructor = sConstructorMap.get(name); Class<? extends View> clazz = null; try { if (constructor == null) { 

    В LayoutInflater переменная mPrivateFactory фактически является вашей основной деятельностью. Именно там мой gridview будет инициализирован в mPrivateFactory.onCreateView (). Однако при первом щелчке mPrivateFactory.onCreateView () возвращает значение null, потому что статический хэш-файл не имеет представления gridview …. Ниже в командной строке onCreateView(parent, name, attrs); Где, наконец, добавлено:

      if (view == null && mPrivateFactory != null) { view = mPrivateFactory.onCreateView(parent, name, context, attrs); } if (view == null) { final Object lastContext = mConstructorArgs[0]; mConstructorArgs[0] = context; try { if (-1 == name.indexOf('.')) { view = onCreateView(parent, name, attrs); <-- ADD TO STATIC HASHMAP } else { view = createView(name, null, attrs); } } finally { mConstructorArgs[0] = lastContext; } } 

    Поэтому, пока я не придумал более элегантное решение, я просто вызываю метод onCreateView(parent) дважды в первый раз, когда на него нажимается конкретное предпочтение. Первый вызов добавляет gridview к статическому hashmap, второй вызов затем создает представление макета (снова), но на этот раз инициализирует gridview в собственном методе mPrivateFactory.onCreateView() собственного Activity, mPrivateFactory.onCreateView() :

     protected View onCreateView(ViewGroup parent) { View layout = super.onCreateView(parent); if(firstCall){ firstCall = false; layout = super.onCreateView(parent); } return layout; }