onRestoreInstanceState

onRestoreInstanceState

我写了一个很大的自定义视图,它覆盖了onSaveInstanceState()onRestoreInstanceState(Parcelable state)

我想用我的自定义视图填充LinearLayout,因此编写了以下代码:

public class MainActivity extends Activity {

    private LinearLayout    mRootLayout;

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

        mRootLayout = (LinearLayout) findViewById(R.id.root_layout);

        int i;

        // Test: adding 10 instances of MyCustomView.
        for (i = 0; i < 10; ++i) {
            MyCustomView cv = new MyCustomView(this);

            // I set an ID for this view so that onSaveInstanceState() and
            // onRestoreInstanceState(Parcelable state) will be called
            // automatically.
            cv.setId(++i);

            mRootLayout.addView(cv);
        }
    }

    // ...
}


它工作正常-mRootLayout确实由10个MyCustomView实例填充,并且MyCustomView的每个实例在例如屏幕旋转后都已正确还原。

我注意到,由于MyCustomView很大,我的代码在UI线程上很繁琐。

为了解决该问题并减轻UI线程的负担,我决定使用自定义AsyncTask,它将在MyCustomView中创建doInBackground()的实例并将其添加到mRootLayout)中。 cc>。

以下代码是我的自定义AsyncTask:

private class LoadMyCustomViewTask extends AsyncTask<Void, Void, MyCustomView> {

    private Context         mContext;
    private LinearLayout    mLayoutToPopulate;
    private int             mId;

    public LoadMyCustomViewTask(Context context, LinearLayout layout, int id) {
        mContext = context;
        mLayoutToPopulate = layout;
        mId = id;
    }

    @Override
    protected MyCustomView doInBackground(Void... params) {

        MyCustomView cv = new MyCustomView(mContext);

        return cv;
    }

    @Override
    protected void onPostExecute(MyCustomView result) {

        result.setId(mId);
        mLayoutToPopulate.addView(result);
    }
}


onPostExecute()中,我按以下方式使用它:

public class MainActivity extends Activity {

    private LinearLayout    mRootLayout;

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

        mRootLayout = (LinearLayout) findViewById(R.id.root_layout);

        int i;

        for (i = 0; i < 10; ++i) {

            new LoadMyCustomViewTask(this, mRootLayout, ++i).execute();
        }
    }
    // ...
}


该代码也可以使用,但是只有一个问题-MainActivity根本没有还原。

出于调试目的,我在MyCustomViewMyCustomViewonSaveInstanceState()中放入了Log.d(...),我注意到没有调用onRestoreInstanceState(Parcelable state)

您是否知道为什么当我使用AsyncTask填充onRestoreInstanceState(Parcelable state)时为什么不调用onRestoreInstanceState(Parcelable state),而当我在UI线程上完全创建mRootLayout时却确实调用了它?

谢谢。

编辑:我发布MyCustomViewonSaveInstanceState()onRestoreInstanceState()方法

@Override
protected Parcelable onSaveInstanceState() {
    debug("onSaveInstanceState()");
    Bundle state = new Bundle();
    state.putParcelable(_BUNDLE_KEY_PARENT_STATE, super.onSaveInstanceState());
    state.putBooleanArray(_BUNDLE_KEY_CLICKED_VIEWS, mClickedViews);
    return state;
}

@Override
protected void onRestoreInstanceState(Parcelable state) {
    debug("onRestoreInstanceState(Parcelable state)");
    if (state instanceof Bundle) {
        Bundle bundle = (Bundle) state;
        mClickedViews = bundle.getBooleanArray(_BUNDLE_KEY_CLICKED_VIEWS);
        state = bundle.getParcelable(_BUNDLE_KEY_PARENT_STATE);
    }

    super.onRestoreInstanceState(state);
}

最佳答案

视图状态还原从根视图开始,然后向下移动到当时附加的所有子视图。这可以在ViewGroup.dispatchRestoreInstanceState方法中看到。这意味着,只有在调用Activity.onRestoreInstanceState时视图属于视图层次结构的一部分,Android才能还原视图。

使用AsyncTask,您可以异步创建视图,然后安排它们在主循环器闲置后的某个时间添加。考虑到生命周期,Android仅允许您在AsyncTask.onPostExecuteActivity.onStartActivity.onRestoreInstanceState等被调用后运行Activity.onResume。您的视图添加到布局的时间太晚,无法进行自动恢复。

如果将日志语句添加到上述那些方法以及AsyncTask.onPostExecute,您将能够看到排序/定时在实际情况中如何发挥作用。即使所有代码都发生在主线程上,下面的代码也会在Activity.onRestoreInstanceState之后运行,这仅仅是因为调度:

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

    new Handler().post(new Runnable() {
        @Override
        public void run() {
            Log.i("TAG", "when does this run?");
        }
    });

    ...
}

关于java - 将自定义 View 从AsyncTask的onPostExecute()添加到布局后,无法还原,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21468814/

10-10 20:24