Android多Fragment应用中用户绘图持久化实现问询
Alright, let's fix your drawing persistence issue step by step. The core problems with your current code are:
- Your
FingerPathclass doesn't serialize thePathobject in itsParcelableimplementation, so the actual drawing paths aren't being saved. - You're trying to use
putParcelableArraywith anArrayList, which won't work—you need to use the correct method for lists of Parcelables. - You haven't added logic to restore the saved paths when the fragment is recreated.
Step 1: Fix the FingerPath Parcelable Implementation
The Path class already implements Parcelable, so we just need to add it to the serialization/deserialization flow:
import android.graphics.Path; import android.os.Parcel; import android.os.Parcelable; public class FingerPath implements Parcelable { public int color; public boolean emboss; public boolean blur; public int strokeWidth; public Path path; public FingerPath(int color, boolean emboss, boolean blur, int strokeWidth, Path path) { this.color = color; this.emboss = emboss; this.blur = blur; this.strokeWidth = strokeWidth; this.path = path; } protected FingerPath(Parcel in) { color = in.readInt(); emboss = in.readByte() != 0; blur = in.readByte() != 0; strokeWidth = in.readInt(); // Read the Path object (it's Parcelable) path = in.readParcelable(Path.class.getClassLoader()); } public static final Creator<FingerPath> CREATOR = new Creator<FingerPath>() { @Override public FingerPath createFromParcel(Parcel in) { return new FingerPath(in); } @Override public FingerPath[] newArray(int size) { return new FingerPath[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeInt(color); parcel.writeByte((byte) (emboss ? 1 : 0)); parcel.writeByte((byte) (blur ? 1 : 0)); parcel.writeInt(strokeWidth); // Write the Path object parcel.writeParcelable(path, i); } }
Step 2: Update PaintView to Support Restoring Paths
Add a setter method to accept saved paths, and fix the getter to use proper generics:
// Fix the getter to avoid unchecked type warnings public ArrayList<FingerPath> getPaths() { return paths; } // Add a setter to restore saved paths and trigger redraw public void setPaths(ArrayList<FingerPath> paths) { this.paths = new ArrayList<>(paths); invalidate(); // Force the view to redraw with restored paths }
Step 3: Fix Fragment State Save/Restore Logic
Use putParcelableArrayList (designed for lists of Parcelables) instead of putParcelableArray, and add code to restore paths when the fragment recreates:
import android.os.Bundle; import android.util.DisplayMetrics; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; public class LineLHwFragment extends Fragment { private PaintView paintView; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_line_l_hw, container, false); paintView = v.findViewById(R.id.lineLPaintView); DisplayMetrics metrics = new DisplayMetrics(); getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics); paintView.init(metrics); // Restore saved paths if they exist if (savedInstanceState != null) { ArrayList<FingerPath> savedPaths = savedInstanceState.getParcelableArrayList("line_paths"); if (savedPaths != null) { paintView.setPaths(savedPaths); } } setHasOptionsMenu(true); return v; } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.main, menu); super.onCreateOptionsMenu(menu, inflater); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.normal: paintView.normal(); return true; case R.id.clear: paintView.clear(); return true; } return super.onOptionsItemSelected(item); } @Override public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); // Save the ArrayList of FingerPath using the correct method outState.putParcelableArrayList("line_paths", paintView.getPaths()); } }
Bonus: Persist Drawing Across App Restarts
If you want the drawing to stay even after the user closes and reopens the app, add file-based persistence to PaintView:
First, make FingerPath implement Serializable:
public class FingerPath implements Parcelable, Serializable { // ... existing code remains the same ... }
Then add save/load methods to PaintView:
import android.content.Context; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; // Save paths to internal storage public void savePathsToFile(Context context) { try { FileOutputStream fos = context.openFileOutput("drawing_data.dat", Context.MODE_PRIVATE); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(paths); oos.close(); fos.close(); } catch (Exception e) { e.printStackTrace(); } } // Load paths from internal storage @SuppressWarnings("unchecked") public void loadPathsFromFile(Context context) { try { FileInputStream fis = context.openFileInput("drawing_data.dat"); ObjectInputStream ois = new ObjectInputStream(fis); paths = (ArrayList<FingerPath>) ois.readObject(); ois.close(); fis.close(); invalidate(); } catch (Exception e) { e.printStackTrace(); } }
Finally, call these methods in your fragment's lifecycle:
@Override public void onPause() { super.onPause(); paintView.savePathsToFile(getContext()); } @Override public void onResume() { super.onResume(); paintView.loadPathsFromFile(getContext()); }
内容的提问来源于stack exchange,提问作者dan

