如何在onSaveInstanceState中保存Fragment的自定义类状态
Got it, let's fix this state loss issue step by step. The problem right now is that when a configuration change (like screen rotation) happens, your fragment gets recreated, and since you're not saving the log data and other state variables, everything resets. Here's how to fix it:
Step 1: Make LogItems Serializable
First, your LogItems class needs to implement the Serializable interface so it can be stored in a Bundle. This is required because we need to save the entire list of log entries, and each entry must be serializable to be written to the bundle.
Update your LogItems code:
package com.example.student.mysterygame; import java.io.Serializable; public class LogItems implements Serializable { // Add the Serializable interface private String logName; private String logDate; private String logEntry; public String getLogName(){return logName;} public String getLogDate(){return logDate;} public String getLogEntry(){return logEntry;} public void setLogName(String LogName){this.logName = LogName;} public void setLogDate(String LogDate){this.logDate = LogDate;} public void setLogEntry(String logEntry){this.logEntry = logEntry;} public LogItems(String name, String date, String logEntry){ this.logEntry = logEntry; this.logName = name; this.logDate = date; } }
Step 2: Fix Dangerous Static Members & Activity Initialization
Using static variables like mArrayList and mArrayAdapter is a big red flag here—it can cause memory leaks and unexpected behavior when the fragment is recreated. Let's convert them to instance variables:
// Remove the static keywords from these members in your logView fragment public ArrayAdapter<LogItems> mArrayAdapter; public ArrayList<LogItems> mArrayList; // Keep other instance variables as-is AbsListView mListView; EditText testField; String mmMessage; String name; String date; boolean hasEnteredPassword; private MainActivity mmActivity;
Also, fix the mmActivity initialization—never create a new Activity instance with new MainActivity(). Instead, cast the fragment's attached activity to your MainActivity type:
// Replace mmActivity = new MainActivity(); with this line in onViewCreated mmActivity = (MainActivity) getActivity();
Step 3: Implement onSaveInstanceState to Save State
Now we'll store all critical state data into the Bundle that's preserved across configuration changes:
@Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); // Save the full list of log entries savedInstanceState.putSerializable("LOG_ITEMS", mArrayList); // Save the password entry state savedInstanceState.putBoolean("HAS_ENTERED_PASSWORD", hasEnteredPassword); // Optional: Save the current text in the edit field savedInstanceState.putString("EDIT_TEXT_CONTENT", testField.getText().toString()); }
Step 4: Restore State When the Fragment Recreated
We need to pull the saved data back out when the fragment is rebuilt. Do this in the onCreate method to initialize your list and adapter correctly:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Check if we have saved state to restore if (savedInstanceState != null) { // Restore the log items list mArrayList = (ArrayList<LogItems>) savedInstanceState.getSerializable("LOG_ITEMS"); // Restore the password entry state hasEnteredPassword = savedInstanceState.getBoolean("HAS_ENTERED_PASSWORD"); } else { // Initialize empty list if this is the first creation mArrayList = new ArrayList<LogItems>(); } // Create the adapter with the (restored or new) list mArrayAdapter = new textLogAdpater(getActivity(), mArrayList); }
Also, restore the edit text content in onViewCreated:
@Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // ... existing code to find views ... testField = getView().findViewById(R.id.editText); // Restore edit text content if available if (savedInstanceState != null) { String savedText = savedInstanceState.getString("EDIT_TEXT_CONTENT"); testField.setText(savedText); } // ... rest of your existing code ... }
Bonus: Fix Duplicate Initial Log Entries
Right now, your initial log messages (like "Connecting to Friend1 Phone....") are added every time onViewCreated runs—including after a configuration change, leading to duplicates. Fix this by only running that code on the fragment's first creation:
@Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // ... existing code ... /** * ALL POPULATION REQUESTS FOR THE LOG SHOULD BE PUT BELOW THIS COMMENT. */ if (savedInstanceState == null) { // Only run on first creation Log.d("Log Population", "OnCreate called for LogPopulation"); populateLogOnStartWith("UI", "10/11/2018:", "Connecting to Friend1 Phone...."); populateLogOnStartWith("UI", "10/11/2018:", "Phone is now Connected"); populateLogOnStartWith("UI", "10/123/2018:", "Enter Password to access phone:"); } }
内容的提问来源于stack exchange,提问作者BagelDasu

