自定义视图的状态已保存,但从未恢复

时间:2012-05-18 16:36:56

标签: android android-layout android-widget custom-controls android-view

我使用过的建议 How to prevent custom views from losing state across screen orientation changes但即使我的View正确保存了状态,也永远不会调用onRestoreInstanceState。调用Activity的恢复方法使事情变得更奇怪。

import java.text.DecimalFormat;
import java.text.NumberFormat;
import com.szyk.myheart.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Scroller;

public class NumberScroller extends View implements OnTouchListener{

    private final float VIEW_FILL_PERCENTAGE = 80;
    private final int MIN_VELOCITY_Y = 100;
    private final int VELOCITY_UNIT = 1000;
    private final String TAG = "NumberScroller";
    private final int ALIGNING_DURATION = 1000;

    private boolean isCustomizing = true;
    private boolean isDragged = false;
    private boolean isNewVelocityTracker = false;

    private Scroller scroller;
    private VelocityTracker velocityTracker;
    private float lastY;
    private int absoleteY;
    private float velocityY;
    private float ascent;
    private Integer maxScrollerNumber;
    private Integer minScrollerNumber;

    private Paint paintNumber;
    private Paint paintNumberActivated;
    private Paint paintBorder;
    private float textOffsetX;
    private Drawable foregroundBorder;
    private Drawable foregroundAlpha;
    private NumberFormat numberFormatter;


    /**
     * Initializes attributes and variables.
     * @param attrs - AttributeSet for Number Scroller
     * @param context in which scroller exists.
     */
    public NumberScroller(Context context, AttributeSet attrs) {
        super(context, attrs);
        Log.i(TAG, "Creating NumberScroller.");
        initAttrs(attrs, context);
        scroller = new Scroller(getContext());
        setOnTouchListener(this);

        foregroundAlpha = getResources().getDrawable(R.drawable.foreground_alpha);

        numberFormatter = new DecimalFormat();
        numberFormatter.setMinimumIntegerDigits(maxScrollerNumber.toString()
                .length());
        numberFormatter.setMinimumFractionDigits(0);

        setSaveEnabled(true);

    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
    }
    /**
     * (non-Javadoc)
     * @see android.view.View#onMeasure(int, int)
     */

/**
     * Initializes attributes from xml description.
     * @param attrs - AttributeSet for Number Scroller
     * @param context in which scroller exists.
     */
    private void initAttrs(AttributeSet attrs, Context context) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs,
                R.styleable.NumberScroller);
        maxScrollerNumber = typedArray.getInteger(
                R.styleable.NumberScroller_maximum, 99);
        minScrollerNumber = typedArray.getInteger(
                R.styleable.NumberScroller_minimum, 0);
        if (maxScrollerNumber < minScrollerNumber) {
            int tmp = minScrollerNumber;
            minScrollerNumber = maxScrollerNumber;
            maxScrollerNumber = tmp;
        }
        typedArray.recycle();
    }

V1:

@Override
  public Parcelable onSaveInstanceState() {
    Log.i(TAG,"SAve");
    //begin boilerplate code that allows parent classes to save state
    Parcelable superState = super.onSaveInstanceState();

    SavedState ss = new SavedState(superState);
    //end

    ss.stateToSave = absoleteY;

    return ss;
  }

  @Override
  public void onRestoreInstanceState(Parcelable state) {
      Log.i(TAG,"REstore");
    //begin boilerplate code so parent classes can restore state
    if(!(state instanceof SavedState)) {
      super.onRestoreInstanceState(state);
      return;
    }
    SavedState ss = (SavedState)state;
    super.onRestoreInstanceState(ss.getSuperState());
    //end

    absoleteY = ss.stateToSave;
  }

  public static class SavedState extends BaseSavedState {
   int stateToSave;

    SavedState(Parcelable superState) {
      super(superState);
    }

    private SavedState(Parcel in) {
      super(in);
      this.stateToSave = in.readInt();
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
      super.writeToParcel(out, flags);
      out.writeInt(this.stateToSave);
    }
    //required field that makes Parcelables from a Parcel
    public static final Parcelable.Creator<SavedState> CREATOR =
        new Parcelable.Creator<SavedState>() {
          public SavedState createFromParcel(Parcel in) {
            return new SavedState(in);
          }
          public SavedState[] newArray(int size) {
            return new SavedState[size];
          }
    };
  }

V2:

@Override
protected Parcelable onSaveInstanceState() {
    Log.i(TAG, "Saving state.");
    Bundle bundle = new Bundle();
    bundle.putParcelable("state", super.onSaveInstanceState());
    bundle.putInt("absoleteY", absoleteY);
    return bundle;
}

@Override
protected void onRestoreInstanceState(Parcelable state) {
    Log.i(TAG, "Restoring state");

    if(state instanceof Bundle){

        Bundle bundle = (Bundle) state;
        absoleteY = bundle.getInt("absoleteY");
        super.onRestoreInstanceState(bundle.getParcelable("state"));
        return;
    }

    super.onRestoreInstanceState(state); 
}

在日志中,我从未看到“恢复状态”。

看来如果我没有在android.support.v4.view.ViewPager中使用我的自定义视图,则会调用onRestoreInstanceState。有没有人知道原因,我是否必须在活动中调用保存/恢复?

1 个答案:

答案 0 :(得分:0)

这个问题已经很老了,但是我在谷歌搜索解决方案时偶然发现了这个问题,然后我发现了它。

问题可能是在根Activity的onCreate方法中以编程方式创建自定义视图。

解决方案是从包含ViewPager的根Activity调用onSaveInstanceState和onRestoreInstanceState,并以编程方式存储自定义视图的状态。

在您的根Activity中实现以下内容:

保存自定义视图的状态

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putParcelable("STATE_COLLECTION", collectionFrameLayout.onSaveInstanceState());
    super.onSaveInstanceState(outState);
}

在onCreate()内部,在创建自定义视图后将其恢复。

 if (savedInstanceState != null) {
     Parcelable state = savedInstanceState.getParcelable("STATE_COLLECTION");
     if (state != null) {
         collectionFrameLayout.onRestoreInstanceState(state);
     }
 }