Save-Bundle with Fragments Not Saving State on Android

TrickExplanation :

I have an android app that has two fragments that pass data from fragmentA to fragmentB. I can load all the data correctly but when I change the screen orientation it all reloads. I have set up the onSaveInstanceState and onViewStateRestored methods in the fragment I want to keep the state in, but nothing stays when the screen orientation changes.

The main problem that needs to be fixed is when text is loaded into the TextView in FragmentB - it needs to stay there when the screen orientation is changed.

MainActivity.Java

package com.example.tourguide;

import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentTransaction;

public class MainActivity extends AppCompatActivity implements FragmentA.FragmentAListener, FragmentB.FragmentBListener {
    private FragmentA fragmentA;
    private FragmentB fragmentB;

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

        fragmentA = new FragmentA();
        fragmentB = new FragmentB();

        if(savedInstanceState == null) {
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.replace(R.id.container_a, new FragmentA());
            ft.replace(R.id.container_b, new FragmentB());
            ft.commitNow();
        }

    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

    }

    @Override
    protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);

    }

    @Override
    public void onInputASent(CharSequence input) {
        fragmentB.updateEditText(input);
    }

    @Override
    public void onInputBSent(CharSequence input) {
        fragmentA.updateEditText(input);
    }
}

FragmentA.Java

package com.example.tourguide;

import android.content.Context;
import android.os.Bundle;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.ListFragment;


public class FragmentA extends ListFragment implements AdapterView.OnItemClickListener {
    private FragmentAListener listener;

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        String[] locationList = getActivity().getResources().getStringArray(R.array.location_list);
        updateEditText(locationList[position]);
        listener.onInputASent(locationList[position]);
    }

    public interface FragmentAListener {
        void onInputASent(CharSequence input);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_a, container, false);

        return v;
    }


    @Override
    public void onListItemClick(@NonNull ListView l, @NonNull View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
    }

    public void updateEditText(CharSequence newText) {
        //editText.setText(newText);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof FragmentAListener) {
            listener = (FragmentAListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement FragmentAListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        listener = null;
    }

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

        ArrayAdapter arrayAdapter = ArrayAdapter.createFromResource(getActivity(), R.array.location_list, android.R.layout.simple_list_item_1);

        setListAdapter(arrayAdapter);

        getListView().setOnItemClickListener(this);
    }

}

FragmentB.Java - This is the fragment that needs to be keep the string inside the TextView when the screen is rotated

package com.example.tourguide;

import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;


public class FragmentB extends Fragment {
    private FragmentBListener listener;

    private TextView resultsFrag;

    private static final String KEY_TITLE = "title_key";

    private String stateObject;

    public interface FragmentBListener {
        void onInputBSent(CharSequence input);
    }


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_b, container, false);

        resultsFrag = v.findViewById(R.id.tvFragmentB);

        //I used the same if block in three different locations and none of them worked
        if (savedInstanceState != null) {
            String itemTo = savedInstanceState.getString(KEY_TITLE);
            resultsFrag.setText(itemTo);
        } else {
            Toast.makeText(getActivity(), "Error 1", Toast.LENGTH_SHORT).show();
        }

        return v;
    }

    public void updateEditText(CharSequence newText) {

        String newOption = newText.toString();
        stateObject = newText.toString();

        Resources res = getResources();
        String[] locationDesc = res.getStringArray(R.array.location_description);

        if (newOption.equals("Calgary")) {
            resultsFrag.setText(locationDesc[0]);
        } else if (newOption.equals("Victoria")) {
            resultsFrag.setText(locationDesc[1]);
        } else if (newOption.equals("Vancouver")) {
            resultsFrag.setText(locationDesc[2]);
        } else if (newOption.equals("Toronto")) {
            resultsFrag.setText(locationDesc[3]);
        }

    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof FragmentBListener) {
            listener = (FragmentBListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement FragmentBListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        listener = null;
    }

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(KEY_TITLE, resultsFrag.getText().toString());
    }

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

        //I used the same if block in three different locations and none of them worked
        if (savedInstanceState != null) {
            String itemTo = savedInstanceState.getString(KEY_TITLE);
            resultsFrag.setText(itemTo);
        } else {
            Toast.makeText(getActivity(), "Error 2", Toast.LENGTH_SHORT).show();
        }
    }

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

        //I used the same if block in three different locations and none of them worked
        if (savedInstanceState != null) {
            String itemTo = savedInstanceState.getString(KEY_TITLE);
            resultsFrag.setText(itemTo);
        } else {
            Toast.makeText(getActivity(), "Error 3", Toast.LENGTH_SHORT).show();
        }
    }

}

fragment_b.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@android:color/holo_blue_light"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/tvFragmentB"
        android:layout_width="match_parent"
        android:layout_height="602dp" />

</LinearLayout>

Strings

<resources>
    <string name="app_name">Tour Guide</string>

    <string-array name="location_list">
        <item>Calgary</item>
        <item>Victoria</item>
        <item>Vancouver</item>
        <item>Toronto</item>
    </string-array>

    <!-- Descriptions for the locations -->
    <string-array name="location_description">
        <item>This is a big description for CALGARY - THIS needs to load in for more information regarding CALGARY</item>
        <item>This is a big description for VICTORIA - THIS needs to load in for more information regarding VICTORIA</item>
        <item>This is a big description for VANCOUVER - THIS needs to load in for more information regarding VANCOUVER</item>
        <item>This is a big description for TORONTO - THIS needs to load in for more information regarding TORONTO</item>
    </string-array>

</resources>

fragment_a.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@android:color/holo_green_light"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:padding="16dp">

    <ListView
        android:id="@android:id/list"
        android:layout_width="wrap_content"
        android:layout_height="206dp" />

</LinearLayout>

activity_main.xml

<?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"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/container_a"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <FrameLayout
        android:id="@+id/container_b"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>
EpicPandaForce :

They are saved, but you are replacing them. Use this

if(savedInstanceState == null) {
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.replace(R.id.container_a, new FragmentA());
    ft.replace(R.id.container_b, new FragmentB());
    ft.commit();
}

Please note that fragment instantiation is pretty much the ONLY scenario in which this check yields correct and expected results.

Do not keep a reference to a Fragment, unless it is obtained via findFragmentByTag + instantiation. You might want to use commitNow to get reliable results in this case.


EDIT: Update with more complete code:

public class MainActivity extends AppCompatActivity implements FragmentA.FragmentAListener, FragmentB.FragmentBListener {
    private FragmentA fragmentA;
    private FragmentB fragmentB;

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

        if(savedInstanceState == null) {
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.replace(R.id.container_a, new FragmentA(), "fragmentA");
            ft.replace(R.id.container_b, new FragmentB(), "fragmentB");
            ft.commitNow();
        }

        fragmentA = getSupportFragmentManager().findFragmentByTag("fragmentA");
        fragmentB = getSupportFragmentManager().findFragmentByTag("fragmentB");
    }

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=238503&siteId=1