问题
最近开发的时候发现Activity横屏之后,布局发生错乱,找了好久没有问题,研究AutoSize看出了一点问题。
分析
我们从源码的角度查看一下问题
AutoSize初始化注册横竖屏监听,每次横竖屏都会回调该监听
AutoSizeConfig#init(final Application application, boolean isBaseOnWidth, AutoAdaptStrategy strategy)
AutoSizeConfig init(final Application application, boolean isBaseOnWidth, AutoAdaptStrategy strategy) {
···
application.registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (newConfig != null) {
if (newConfig.fontScale > 0) {
mInitScaledDensity =
Resources.getSystem().getDisplayMetrics().scaledDensity;
AutoSizeLog.d("initScaledDensity = " + mInitScaledDensity + " on ConfigurationChanged");
}
isVertical = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT;
int[] screenSize = ScreenUtils.getScreenSize(application);
mScreenWidth = screenSize[0];
mScreenHeight = screenSize[1];
}
}
@Override
public void onLowMemory() {
}
});
}
当每次进入Activity的时候都会根据AutoSizeConfig初始化设置的参考值进行初始化 activity.getResources().getDisplayMetrics();通过setDensity()、
setScreenSizeDp()重新赋值。
AutoSize#autoConvertDensity(Activity activity, float sizeInDp, boolean isBaseOnWidth)
public static void autoConvertDensity(Activity activity, float sizeInDp, boolean isBaseOnWidth) {
···
setDensity(activity, targetDensity, targetDensityDpi, targetScaledDensity, targetXdpi);
setScreenSizeDp(activity, targetScreenWidthDp, targetScreenHeightDp);
AutoSizeLog.d(String.format(Locale.ENGLISH, "The %s has been adapted! \n%s Info: isBaseOnWidth = %s, %s = %f, %s = %f, targetDensity = %f, targetScaledDensity = %f, targetDensityDpi = %d, targetXdpi = %f, targetScreenWidthDp = %d, targetScreenHeightDp = %d"
, activity.getClass().getName(), activity.getClass().getSimpleName(), isBaseOnWidth, isBaseOnWidth ? "designWidthInDp"
: "designHeightInDp", sizeInDp, isBaseOnWidth ? "designWidthInSubunits" : "designHeightInSubunits", subunitsDesignSize
, targetDensity, targetScaledDensity, targetDensityDpi, targetXdpi, targetScreenWidthDp, targetScreenHeightDp));
}
问题出在横竖屏之后,Activity的Resources()重新创建了,而AutoSize没有重新给它赋值,导致UI使用的是默认的Resources()参数渲染。
解决
我们通过AutoSize#autoConvertDensityOfGlobal()重新给Activity的Resources()赋值,这也是网上解决的方案。
@Override public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
AutoSizeConfig.getInstance().setScreenWidth(ScreenUtils.getScreenSize(this)[0]);
AutoSizeConfig.getInstance().setScreenHeight(ScreenUtils.getScreenSize(this)[1]);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
//横屏 640设计图上的总高度
AutoSize.autoConvertDensityBaseOnHeight(this, 640);
Log.i(TAG, "onConfigurationChanged: 横屏" + newConfig.orientation);
} else {
//竖屏
AutoSize.autoConvertDensityOfGlobal(this);
Log.i(TAG, "onConfigurationChanged: 竖屏" + newConfig.orientation);
}
}
这两句特别重要,由于Activity#onConfigurationChanged()执行快于application#registerComponentCallbacks()#onConfigurationChanged(),则先需要重新设置屏幕宽高,再去重新更新Resources()。
AutoSizeConfig.getInstance().setScreenWidth(ScreenUtils.getScreenSize(this)[0]);
AutoSizeConfig.getInstance().setScreenHeight(ScreenUtils.getScreenSize(this)[1]);