Androidの奇抜な問題の全記録-(一)

8704 ワード

1.androidはfragmentで作成したtabページを使用し、メインインタフェースがバックグラウンドに切り替わり、システムメモリが不足している場合、メインインタフェースがシステムに強制回収された後、再びcreateされてfragmentが重なる.
メインインタフェースのtab切替はfragment切替を使用して実現されるため、メインactivityはv 7の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メソッドで渡されたsavedInstancesStateが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をパッケージ化した後、一部の携帯電話にインストールし、インストールが完了したら、直接システムインストール画面の開いたボタンをクリックし、ホームボタンをクリックしてホームページに移動し、起動アイコンをクリックし、繰り返し起動を適用する(この問題は最初にappをインストールしたときにのみ発生し、その後appを終了して再実行し、ホームをクリックし、起動アイコンをクリックしても問題は発生しない)
ソリューションは、起動ページにコード判定を追加し、起動した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異常を報告する
このようなエラーは、一般的に2つのケースで発生します.
  • 一部の機器にはカメラが備え付けられていない
  • 一部機器にsdカードがない
  • この2つの状況を処理するために、カメラを起動するときに簡単な判断をしました.
    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ライブラリが参照されていますが、arm 64-v 8ディレクトリのsoファイルはありません.frescoのライブラリファイルにはarm 64-v 8ディレクトリが作成されています.
    Androidがsoファイルを検索するルールに従って、Androidデバイスは対応するcpuアーキテクチャディレクトリを優先的に検索し、対応するディレクトリが見つからない場合はarmeabiディレクトリの下で互換的にsoファイルを呼び出すが、対応するディレクトリが検索できれば、そのディレクトリの下のsoライブラリのみを呼び出す.既存のsoライブラリに対応するディレクトリの下のsoファイルがなければ、対応するディレクトリsoライブラリが見つからないため、エラーが発生します.
    では、私のプロジェクトはarm 64-v 8のディレクトリを作成していません.なぜエラーが発生したのでしょうか.検査の結果、私たちのfrescoライブラリは互換性のため、デフォルトで対応するarm 64-v 8のライブラリディレクトリを作成していましたが、私のプロジェクトの他のsoライブラリには対応するarm 64-v 8アーキテクチャがありません.そのため、appはarm 64ビットデバイスにインストールされたときにarm 64-v 8のsoディレクトリを検索し、is 32-bit instead of 64-bitのエラーを報告します.
    ソリューション:
  • プロジェクトが参照したsoライブラリにarm 64-v 8アーキテクチャに対応するsoライブラリを追加します.
  • gradleのdefaultConfigに
    ndk {
      //       SO    ,                
     abiFilters 'armeabi' , 'x86'
    }
  • を設定