本文记录了项目,从support库,迁移到了最新的androidx库,迁移后一些兼容性问题处理。
迁移过程很顺利,后续自动化测试发现有两个问题,都是关于FloatingActionButton
的
1、崩溃 android.os.BadParcelableException: ClassNotFoundException when unmarshalling
复现条件:首页有FloatingActionButton
,子页模拟app杀死重建。退出子页回到首页,崩溃。
原因:我们继承了FloatingActionButton
,重写了保存恢复函数,在恢复的时候,ClassLoader为Null导致崩溃。
详细可以参考:https://wangchao.im/2016/10/12/android-badpracelableexception/
解决办法:使用系统提供的方法保存、恢复View的数据。
核心类
public class XLViewSavedStateHelper {
private static final String BUNDLE_KEY = "XL_VIEW_BUNDLE_KEY";
public static Bundle saveState(Parcelable parcelable) {
if (parcelable == null) return null;
if (parcelable instanceof Bundle) return (Bundle) parcelable;
Bundle bundle = new Bundle();
bundle.putParcelable(BUNDLE_KEY, parcelable);
return bundle;
}
public static Parcelable getXLSaveParcelable(Parcelable state) {
if (state instanceof Bundle) {
return ((Bundle) state).getParcelable(BUNDLE_KEY);
}
return null;
}
public static boolean isXLSave(Parcelable parcelable) {
return parcelable instanceof Bundle && ((Bundle) parcelable).getParcelable(BUNDLE_KEY) != null;
}
}
使用方式
private static final String KEY_PASSED_TIME = "KEY_PASSED_TIME";
private static final String KEY_SYSTEM_CLOCK_TIME = "KEY_SYSTEM_CLOCK_TIME";
@Override
public Parcelable onSaveInstanceState() {
Bundle bundle = XLViewSavedStateHelper.saveState(super.onSaveInstanceState());
if (bundle != null) {
bundle.putLong(KEY_PASSED_TIME, mPassedTime);
bundle.putLong(KEY_SYSTEM_CLOCK_TIME, SystemClock.elapsedRealtime());
}
return bundle;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
if (!XLViewSavedStateHelper.isXLSave(state)) {
super.onRestoreInstanceState(state);
return;
}
super.onRestoreInstanceState(XLViewSavedStateHelper.getXLSaveParcelable(state));
Bundle bundle = (Bundle) state;
long passedTime = bundle.getLong(KEY_PASSED_TIME);
long systemTime = bundle.getLong(KEY_SYSTEM_CLOCK_TIME);
mPassedTime = passedTime + SystemClock.elapsedRealtime() - systemTime;
}
2、同时操作FloatingActionButton
,按钮图标丢失
复现条件:首页fab按钮,多个tab下的子页会去同时更新按钮状态,fab的图标丢失了。
原因:在androidX上出现,support库里的FloatingActionButton
不会有这个问题。排查源码未找到原因
解决办法:限制更新频率,本质上来说,fab按钮只由当前页面来管理,其余不可见的页面,发出的更新请求应该被过滤掉。
观察了下很多更新请求,setImageResource()
的操作都是同样的图片源,因此也可以简单粗暴的解决这个问题。
public class SafeFloatingActionButton extends FloatingActionButton {
private Integer mPreviousRes;
public SafeFloatingActionButton(Context context) {
super(context);
}
public SafeFloatingActionButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SafeFloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void setImageResource(int resId) {
if (mPreviousRes != null && mPreviousRes == resId) return;
mPreviousRes = resId;
super.setImageResource(resId);
}
}
总结
安卓因为历史原因,有supportV4、supportV7两大库,现在androidX可以终结掉这个分裂现象。官方提供的升级指引很简单方便,咱千万用户的app迁移下来很顺利,只发现这两处问题。
彩蛋
经过迁移后,项目里面搜.support.
找到了android.support.FILE_PROVIDER_PATHS
,这个7.0引入的FileProvider,路径就是这样的哦,设计如此。
<provider
android:name=".file.XLFileProvider"
android:authorities="${applicationId}.xlcore.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/xl_file_paths"/>
</provider>