2

I have two fragments :
- HomeFragment that extends Fragment
- SettingsFragment that extends PreferenceFragment

Each one contains a TextView that I wish to access and modify its content in the Java code. I make this modification inside the onViewCreated by calling findViewById and then, using setText on the TextView.
This works fine for HomeFragment, but it does not in SettingsFragment.
For information, the TextView of SettingsFragment is defined in the layout associated to the Preference. Strangely, it seems that the views hierarchy of PreferenceFragment type is not fully ready in the onViewCreated ! To go further, I tried to put the code that modifies the TextView after some delay (using postDelay), and that worked !

Below, I put all the code necessary to test the issue I have just raised.

MainActivity.java

public class MainActivity extends AppCompatActivity {

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

        final HomeFragment homeFragment = new HomeFragment();
        final SettingsFragment settingsFragment = new SettingsFragment();

        getFragmentManager().beginTransaction()
                .add(R.id.fragmentContainer, homeFragment).commit();

        // Just a simple button to switch between the two fragments
        Button button = findViewById(R.id.activityButton);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(homeFragment.isAdded()) {
                    getFragmentManager().beginTransaction()
                            .replace(R.id.fragmentContainer, settingsFragment).commit();
                } else {
                    getFragmentManager().beginTransaction()
                            .replace(R.id.fragmentContainer, homeFragment).commit();
                }
            }
        });
    }
}

HomeFragment.java

public class HomeFragment extends Fragment {

    public HomeFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_home, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        TextView textView = view.findViewById(R.id.homeText);
        if(textView != null) {
            textView.setText("Home fragment text (modified)");
        }
    }
}

SettingsFragment.java

public class SettingsFragment extends PreferenceFragment {


    public SettingsFragment() {
        // Required empty public constructor
    }

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

        addPreferencesFromResource(R.xml.fragment_settings);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        // ---- BLOCK 1 -----
        TextView textView = view.findViewById(R.id.settingsText);
        if (textView != null) {
            textView.setText("Preference 1 (modified)");
        }

        // ---- BLOCK 2 -----
//        view.post(new Runnable() {
//            @Override
//            public void run() {
//                TextView textView = view.findViewById(R.id.settingsText);
//                if (textView != null) {
//                    textView.setText("Preference 1 (modified)");
//                }
//            }
//        });

        // ---- BLOCK 3 -----
//        view.postDelayed(new Runnable() {
//            @Override
//            public void run() {
//                TextView textView = view.findViewById(R.id.settingsText);
//                if (textView != null) {
//                    textView.setText("Preference 1 (modified)");
//                }
//            }
//        }, 100);
    }
}

activity_main.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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/activityText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:gravity="center_horizontal"
        android:text="MainActivity" />

    <Button
        android:id="@+id/activityButton"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/activityText"
        android:text="Change fragment"/>

    <FrameLayout
        android:id="@+id/fragmentContainer"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@id/activityButton"
        app:layout_constraintBottom_toBottomOf="parent">

    </FrameLayout>

</android.support.constraint.ConstraintLayout>

fragment_home.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".HomeFragment">

    <TextView
        android:id="@+id/homeText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:text="Home fragment text" />

</android.support.constraint.ConstraintLayout>

fragment_settings.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory
        android:layout="@layout/preference_layout_category">

        <Preference
            android:enabled="true"
            android:layout="@layout/preference_layout" />

    </PreferenceCategory>
</PreferenceScreen>

preference_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <TextView
        android:id="@+id/settingsText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:textAllCaps="true"
        android:text="Preference 1"/>

</android.support.constraint.ConstraintLayout>

preference_layout_category.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <TextView
        android:id="@+id/settingsTextContainer"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:textAllCaps="true"
        android:background="@android:color/background_dark"
        android:textColor="@android:color/background_light"
        android:text="Category 1"/>

</android.support.constraint.ConstraintLayout>
MMasmoudi
  • 508
  • 1
  • 5
  • 19

2 Answers2

1

I had something similar the other day. Use findViewById() in the on onCreateView of the fragment instead of the onViewCreated method. Good luck.

Beast77
  • 193
  • 1
  • 17
  • I started using **onCreateView** and it did not work. I deliberately used **onViewCreated** as it is triggered after **onCreateView** – MMasmoudi Feb 27 '19 at 10:47
  • Then use a custom preference. Follow this link: https://stackoverflow.com/questions/34548731/how-to-reach-the-elements-of-the-layout-using-preferencefragment – Beast77 Feb 27 '19 at 11:06
  • As I began using this technique, I noticed some strange behaviour : onBindView is called many times whereas I only have one instance of my custom preference ? Any ideas why ? – MMasmoudi Feb 27 '19 at 15:41
0

Bind your views in onCreateView() instead like this

View view= inflater.inflate(R.layout.your_fragment, container, false);
TextView textView = view.findViewById(R.id.settingsText);
return view;
  • onCreateView of PreferenceFragment is slightly different than the one of a normal Fragment. In fact, it is calls **super.onCreateView(inflater, container, savedInstanceState);** In addition, we cannot inflate a layout because its associated XML file should lay in the xml resource folder – MMasmoudi Feb 27 '19 at 10:58