Androidアプリ開発

UIスレッドでタイムアウトを回避する

この記事は約26分で読めます。
記事内に広告が含まれています。
スポンサーリンク

この記事は Android スマホ用のアプリ開発の中で、
今後の開発で再使用性が高いと思われるコーディングをまとめたものです。
Java での開発経験、XML 構文規則、Android のアプリ開発経験がある方を対象としています。
Android のアプリ開発でお役にたててれば、嬉しいです。
(これから Android のアプリ開発や Java での開発を始めたい方への案内は、
記事の最後で紹介します)

この記事のテーマ


UIスレッドで実行した処理がANRエラーを発生しないようにする

ポイント

UIスレッドで実行した処理が5秒以上応答がない場合、Input event dispatching timed outのANRエラーが発生します。
これを防ぐには、UIスレッドとは別スレッドで処理を実行する必要があります。

対応前

UIスレッドで実行した処理が5秒以上応答がない場合にANRエラーが発生します。
(ANRダイアログで「wait」を選択すれば、アプリ自体は落ちません)

◎Javaコーディング【対応前】

ActivityResultLauncher.launchで処理を呼び出します。
結果は、ActivityResultContracts.StartActivityForResultで受け取ります。
処理中のUIコンポーネントを無効化し、処理を実行する。
(無効化したUIコンポーネントを有効化は、処理終了後に行う)

	:
    // バックアップ
    private final ActivityResultLauncher<Intent> activityResultLauncher1 = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
            result -> {
                if (result.getResultCode() == Activity.RESULT_OK) {
                    if (result.getData() != null) {
                        download.setVisibility(View.INVISIBLE);
                        upload.setVisibility(View.INVISIBLE);
                        progressBar.setVisibility(android.widget.ProgressBar.VISIBLE);
                        getArchiveDatabase().dbExport(context, result.getData().getData());
  				    }
                }
            });
	:

◎Logcat出力結果

