Android奇葩问题全纪录-(一)

1. android使用fragment制作的tab页,当主界面切换到后台,在系统内存不足的情况下,主界面被系统强制回收后又被重新create造成fragment重叠。


主界面的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);
    }

2. App打包成apk后在部分手机上安装,安装完成后直接点击系统安装界面上的打开按钮后点击home键到home页,再点击启动图标,应用重复启动(该问题只出现在第一次安装app的时候,之后退出app再重新运行,点击home,再点击启动图标不会出现该问题)


解决方案,在启动页增加代码判断,如果启动的Activity不是当前任务的根Activity则直接finish掉,代码如下:

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        setTheme(R.style.AppTheme_NoActionBar);
        super.onCreate(savedInstanceState);

        //判断根Activity代码
        if (!isTaskRoot()) {
            finish();
            return;
        }
    }

3. 应用调用系统相机后,返回应用数据丢失,应用崩溃等


在手机上调用系统相机的时候,有很大的几率会导致内存不足从而调用相机的app或者app的调用相机的Activity界面被强制回收,所以调用相机的Activity重写onSaveInstanceState是非常必要的,在onSaveInstanceState方法中将局部变量保存起来,同时在onRestoreInstanceState方法中重新获取这些局部变量并做必要的逻辑处理。


4. 在部分老旧机型上,调用系统相机报Activity Not Found 异常


出现这种错误一般两种情况:

  1. 部分设备没有自带摄像头
  2. 部分设备没有sd卡

为了处理这两种情况,在启动相机的时候做了简单的判断:

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);
        }

    }

5. 在Android 4.1等设备上使用EventBus报aused by: java.lang.ClassNotFoundException: Didn’t find class “android.os.PersistableBundle” on path: DexPathList


造成这个错误的原因一般是无意中重写了onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState)这个方法,检查下自己的代码,使用onSaveInstanceState(Bundle outState)来处理你的代码逻辑

6. 引入图片框架fresco后,出现is 32-bit instead of 64-bit的错误


因为项目中引用了其他第三方的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的错误。

解决方案:

  1. 为项目已经引用的so库添加对应arm64-v8架构的so库。
  2. 在gradle的defaultConfig中设置

    ndk {
      // 设置支持的 SO 库构架,注意这里要根据你的实际情况来设置
     abiFilters 'armeabi' , 'x86'
    }

你可能感兴趣的:(android)