Android自定义视图会在方向更改时重新创建两次,第二次没有onRestoreInstanceState
我创建了一个自定义视图,它是Android自定义视图会在方向更改时重新创建两次,第二次没有onRestoreInstanceState,android,android-layout,android-custom-view,Android,Android Layout,Android Custom View,我创建了一个自定义视图,它是RelativeLayout的子类。视图是片段集合的一部分,用于保留其实例状态。我想在设备方向更改时保存状态信息(仅一个布尔值),因此我使用自定义扩展名BaseSavedState实现了onSaveInstanceState和onRestoreInstanceState。无论是片段,还是活动都没有实现任何有关保存/恢复实例状态的操作。当我更改设备方向时,它会保存状态,用保存的状态重新创建视图,然后再次重新创建视图,而不调用onRestoreInstanceState
RelativeLayout
的子类。视图是片段
集合的一部分,用于保留其实例状态。我想在设备方向更改时保存状态信息(仅一个布尔值),因此我使用自定义扩展名BaseSavedState
实现了onSaveInstanceState
和onRestoreInstanceState
。无论是片段
,还是活动
都没有实现任何有关保存/恢复实例状态的操作。当我更改设备方向时,它会保存状态,用保存的状态重新创建视图,然后再次重新创建视图,而不调用onRestoreInstanceState
事件顺序如下,showingProgress
是我要保存的布尔值:
View#1 (onSaveInstanceState) showingProgress=true
View#2 (ctor) showingProgress=false
View#2 (onFinishInflate)
View#2 (onRestoreInstanceState) showingProgress=true
View#2 (showProgress)
View#2 (onSaveInstanceState) showingProgress=true
View#3 (ctor) showingProgress=false
View#3 (onFinishInflate)
之后,将重建视图,但由于从未为视图#3调用onRestoreInstanceState
,因此视图始终处于初始状态
为什么要重新创建视图两次?
如何防止再次创建第二个视图,或将保存的状态分别传递给第三个视图
编辑:
活动的相关部分
private Fragment currentFragment = null;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.single_fragment);
getSupportActionBar().setDisplayShowTitleEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().show();
showLoginFragment();
}
public void showLoginFragment()
{
final FragmentTransaction t = this.getSupportFragmentManager().beginTransaction();
currentFragment = MyFragment.newInstance();
t.replace(R.id.layoutRoot, currentFragment);
t.commit();
}
布局single_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/layoutRoot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
</ScrollView>
布局my_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.my.package.ProgressButton
android:id="@+id/myButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/button_caption" />
</LinearLayout>
最后是进程按钮的代码
/**
* A Button with an integrated progress spinner. The button can show the progress spinner while some background process
* is running to indicate it can't be clicked again.
*/
public class ProgressButton extends RelativeLayout
{
/** The view holding the button text */
private TextView textView = null;
/** The progress spinner */
private ProgressBar progressSpinner = null;
private boolean showingProgress = false;
public ProgressButton(Context context)
{
super(context);
textView = new TextView(context);
progressSpinner = new ProgressBar(context);
initView();
}
public ProgressButton(Context context, AttributeSet attrs)
{
super(context, attrs);
textView = new TextView(context, attrs);
progressSpinner = new ProgressBar(context, attrs);
initView();
}
public ProgressButton(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
textView = new TextView(context, attrs, defStyle);
progressSpinner = new ProgressBar(context, attrs, defStyle);
initView();
}
/**
* Initializes the view with all its properties.
*/
@SuppressWarnings("deprecation")
private void initView()
{
// remove the background attributes from progressbar and textview, because they should be transparent
if (Build.VERSION.SDK_INT >= 16)
{
textView.setBackground(null);
progressSpinner.setBackground(null);
}
else
{
textView.setBackgroundDrawable(null);
progressSpinner.setBackgroundDrawable(null);
}
}
@Override
protected void onFinishInflate()
{
super.onFinishInflate();
if (!isInEditMode())
{
progressSpinner.setVisibility(View.INVISIBLE);
}
RelativeLayout layout = new RelativeLayout(getContext());
layout.setId(R.id.progressButtonContainer);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
this.addView(layout, params);
params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_LEFT);
params.leftMargin = 10;
progressSpinner.setClickable(false);
progressSpinner.setId(R.id.progressButtonProgress);
layout.addView(progressSpinner, params);
params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
textView.setClickable(false);
textView.setId(R.id.progressButtonText);
layout.addView(textView, params);
}
/**
* Disables the button and shows the progress spinner.
*/
public void showProgress()
{
this.setEnabled(false);
progressSpinner.setVisibility(View.VISIBLE);
showingProgress = true;
}
/**
* Enables the button and hides the progress spinner.
*/
public void hideProgress()
{
this.setEnabled(true);
progressSpinner.setVisibility(View.INVISIBLE);
showingProgress = false;
}
@Override
public Parcelable onSaveInstanceState()
{
Parcelable superState = super.onSaveInstanceState();
return new SavedState(superState, showingProgress);
}
@Override
public void onRestoreInstanceState(Parcelable state)
{
SavedState savedState = (SavedState) state;
super.onRestoreInstanceState(savedState.getSuperState());
showingProgress = savedState.showProgress;
if(showingProgress)
{
showProgress();
}
else
{
hideProgress();
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
protected void dispatchSaveInstanceState(SparseArray container)
{
super.dispatchFreezeSelfOnly(container);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
protected void dispatchRestoreInstanceState(SparseArray container)
{
super.dispatchThawSelfOnly(container);
}
static class SavedState extends BaseSavedState
{
boolean showProgress = false;
SavedState(Parcelable superState, boolean showProgress)
{
super(superState);
this.showProgress = showProgress;
}
private SavedState(Parcel in)
{
super(in);
this.showProgress = in.readByte() == 0 ? false : true;
}
@Override
public void writeToParcel(Parcel out, int flags)
{
super.writeToParcel(out, flags);
out.writeByte((byte) (showProgress ? 1 : 0));
}
// 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];
}
};
}
}
/**
*带有集成进度微调器的按钮。该按钮可以在后台处理时显示进度微调器
*正在运行,表示无法再次单击。
*/
公共类ProgressButton扩展了RelativeLayout
{
/**保存按钮文本的视图*/
私有TextView TextView=null;
/**进度微调器*/
私有ProgressBar progressSpinner=null;
私有布尔值showingProgress=false;
公共进程按钮(上下文)
{
超级(上下文);
textView=新的textView(上下文);
progressSpinner=新的ProgressBar(上下文);
initView();
}
公共进程按钮(上下文上下文、属性集属性)
{
超级(上下文,attrs);
textView=新的textView(上下文,属性);
progressSpinner=新的ProgressBar(上下文,属性);
initView();
}
公共进程按钮(上下文上下文、属性集属性、int-defStyle)
{
超级(上下文、属性、定义样式);
textView=新的textView(上下文、属性、定义样式);
progressSpinner=新的ProgressBar(上下文、属性、定义样式);
initView();
}
/**
*初始化视图及其所有属性。
*/
@抑制警告(“弃用”)
私有void initView()
{
//从progressbar和textview中删除背景属性,因为它们应该是透明的
如果(Build.VERSION.SDK_INT>=16)
{
textView.setBackground(空);
progressSpinner.setBackground(空);
}
其他的
{
textView.setBackgroundDrawable(空);
progressSpinner.setBackgroundDrawable(空);
}
}
@凌驾
充气时受保护的空隙()
{
超级充气();
如果(!isInEditMode())
{
progressSpinner.setVisibility(View.INVISIBLE);
}
RelativeLayout布局=新的RelativeLayout(getContext());
布局。设置id(R.id.progressButtonContainer);
RelativeLayout.LayoutParams params=新的RelativeLayout.LayoutParams(LayoutParams.MATCH_父项,LayoutParams.WRAP_内容);
此.addView(布局、参数);
params=新的RelativeLayout.LayoutParams(LayoutParams.WRAP\u内容,LayoutParams.WRAP\u内容);
参数addRule(相对左对齐);
params.leftMargin=10;
progressSpinner.setClickable(错误);
progressSpinner.setId(R.id.progressButtonProgress);
layout.addView(progressSpinner,params);
params=新的RelativeLayout.LayoutParams(LayoutParams.WRAP\u内容,LayoutParams.WRAP\u内容);
参数addRule(父项中的相对位置居中);
textView.setClickable(错误);
setId(R.id.progressButtonText);
layout.addView(文本视图,参数);
}
/**
*禁用该按钮并显示进度微调器。
*/
公共服务进展
{
此.setEnabled(false);
progressSpinner.setVisibility(View.VISIBLE);
显示进展=正确;
}
/**
*启用按钮并隐藏进度微调器。
*/
public void hideProgress()
{
此.setEnabled(true);
progressSpinner.setVisibility(View.INVISIBLE);
显示进度=错误;
}
@凌驾
公共地块可在SaveInstanceState()上使用
{
可包裹的超级状态=super.onSaveInstanceState();
返回新的SavedState(超级状态,显示进度);
}
@凌驾
RestoreInstanceState(可包裹状态)上的公共无效
{
SavedState SavedState=(SavedState)状态;
super.onRestoreInstanceState(savedState.getSuperState());
showingProgress=savedState.showProgress;
如果(显示进度)
{
showProgress();
}
其他的
{
hideProgress();
}
}
@SuppressWarnings({“unchecked”,“rawtypes”})
@凌驾
受保护的void dispatchSaveInstanceState(SparseArray容器)
{
超级发货单(集装箱);
}
@SuppressWarnings({“unchecked”,“rawtypes”})
@凌驾
受保护的无效dispatchRestoreInstanceState(SparseArray容器)
{
超级发货单(集装箱);
}
静态类SavedState扩展了BaseSavedState
{
布尔值showProgress=false;
SavedState(可包裹的超级状态,布尔showProgress)
{
苏佩
/**
* A Button with an integrated progress spinner. The button can show the progress spinner while some background process
* is running to indicate it can't be clicked again.
*/
public class ProgressButton extends RelativeLayout
{
/** The view holding the button text */
private TextView textView = null;
/** The progress spinner */
private ProgressBar progressSpinner = null;
private boolean showingProgress = false;
public ProgressButton(Context context)
{
super(context);
textView = new TextView(context);
progressSpinner = new ProgressBar(context);
initView();
}
public ProgressButton(Context context, AttributeSet attrs)
{
super(context, attrs);
textView = new TextView(context, attrs);
progressSpinner = new ProgressBar(context, attrs);
initView();
}
public ProgressButton(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
textView = new TextView(context, attrs, defStyle);
progressSpinner = new ProgressBar(context, attrs, defStyle);
initView();
}
/**
* Initializes the view with all its properties.
*/
@SuppressWarnings("deprecation")
private void initView()
{
// remove the background attributes from progressbar and textview, because they should be transparent
if (Build.VERSION.SDK_INT >= 16)
{
textView.setBackground(null);
progressSpinner.setBackground(null);
}
else
{
textView.setBackgroundDrawable(null);
progressSpinner.setBackgroundDrawable(null);
}
}
@Override
protected void onFinishInflate()
{
super.onFinishInflate();
if (!isInEditMode())
{
progressSpinner.setVisibility(View.INVISIBLE);
}
RelativeLayout layout = new RelativeLayout(getContext());
layout.setId(R.id.progressButtonContainer);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
this.addView(layout, params);
params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_LEFT);
params.leftMargin = 10;
progressSpinner.setClickable(false);
progressSpinner.setId(R.id.progressButtonProgress);
layout.addView(progressSpinner, params);
params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
textView.setClickable(false);
textView.setId(R.id.progressButtonText);
layout.addView(textView, params);
}
/**
* Disables the button and shows the progress spinner.
*/
public void showProgress()
{
this.setEnabled(false);
progressSpinner.setVisibility(View.VISIBLE);
showingProgress = true;
}
/**
* Enables the button and hides the progress spinner.
*/
public void hideProgress()
{
this.setEnabled(true);
progressSpinner.setVisibility(View.INVISIBLE);
showingProgress = false;
}
@Override
public Parcelable onSaveInstanceState()
{
Parcelable superState = super.onSaveInstanceState();
return new SavedState(superState, showingProgress);
}
@Override
public void onRestoreInstanceState(Parcelable state)
{
SavedState savedState = (SavedState) state;
super.onRestoreInstanceState(savedState.getSuperState());
showingProgress = savedState.showProgress;
if(showingProgress)
{
showProgress();
}
else
{
hideProgress();
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
protected void dispatchSaveInstanceState(SparseArray container)
{
super.dispatchFreezeSelfOnly(container);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
protected void dispatchRestoreInstanceState(SparseArray container)
{
super.dispatchThawSelfOnly(container);
}
static class SavedState extends BaseSavedState
{
boolean showProgress = false;
SavedState(Parcelable superState, boolean showProgress)
{
super(superState);
this.showProgress = showProgress;
}
private SavedState(Parcel in)
{
super(in);
this.showProgress = in.readByte() == 0 ? false : true;
}
@Override
public void writeToParcel(Parcel out, int flags)
{
super.writeToParcel(out, flags);
out.writeByte((byte) (showProgress ? 1 : 0));
}
// 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];
}
};
}
}
if(savedInstanceState == null)
{
showLoginFragment();
}