通知管理器的notify()方法能否从工作线程调用?

54

我的问题更多关于什么是好的实践,而不是可能性:

  • 从工作线程调用 NoticationManager.notify()是否是一件好事?
  • 系统是否会在UI线程中执行它?

我始终牢记:与UI有关的内容应该在UI线程中执行,其余内容应该在工作线程中执行,正如Android文档关于进程和线程所建议的:

此外,Andoid UI工具包不是线程安全的。因此,您不能从工作线程中操作UI,必须从UI线程中执行所有对用户界面的操作。因此,Android的单线程模型有两个规则:

  • 不要阻塞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();

因此,我想知道是否实际上需要在主线程上运行它,或者系统会自动处理。

感谢您的帮助!

1个回答

99

可以从工作线程更新Notification,因为Notification不在您的应用程序进程中,因此您没有直接更新其UI。通知在系统进程中维护,并且通过RemoteViewsdoc)更新Notification的UI,允许操作由其他进程维护的视图层次结构。如果查看Notification.Builder的源代码在这里,最终可以看到它正在构建一个RemoteViews

如果查看RemoteViews的源代码在这里,则会发现当您操作视图时,实际上只是创建了一个Actionsource)对象并将其添加到队列中以进行处理。 Action是一个可打包对象,最终通过IPC发送到拥有Notification的视图的进程,在那里它可以解包值并根据指示更新视图...在自己的UI线程上。

希望这样可以澄清为什么可以从应用程序的工作线程更新Notification


嗨,阅读了你的答案后,我尝试在SyncAdapter(AbstractThreadedSyncAdapter)中创建通知。通知工作正常,但我无法使它们可取消。与在UI线程中显示相比,是否存在任何限制或差异? 示例Gist: https://gist.github.com/mauron85/f8c40096643f5bb08fcb7d77ff30e4b1 - mauron85

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接