2021-12-13 09:20:36.633 19608-19608/? D/Documents: shouldRestrictStorageAccessFramework = true, packageName = com.gymtec.archivepro
2021-12-13 09:21:00.102 1724-2299/? I/WindowManager: Input event dispatching timed out sending to com.gymtec.archivepro/com.gymtec.archivepro.view.SystemActivity.  Reason: 9dc79eb com.gymtec.archivepro/com.gymtec.archivepro.view.SystemActivity (server) is not responding. Waited 5003ms for FocusEvent(hasFocus=true)
2021-12-13 09:21:00.149 1724-2299/? W/InputDispatcher: Canceling events for 9dc79eb com.gymtec.archivepro/com.gymtec.archivepro.view.SystemActivity (server) because it is unresponsive
2021-12-13 09:21:00.657 30829-30842/com.gymtec.archivepro I/mtec.archivepr: Thread[3,tid=30842,WaitingInMainSignalCatcherLoop,Thread*=0xb400007588473010,peer=0x12dc0318,"Signal Catcher"]: reacting to signal 3
2021-12-13 09:21:00.726 30829-30842/com.gymtec.archivepro I/mtec.archivepr: Wrote stack traces to tombstoned
2021-12-13 09:21:01.986 1724-2299/? I/InputDispatcher: 9dc79eb com.gymtec.archivepro/com.gymtec.archivepro.view.SystemActivity (server) spent 6888ms processing FocusEvent(hasFocus=true)
2021-12-13 09:21:06.016 1724-31369/? E/ActivityManager: ANR in com.gymtec.archivepro (com.gymtec.archivepro/.view.SystemActivity)
    PID: 30829
    Reason: Input dispatching timed out (9dc79eb com.gymtec.archivepro/com.gymtec.archivepro.view.SystemActivity (server) is not responding. Waited 5003ms for FocusEvent(hasFocus=true))
    Parent: com.gymtec.archivepro/.view.SystemActivity
    Load: 0.0 / 0.0 / 0.0
    ----- Output from /proc/pressure/memory -----
    some avg10=0.00 avg60=0.00 avg300=0.00 total=14703203
    full avg10=0.00 avg60=0.00 avg300=0.00 total=4851181
    ----- End output from /proc/pressure/memory -----
    
    CPU usage from 0ms to 5816ms later (2021-12-13 09:21:00.150 to 2021-12-13 09:21:05.966):
      34% 30829/com.gymtec.archivepro: 18% user + 15% kernel / faults: 8823 minor
        14% 30860/RenderThread: 7.4% user + 7% kernel
        13% 30829/mtec.archivepro: 5.8% user + 7.9% kernel
        1.5% 30846/HeapTaskDaemon: 1.5% user + 0% kernel
        1.2% 30842/Signal Catcher: 1% user + 0.1% kernel
        0.1% 30847/ReferenceQueueD: 0.1% user + 0% kernel
        0.1% 30851/Binder:30829_2: 0.1% user + 0% kernel
        0.1% 30853/Binder:30829_3: 0% user + 0.1% kernel
       +0% 31409/pool-15-thread-: 0% user + 0% kernel
      0.3% 1557/media.codec: 0.1% user + 0.1% kernel / faults: 46878 minor
        0% 1557/omx@1.0-service: 0% user + 0% kernel
        0% 16672/HwBinder:1557_C: 0% user + 0% kernel
        0% 16842/HwBinder:1557_1: 0% user + 0% kernel
        0% 17025/HwBinder:1557_1: 0% user + 0% kernel
        0% 3606/HwBinder:1557_3: 0% user + 0% kernel
        0% 16235/HwBinder:1557_6: 0% user + 0% kernel
        0% 16677/HwBinder:1557_E: 0% user + 0% kernel
        0% 16843/HwBinder:1557_1: 0% user + 0% kernel
        0% 1618/Binder:1557_2: 0% user + 0% kernel
        0% 16236/HwBinder:1557_7: 0% user + 0% kernel
        0% 16805/HwBinder:1557_1: 0% user + 0% kernel
        0% 1612/Binder:1557_1: 0% user + 0% kernel
        0% 16238/HwBinder:1557_8: 0% user + 0% kernel
        0% 16680/HwBinder:1557_1: 0% user + 0% kernel
        0% 17023/HwBinder:1557_1: 0% user + 0% kernel
        0% 1653/HwBinder:1557_2: 0% user + 0% kernel
        0% 16676/HwBinder:1557_D: 0% user + 0% kernel
        0% 16678/HwBinder:1557_F: 0% user + 0% kernel
        0% 16681/HwBinder:1557_1: 0% user + 0% kernel
        0% 16867/HwBinder:1557_1: 0% user + 0% kernel
        0% 16239/HwBinder:1557_9: 0% user + 0% kernel
        0% 16671/HwBinder:1557_B: 0% user + 0% kernel
        0% 16679/HwBinder:1557_1: 0% user + 0% kernel
        0% 16682/HwBinder:1557_1: 0% user + 0% kernel
        0% 16726/HwBinder:1557_1: 0% user + 0% kernel
        0% 16727/HwBinder:1557_1: 0% user + 0% kernel
        0% 16804/HwBinder:1557_1: 0% user + 0% kernel
        0% 16844/HwBinder:1557_1: 0% user + 0% kernel
        0% 17024/HwBinder:1557_1: 0% user + 0% kernel
        0% 1628/HwBinder:1557_1: 0% user + 0% kernel
        0% 3671/HwBinder:1557_4: 0% user + 0% kernel
        0% 16231/HwBinder:1557_5: 0% user + 0% kernel
        0% 16240/HwBinder:1557_A: 0% user + 0% kernel
        0% 16868/HwBinder:1557_1: 0% user + 0% kernel
      24% 1724/system_server: 13% user + 11% kernel / faults: 8548 minor
        7.5% 31369/AnrConsumer: 1.8% user + 5.6% kernel
        6.2% 14553/Binder:1724_1F: 4.1% user + 2% kernel
        3.6% 1739/Signal Catcher: 2.4% user + 1.2% kernel
        3.2% 13275/Binder:1724_13: 2.2% user + 1% kernel
        0.6% 1743/HeapTaskDaemon: 0.6% user + 0% kernel
        0.5% 1724/Binder:1724_3: 0.3% user + 0.1% kernel
        0.5% 13253/Binder:1724_11: 0.5% user + 0% kernel
        0.5% 14550/Binder:1724_1C: 0.3% user + 0.1% kernel
        0.1% 1744/ReferenceQueueD: 0.1% user + 0% kernel
        0.1% 2015/android.ui: 0% user + 0.1% kernel
        0.1% 2016/android.io: 0.1% user + 0% kernel
        0.1% 2025/ActivityManager: 0.1% user + 0% kernel
        0.1% 2286/Binder:1724_4: 0.1% user + 0% kernel
        0.1% 3426/WifiHandlerThre: 0% user + 0.1% kernel
        0.1% 20804/RenderThread: 0.1% user + 0% kernel
      20% 1210/surfaceflinger: 9.8% user + 10% kernel / faults: 536 minor
        10% 1210/surfaceflinger: 6.2% user + 4.4% kernel
        1.7% 1451/app: 0.5% user + 1.2% kernel
        1.5% 1249/Binder:1210_2: 0.1% user + 1.3% kernel
        1.2% 1449/TimerDispatch: 0.3% user + 0.8% kernel
