主界面的tab切换使用了fragment切换来实现,因此主activity继承自v7的AppCompatActivity,而AppCompatActivity继承自FragmentActivity
我们看下FragmentActivity中的onSaveInstanceState方法:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
if (mPendingFragmentActivityResults.size() > 0) { outState.putInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG,mNextCandidateRequestIndex);
int[] requestCodes = new int[mPendingFragmentActivityResults.size()];
String[] fragmentWhos = new String[mPendingFragmentActivityResults.size()];
for (int i = 0; i < mPendingFragmentActivityResults.size(); i++) {
requestCodes[i] = mPendingFragmentActivityResults.keyAt(i);
fragmentWhos[i] = mPendingFragmentActivityResults.valueAt(i);
}
outState.putIntArray(ALLOCATED_REQUEST_INDICIES_TAG, requestCodes);
outState.putStringArray(REQUEST_FRAGMENT_WHO_TAG, fragmentWhos);
}
}
在代码中有这么一段
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
FragmentActivity在onSaveInstanceState中保存了当前界面所有fragment的状态,这就导致了主界面activity在销毁后fragment被onSaveInstanceState保存了下来,在主界面Activity重新回到前台被系统重新创建的时候,原有的fragment的视图状态在FragmentActivity中被还原了回来,同时主界面Activity的oncreate方法又被重新执行了,于是导致了在已有fragment基础上重复创建了fragment。
下面是几种解决方案:
1.在oncreate中判断oncreate方法中传递过来的savedInstanceState是否为null,如果为null执行完整的fragment tab初始化工作,否则不执行初始化,思路代码如下:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
if (savedInstanceState != null) {
//界面正常情况下create时的逻辑
initTab();
}
else {
//界面在内存不足情况下被强制回收后重新create的逻辑
}
}
2.这种方法属于懒人方法的一种,在oncreate中在super.oncreate执行前将saveInstance中的fragment状态全部置空,这样在Activity被重新创建的时候原有的fragment都不会被恢复状态,而是按照Activity的正常create执行:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
if (savedInstanceState != null) {
savedInstanceState.putParcelable("android:support:fragments", null);
}
super.onCreate(savedInstanceState);
}
3.同样是懒人方法,重写onSaveInstanceState方法,注释对父saveInstanceState的调用,不过这么做会有很多副作用,系统自己实现的onSaveInstanceState就完全失去作用了,所以并不太推荐大家这么去做,参考代码:
@Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
// super.onSaveInstanceState(outState, outPersistentState);
}
解决方案,在启动页增加代码判断,如果启动的Activity不是当前任务的根Activity则直接finish掉,代码如下:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
setTheme(R.style.AppTheme_NoActionBar);
super.onCreate(savedInstanceState);
//判断根Activity代码
if (!isTaskRoot()) {
finish();
return;
}
}
在手机上调用系统相机的时候,有很大的几率会导致内存不足从而调用相机的app或者app的调用相机的Activity界面被强制回收,所以调用相机的Activity重写onSaveInstanceState是非常必要的,在onSaveInstanceState方法中将局部变量保存起来,同时在onRestoreInstanceState方法中重新获取这些局部变量并做必要的逻辑处理。
出现这种错误一般两种情况:
为了处理这两种情况,在启动相机的时候做了简单的判断:
private void showCamera() {
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_MOUNTED)) {
try {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
mTakePhotoUri = FileUtils.getOutputMediaFileUri(FileUtils.MEDIA_TYPE_IMAGE);
mFilePath = mTakePhotoUri.getPath();
intent.putExtra(MediaStore.EXTRA_OUTPUT, mTakePhotoUri);
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
} catch (ActivityNotFoundException e) {
showShortToast(R.string.error_no_camera);
}
}
else {
showShortToast(R.string.error_no_sdcard);
}
}
造成这个错误的原因一般是无意中重写了onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState)这个方法,检查下自己的代码,使用onSaveInstanceState(Bundle outState)来处理你的代码逻辑
因为项目中引用了其他第三方的so库,但是却没有arm64-v8目录的so文件,而fresco的库文件中却创建了arm64-v8的目录
按照Android查找so文件的规则,Android设备会优先查找对应的cpu架构目录,如果查找不到对应的目录,会到armeabi目录下兼容方式调用so文件,但是如果能查找到对应的目录,则只会调用该目录下的so库,如果已有的so库没有对应目录下的so文件,那么就会因为找不到对应目录so库从而造成错误。
那么我的项目并没有创建arm64-v8的目录,为什么会出错呢,经过检查后发现,原来我们的fresco库为了兼容性,默认创建了对应的arm64-v8的库目录,而我的项目中其他的so库并没有对应的arm64-v8架构的,所以导致app在安装到arm64位设备上的时候会到arm64-v8的so目录下去查找,从而报了is 32-bit instead of 64-bit的错误。
解决方案:
在gradle的defaultConfig中设置
ndk {
// 设置支持的 SO 库构架,注意这里要根据你的实际情况来设置
abiFilters 'armeabi' , 'x86'
}