Не найдено представления для идентификатора фрагмента на экране настройки предпочтений

#java #android #android-fragments #fragment #application-settings

#java #Android #android-фрагменты #фрагмент #приложение-настройки

Вопрос:

В моем приложении я использую DraverLayout в качестве основного действия, которое содержит фрагменты как части NavigationView. Но для настроек я использую SettingActivity, который содержит SettingFragment. Проблема возникает, когда я пытаюсь открыть дополнительный экран с экрана настроек:
«java.lang.Исключение IllegalArgumentException: представление не найдено для идентификатора 0x7f09014e (com.example.tipcollector:id / settings_container) для фрагмента NotificationMenuFragment{1fe50ef} (618cc8dc-6287-4830- b9a1-0e9b2d1d1827) id=0x7f09014e}». Что было сделано неправильно и как я могу это исправить? Я буду признателен за любую помощь или информацию!

SettingActivity.java

 package com.example.tipcollector;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import android.os.Bundle;
import com.example.tipcollector.Notification.NotificationMenuFragment;
public class SettingsActivity extends AppCompatActivity implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
    private Toolbar toolbar;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_setting);

        toolbar = findViewById(R.id.mainToolbar);
        setSupportActionBar(toolbar);
        if(findViewById(R.id.settings_container)!=null){
            if(savedInstanceState!=null)
                return;
             getSupportFragmentManager()
                     .beginTransaction()
                     .replace(R.id.settings_container, new SettingsFragment()).commit();
        }




        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

    @Override
    public boolean onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref) {
        final Bundle args = pref.getExtras();
        final Fragment fragment = getSupportFragmentManager().getFragmentFactory().instantiate(
                getClassLoader(),
                pref.getFragment());
        fragment.setArguments(args);
        fragment.setTargetFragment(caller,0);
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.settings_container, fragment)
                .addToBackStack(null)
                .commit();
        return true;
    }


}
 

Вот мой SettingsFragment

 package com.example.tipcollector;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.text.InputType;
import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.EditTextPreference;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import com.example.tipcollector.Notification.NotificationMenuFragment;
import database.DataBaseHelper;


public class SettingsFragment extends PreferenceFragmentCompat implements PreferenceManager.OnPreferenceTreeClickListener {



    public static final String PREF_HOURLY_RATE = "hourly_rate_key";
    public static final String PREF_CURRENCY = "currencies";
    public static final String PREF_NOTIFICATION = "notifications";

    private SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    @Override
    public boolean onPreferenceTreeClick(Preference preference) {
        String key = preference.getKey();

        if ("clear_all_key".equals(key)) {}

        if(PREF_NOTIFICATION.equals(key)){
            getChildFragmentManager().beginTransaction().replace(R.id.settings_container,new NotificationMenuFragment()).commit();   

        }

        return true;
    }

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.preferencesscreen,rootKey);

        preferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
            @Override
            public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {

                if(key.equals(PREF_HOURLY_RATE)){
                    EditTextPreference hourlyRatePref = findPreference(key);
                    hourlyRatePref.setSummary(sharedPreferences.getString(key,""));
                }else if(key.equals(PREF_CURRENCY)){
                    ListPreference currencyPref = findPreference(key);
                    currencyPref.setSummary(sharedPreferences.getString(key,""));
                }

            }
        };
    }
 

И XML-файлы для обоих. Вот экран настроек (макет для SettingFragment)

 <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <PreferenceCategory
        android:title="@string/setting_general"
        />
        <ListPreference
            android:entryValues="@array/currencies"
            android:entries="@array/currencies"
            app:title="@string/select_currency"
            app:key="currencies"
            android:icon="@drawable/ic_money_black"
            android:defaultValue="PLN"/>
        <EditTextPreference
            android:summary="@string/settings_general_hourly_rate"
            android:title="@string/your_hourly_rate"
            app:key="hourly_rate_key"
            android:icon="@drawable/ic_business_center_black_24dp"
            />
    <PreferenceCategory
        android:title="@string/data_settings"/>
        <Preference
            android:title="@string/clear_all_database"
            app:key="clear_all_key"
            android:summary="@string/clear_all_data_message"
            android:icon="@drawable/ic_delete_forever_black_24dp"/>
    <PreferenceCategory
        android:title="Notification"/>

        <Preference
            android:title="Notification"
            app:key="notification"
            android:icon="@drawable/ic_notifications_black_24dp"/>
    
</PreferenceScreen>
 

И вот SettingActivity

 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SettingsActivity"
android:orientation="vertical">

<include
    layout="@layout/main_toolbar"/>
<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@ id/settings_container"/>

</LinearLayout>
 

Комментарии:

1. Я заметил, что replace вызывается в контейнере FrameLayout settings_container как через: getChildFragmentManager(), так и getSupportFragmentManager(). Может ли это быть проблемой?

2. Я использовал getSupportFragmentManager() для перевода транзакции из activity в fragment, а в SettingsFragment я пытаюсь получить доступ к другому фрагменту, поэтому getChildFrragmentManager() там

3. Подождите, где в коде вы раздуваете макет SettingsFragment? Также покажите код для макета SettingsFragment

4. @Sarah мой фрагмент настроек я использую в качестве экрана предпочтений, поэтому макет для фрагмента отображается в этой строке setPreferencesFromResource (R.xml.preferencesscreen, rootKey);

5. Хорошо. 1) Вы определили PREF_NOTIFICATION = «уведомления»; но на вашем экране предпочтений нет ключа с именем notifications. 2) В макете не определено prefrencesscreen.xml который имеет id = settings_container, поэтому он выдаст ошибку

Ответ №1:

Изменения, которые необходимо внести в ваш preferencesscreen.xml

 <Preference
            android:title="Notification"
            app:key="notification"
            android:icon="@drawable/ic_notifications_black_24dp"
            app:fragment="com.example.tipcollector.Notification.NotificationMenuFragment" />
 

Кроме того, удалите этот метод из вашего SettingsFragment

 @Override
    public boolean onPreferenceTreeClick(Preference preference) {
        String key = preference.getKey();

        if ("clear_all_key".equals(key)) {}

        if(PREF_NOTIFICATION.equals(key)){
            getChildFragmentManager().beginTransaction().replace(R.id.settings_container,new NotificationMenuFragment()).commit();   

        }

        return true;
    }
 

Вам это не нужно, поскольку preferenceClick будет обрабатываться этим тегом в xml

 app:fragment="com.example.tipcollector.Notification.NotificationMenuFragment" 
 

Комментарии:

1. Хорошо. Большое вам спасибо, наконец, это сработало для меня. Насколько я понимаю, мой subscree не открывался, потому что общедоступный логический метод onPreferenceTreeClick (Preference preference) каким-то образом заблокировал мою транзакцию в XML. Еще раз большое вам спасибо