2021-12-13 09:21:06.016 1724-31369/? E/ActivityManager: CPU usage from 129ms to 486ms later (2021-12-13 09:21:00.278 to 2021-12-13 09:21:00.635):
      57% 1724/system_server: 14% user + 42% kernel / faults: 697 minor
        28% 31369/AnrConsumer: 0% user + 28% kernel
        25% 14553/Binder:1724_1F: 17% user + 7.1% kernel
        3.5% 3426/WifiHandlerThre: 0% user + 3.5% kernel
      67% 30829/com.gymtec.archivepro: 27% user + 40% kernel / faults: 875 minor
        45% 30829/mtec.archivepro: 18% user + 27% kernel
        18% 30860/RenderThread: 4.5% user + 13% kernel
        4.5% 30846/HeapTaskDaemon: 4.5% user + 0% kernel
        4.5% 30847/ReferenceQueueD: 4.5% user + 0% kernel
      20% 1210/surfaceflinger: 6.7% user + 13% kernel
        10% 1210/surfaceflinger: 10% user + 0% kernel
        3.3% 1247/surfaceflinger: 3.3% user + 0% kernel
        3.3% 1249/Binder:1210_2: 0% user + 3.3% kernel
        3.3% 1451/app: 0% user + 3.3% kernel
        3.3% 2104/Binder:1210_3: 3.3% user + 0% kernel
        3.3% 29619/Binder:1210_2: 3.3% user + 0% kernel
      23% 13212/com.google.android.providers.media.module: 0% user + 23% kernel
        3.8% 8440/Thread-14: 0% user + 3.8% kernel
        3.8% 26751/Thread-18: 0% user + 3.8% kernel
        3.8% 28788/Thread-29: 3.8% user + 0% kernel
        3.8% 31071/Thread-28: 0% user + 3.8% kernel
      6.4% 1053/android.hardware.graphics.composer@2.4-service: 3.2% user + 3.2% kernel
        6.4% 1053/composer@2.4-se: 3.2% user + 3.2% kernel
      7.2% 3505/com.android.systemui: 3.6% user + 3.6% kernel / faults: 10 minor
        7.2% 3505/ndroid.systemui: 3.6% user + 3.6% kernel
      9% 30526/kworker/u16:3: 0% user + 9% kernel
      3% 506/crtc_commit:134: 0% user + 3% kernel
    26% TOTAL: 10% user + 14% kernel + 0.7% irq + 0.3% softirq

対応後

UIスレッドで実行した処理が5秒以上応答がない場合でもANRエラーが発生しません。

◎Javaコーディング【対応①】

