之前在分析科室的疑难杂症中遇到一个问题,wifi的开关在横竖屏切换后,开关状态变化了,由开变为了关,如果是关的状态,切换后是关的状态(或者是由关变为了开,如果是开的状态,切换后是开的状态)。后来写了个demo,实现这种情况,demo所涉及到的原理是一样的,只是设置中代码盘综复杂,所以那个实际的wifi开关的问题,要复杂一些。
操作视频如下所示
横竖屏切换后开关状态变化
Mainactivity.java的布局文件
<com.fw.mytest.myLayout
android:id="@+id/myLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</com.fw.mytest.myLayout>
<com.fw.mytest.myLayout
android:id="@+id/myLayout2"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</com.fw.mytest.myLayout>
myLayout是自定义控件,类如下,布局文件my_layout没什么特别的,就一个TextView,一个Switch
public class myLayout extends LinearLayout {
public Switch mSwitch;
public myLayout(Context paramContext, AttributeSet paramAttributeSet) {
super(paramContext, paramAttributeSet);
LayoutInflater.from(paramContext).inflate(R.layout.my_layout, (ViewGroup)this);
mSwitch = findViewById(R.id.mySwitch);
boolean isChecked = mSwitch.isChecked();
Log.d("myLayout","mj_isChecked:"+isChecked+"mSwitch:"+mSwitch.hashCode());
}
@Override
public Parcelable onSaveInstanceState() {
Log.d("myLayout","mj_onSaveInstanceState_isChecked:"+mSwitch.isChecked());
return super.onSaveInstanceState();
}
@Override
public void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
Log.d("myLayout","mj_onRestoreInstanceState_isChecked:"+mSwitch.isChecked());
}
}
Mainactivity的代码如下:
public class MainActivity extends AppCompatActivity {
private myLayout myLayout1;
private myLayout myLayout2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myLayout1 = (myLayout)findViewById(R.id.myLayout1);
myLayout2 = (myLayout)findViewById(R.id.myLayout2);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
boolean mSwitch1 = myLayout1.mSwitch.isChecked();
boolean mSwitch2 = myLayout2.mSwitch.isChecked();
Log.d("MainActivity","mj_onSaveInstanceState_mSwitch1:"+mSwitch1+",mSwitch2:"+mSwitch2);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
boolean mSwitch1 = myLayout1.mSwitch.isChecked();
boolean mSwitch2 = myLayout2.mSwitch.isChecked();
Log.d("MainActivity","mj_onRestoreInstanceState_mSwitch1:"+mSwitch1+",mSwitch2:"+mSwitch2);
}
}
横竖屏切换,主要log如下
01-18 11:13:15.159 24437 24437 D myLayout: mj_onSaveInstanceState_isChecked:false
01-18 11:13:15.159 24437 24437 D myLayout: mj_onSaveInstanceState_isChecked:true
01-18 11:13:15.159 24437 24437 D MainActivity: mj_onSaveInstanceState_mSwitch1:false,mSwitch2:true
01-18 11:13:15.327 24437 24437 D myLayout: mj_isChecked:falsemSwitch:232238890
01-18 11:13:15.333 24437 24437 D myLayout: mj_isChecked:falsemSwitch:222704312
01-18 11:13:15.339 24437 24437 D myLayout: mj_onRestoreInstanceState_isChecked:false
01-18 11:13:15.343 24437 24437 D myLayout: mj_onRestoreInstanceState_isChecked:false
01-18 11:13:15.343 24437 24437 D MainActivity: mj_onRestoreInstanceState_mSwitch1:true,mSwitch2:true
在MainActivity.java中onRestoreInstanceState方法中,恢复时,两个开关都变为了true。原因是因为他们ID是一样的,所以获取到的状态都是true。解决该问题,在onSaveInstanceState中主动保存下状态值。
控件Switch的状态值的onSaveInstanceState流程
Activity.java --onSaveInstanceState
PhoneWindow.java --saveHierarchyState
View.java --saveHierarchyState–dispatchSaveInstanceState
按ID值去保存的container.put(mID, state);
onRestoreInstanceState流程
Activity.java --onRestoreInstanceState
PhoneWindow.java --restoreHierarchyState
View.java --restoreHierarchyState–dispatchRestoreInstanceState
是按ID获取状态值的Parcelable state = container.get(mID);
在View.java中dispatchSaveInstanceState和dispatchRestoreInstanceState中添加log,以及MainActivity中添加打印switch的id的log
//dispatchSaveInstanceState,switch走了两次,值分别为false、true
01-01 20:53:30.449 4191 4191 D View : mj_dispatchSaveInstanceState_mID:2131165252,state:CompoundButton.SavedState{cf53bde checked=false}
01-01 20:53:30.453 4191 4191 D View : mj_dispatchSaveInstanceState_mID:2131165252,state:CompoundButton.SavedState{3c483d5 checked=true}
//dispatchRestoreInstanceState,switch走了两次,两次都是true
01-01 20:53:30.586 4191 4191 D myLayout: mj_onRestoreInstanceState_isChecked:false,mSwitchId:2131165252
01-01 20:53:30.590 4191 4191 D View : mj_dispatchRestoreInstanceState_mID:2131165252,state:CompoundButton.SavedState{3c483d5 checked=true}
01-01 20:53:30.593 4191 4191 D myLayout: mj_onRestoreInstanceState_isChecked:false,mSwitchId:2131165252
01-01 20:53:30.594 4191 4191 D View : mj_dispatchRestoreInstanceState_mID:2131165252,state:CompoundButton.SavedState{3c483d5 checked=true}
//可以看到两个switch的id是相同的
01-01 20:53:30.600 4191 4191 D MainActivity: mj_onRestoreInstanceState_mSwitch1:true,mSwitch2:true,mSwitch1Id:2131165252,mSwitch2Id:2131165252
另外,myLayout中的onRestoreInstanceState在view的dispatchRestoreInstanceState方法前执行的,所以打印的switch的状态是false