我写了一个很大的自定义视图,它覆盖了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
根本没有还原。出于调试目的,我在
MyCustomView
的MyCustomView
和onSaveInstanceState()
中放入了Log.d(...),我注意到没有调用onRestoreInstanceState(Parcelable state)
。您是否知道为什么当我使用AsyncTask填充
onRestoreInstanceState(Parcelable state)
时为什么不调用onRestoreInstanceState(Parcelable state)
,而当我在UI线程上完全创建mRootLayout
时却确实调用了它?谢谢。
编辑:我发布
MyCustomView
的onSaveInstanceState()
和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.onPostExecute
,Activity.onStart
,Activity.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/