UIスレッドとは別スレッドで処理を実行する。
しかし、この実装で別スレッドで実行した処理でUIコンポーネントを操作すると別のエラーが発生します。
UIコンポーネントを操作しない場合は、この実装でも問題ないと思います。

	:
    // バックアップ
    private final ActivityResultLauncher<Intent> activityResultLauncher1 = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
            result -> {
                if (result.getResultCode() == Activity.RESULT_OK) {
                    if (result.getData() != null) {
                        download.setVisibility(View.INVISIBLE);
                        upload.setVisibility(View.INVISIBLE);
                        progressBar.setVisibility(android.widget.ProgressBar.VISIBLE);
			          new Thread(new Runnable(){
  				          @Override
  				          public void run() {
                     			getArchiveDatabase().dbExport(context, result.getData().getData());
                            }
                        }).start();
                    }
                }
            });
  :

◎Logcat出力結果

別スレッドでUI操作を行うと、Can’t create handler inside thread that has not called Looper.prepareのエラーが発生します。
別スレッドで実行した処理でUI操作する場合、UIスレッドのキューにジョブを投入する実装が必要です。

2021-12-13 09:28:19.249 32509-32678/com.gymtec.archivepro E/AndroidRuntime: FATAL EXCEPTION: Thread-3
    Process: com.gymtec.archivepro, PID: 32509
    java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-3,5,main] that has not called Looper.prepare()
        at android.os.Handler.<init>(Handler.java:227)
        at android.os.Handler.<init>(Handler.java:129)
        at android.app.Activity.<init>(Activity.java:886)
        at androidx.core.app.ComponentActivity.<init>(ComponentActivity.java:48)
        at androidx.activity.ComponentActivity.<init>(ComponentActivity.java:220)
        at androidx.fragment.app.FragmentActivity.<init>(FragmentActivity.java:102)
        at androidx.appcompat.app.AppCompatActivity.<init>(AppCompatActivity.java:94)
        at com.gymtec.archivepro.utility.ArchiveUtilities.<init>(ArchiveUtilities.java:43)
        at com.gymtec.archivepro.utility.ExternalStorageWriter.<init>(ExternalStorageWriter.java:57)
        at com.gymtec.archivepro.database.ArchiveDatabaseHelper.dbExport(ArchiveDatabaseHelper.java:406)
        at com.gymtec.archivepro.view.SystemActivity$1.run(SystemActivity.java:73)
        at java.lang.Thread.run(Thread.java:923)

◎Javaコーディング【対応②】

UIスレッドのキューにジョブを投入する場合、Handlerを使用します。

    private final Handler               handler = new Handler(Looper.getMainLooper());
	:
    //バックアップ
    private final ActivityResultLauncher<Intent> activityResultLauncher1 = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
            result -> {
                if (result.getResultCode() == Activity.RESULT_OK) {
                    if (result.getData() != null) {
                        download.setVisibility(View.INVISIBLE);
                        upload.setVisibility(View.INVISIBLE);
                        progressBar.setVisibility(android.widget.ProgressBar.VISIBLE);
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                handler.post(() -> getArchiveDatabase().dbExport(context, result.getData().getData()));
                            }
                        }).start();
                    }
                }
            });
	:

今回は、ここまでです。

手になじむ、大きさが秀逸です♪

誤字脱字、意味不明でわかりづらい、
もっと詳しく知りたいなどのご意見は、
このページの最後にあるコメントか、
こちら
から、お願いいたします♪

ポチッとして頂けると、
次のコンテンツを作成する励みになります♪

ブログランキング・にほんブログ村へ

これからAndroidのアプリ開発やJavaでの開発を始めたい方へ

アプリケーション開発経験がない方や、アプリケーション開発経験がある方でも、Java や C# などのオブジェクト指向言語が初めての方は、Android のアプリ開発ができるようになるには、かなりの時間がかかります。
オンラインスクールでの習得を、強くおススメします。

未経験者からシステムエンジニアを目指すのに最適かと、まずは無料相談から♪

未経験者からプログラマーを目指すのに最適かと、まずは無料カウンセリングから♪

カリキュラムとサポートがしっかりしています、お得なキャンペーンとかいろいろやっています♪

ゲーム系に強いスクール、UnityやUnrealEngineを習得するのに最適かと、まずは無料オンライン相談から♪

参考になったら、💛をポッチとしてね♪

スポンサーリンク
msakiをフォローする
スポンサーリンク

コメント欄

タイトルとURLをコピーしました