You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用OnSaveInstanceState与OnRestoreInstanceState退出APP后无法恢复视图问题

Why Your Dynamically Created CardViews Aren't Restoring After App Restart

Hey there! Let's break down exactly why your saved state isn't showing up when you reopen the app, and how to fix it.

The Core Issues

  • You're only saving partial data: Your current onSaveInstanceState stores just one input string and a layout ID, but you're creating multiple CardViews with unique text, background colors, and sizes. None of that per-CardView detail is being saved.
  • You're not rebuilding the UI: Right now, you fetch values from the Bundle in onRestoreInstanceState but don't use them to recreate your CardViews/TextViews or add them back to the layout. Retrieving data without acting on it won't bring your UI back.

Step-by-Step Fix

1. Create a Data Class to Store CardView State

First, make a class to hold all the info needed to rebuild a CardView. We'll use Parcelable for efficient Bundle storage:

import android.os.Parcel;
import android.os.Parcelable;

public class CardViewState implements Parcelable {
    private String text;
    private int backgroundColor;
    private int width;
    private int height;

    public CardViewState(String text, int backgroundColor, int width, int height) {
        this.text = text;
        this.backgroundColor = backgroundColor;
        this.width = width;
        this.height = height;
    }

    protected CardViewState(Parcel in) {
        text = in.readString();
        backgroundColor = in.readInt();
        width = in.readInt();
        height = in.readInt();
    }

    public static final Creator<CardViewState> CREATOR = new Creator<CardViewState>() {
        @Override
        public CardViewState createFromParcel(Parcel in) {
            return new CardViewState(in);
        }

        @Override
        public CardViewState[] newArray(int size) {
            return new CardViewState[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(text);
        dest.writeInt(backgroundColor);
        dest.writeInt(width);
        dest.writeInt(height);
    }

    // Getters for saved data
    public String getText() { return text; }
    public int getBackgroundColor() { return backgroundColor; }
    public int getWidth() { return width; }
    public int getHeight() { return height; }
}

2. Save All CardView States in onSaveInstanceState

Update your save method to collect data from every dynamically created CardView:

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState); // Call super FIRST!

    // Collect state for all CardViews with your tag
    ArrayList<CardViewState> cardStates = new ArrayList<>();
    for (int i = 0; i < mConstraintLayout.getChildCount(); i++) {
        View child = mConstraintLayout.getChildAt(i);
        if (child instanceof CardView && CARD_VIEW_TAG.equals(child.getTag())) {
            CardView card = (CardView) child;
            TextView tv = (TextView) card.getChildAt(0);
            CardView.LayoutParams params = (CardView.LayoutParams) card.getLayoutParams();
            
            CardViewState state = new CardViewState(
                tv.getText().toString(),
                card.getCardBackgroundColor().getDefaultColor(),
                params.width,
                params.height
            );
            cardStates.add(state);
        }
    }

    // Save the list to the Bundle
    savedInstanceState.putParcelableArrayList("card_states", cardStates);
}

Pro tip: Always call super.onSaveInstanceState() before adding your own data—this ensures the system saves default view state first.

3. Restore CardViews in onCreate

Add logic to rebuild your CardViews when the app restarts:

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

    // Initialize your views as before
    mContext = getApplicationContext();
    mConstraintLayout = findViewById(R.id.top_left);
    addButton = findViewById(R.id.add);
    userInput = findViewById(R.id.editText);
    mButton = findViewById(R.id.create);

    // Restore saved CardViews if they exist
    if (savedInstanceState != null) {
        ArrayList<CardViewState> cardStates = savedInstanceState.getParcelableArrayList("card_states");
        if (cardStates != null) {
            for (CardViewState state : cardStates) {
                recreateCardView(state);
            }
        }
    }

    // Your existing addButton and mButton click listeners go here...
}

// Helper method to rebuild a CardView from saved state
private void recreateCardView(CardViewState state) {
    CardView sticker = new CardView(mContext);
    CardView.LayoutParams params = new CardView.LayoutParams(
        state.getWidth(),
        state.getHeight()
    );

    sticker.setCardBackgroundColor(state.getBackgroundColor());
    sticker.setId(CardView.generateViewId());
    sticker.setTag(CARD_VIEW_TAG);
    sticker.setLayoutParams(params);

    // Reattach the long click listener (same as original code)
    sticker.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            ClipData.Item item = new ClipData.Item((CharSequence) sticker.getTag());
            String[] mimeTypes = {ClipDescription.MIMETYPE_TEXT_PLAIN};
            ClipData data = new ClipData(sticker.getTag().toString(), mimeTypes, item);
            View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(sticker);
            sticker.startDrag(data, shadowBuilder, sticker, 0);
            sticker.setVisibility(View.INVISIBLE);
            return true;
        }
    });

    // Recreate the TextView
    TextView tv = new TextView(mContext);
    tv.setLayoutParams(params);
    tv.setBackgroundColor(Color.TRANSPARENT);
    tv.setGravity(Gravity.CENTER);
    tv.setText(state.getText());
    tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20);
    tv.setTextColor(Color.BLACK);

    sticker.addView(tv);
    mConstraintLayout.addView(sticker);
}

4. Clean Up onRestoreInstanceState

You can remove your original onRestoreInstanceState method since we're handling restoration directly in onCreate. If you prefer to keep it, move the restoration logic there (just make sure to call super.onRestoreInstanceState(savedInstanceState) first).

Key Takeaways

  • Save everything you need: Don't skip unique properties like color or size—if it makes your CardView distinct, it needs to be saved.
  • Reuse code: The recreateCardView helper keeps your code clean and avoids repetition between creating new CardViews and restoring old ones.
  • Follow super method order: Always call the superclass's save/restore methods first to avoid overriding system behavior.

内容的提问来源于stack exchange,提问作者matthausen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:49:09