web-dev-qa-db-ja.com

NotificationManager.notify()をワーカースレッドから呼び出すことはできますか?

私の質問は、可能なことよりも、良い習慣とは何かについてです。

  • ワーカースレッドからNoticationManager.notify()を呼び出すのは良いことですか?
  • とにかくシステムはUIスレッドでそれを実行しますか?

Android doc about Processes]で提案されているように、UIに関するものはUIスレッドで実行し、残りはワーカースレッドで実行する必要があることを常に念頭に置いています。そしてスレッド

さらに、AndoidUIツールキットはスレッドセーフではありません。したがって、ワーカースレッドからUIを操作しないでください。UIスレッドからユーザーインターフェイスに対してすべての操作を行う必要があります。したがって、Androidのシングルスレッドモデルには2つのルールがあります。

  • UIスレッドをブロックしないでください
  • UIスレッドの外部からAndroid UIツールキットにアクセスしないでください

ただし、進行中の通知の進行状況が更新されたAndroidドキュメント自体( 通知の進行状況の表示 ))の例には驚かされました。ワーカースレッドから直接:

mNotifyManager =
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this);
mBuilder.setContentTitle("Picture Download")
    .setContentText("Download in progress")
    .setSmallIcon(R.drawable.ic_notification);
// Start a lengthy operation in a background thread
new Thread(
    new Runnable() {
        @Override
        public void run() {
            int incr;
            // Do the "lengthy" operation 20 times
            for (incr = 0; incr <= 100; incr+=5) {
                    // Sets the progress indicator to a max value, the
                    // current completion percentage, and "determinate"
                    // state
                    mBuilder.setProgress(100, incr, false);
                    // Displays the progress bar for the first time.
                    mNotifyManager.notify(0, mBuilder.build());
                        // Sleeps the thread, simulating an operation
                        // that takes time
                        try {
                            // Sleep for 5 seconds
                            Thread.sleep(5*1000);
                        } catch (InterruptedException e) {
                            Log.d(TAG, "sleep failure");
                        }
            }
            // When the loop is finished, updates the notification
            mBuilder.setContentText("Download complete")
            // Removes the progress bar
                    .setProgress(0,0,false);
            mNotifyManager.notify(ID, mBuilder.build());
        }
    }
// Starts the thread by calling the run() method in its Runnable
).start();

そのため、実際にメインスレッドで実行する必要があるのか​​、それともシステムが処理するのか疑問に思っています。

ご協力いただきありがとうございます!

43
Joffrey

Notificationはアプリケーションのプロセスに存在しないため、UIを直接更新しないため、ワーカースレッドからNotificationを更新することは許容されます。通知はシステムプロセスで維持され、NotificationのUIはRemoteViewsdoc )を介して更新されます。これにより、によって維持されるビュー階層の操作が可能になります。あなた自身以外のプロセス。 Notification.Builderhere のソースを見ると、最終的にRemoteViewsを構築していることがわかります。

そして、RemoteViewshere のソースを見ると、ビューを操作すると、実際にはActionsource )オブジェクトとそれを処理するキューに追加します。 ActionParcelableであり、最終的にIPCを介して、Notificationのビューを所有するプロセスに送信され、そこで値を解凍できます。示されているようにビューを更新します...それ自体のUIスレッドで。

アプリケーションのワーカースレッドからNotificationを更新しても問題がない理由が明らかになることを願っています。

80
Brett Duncavage