37

Moje pytanie jest więcej o tym, co jest dobrą praktyką, niż jest to możliwe:Czy funkcja NoticationManager.notify() może zostać wywołana z wątku roboczego?

  • Czy jest dobrą rzeczą, aby zadzwonić NoticationManager.notify() z wątku pracownika?
  • Czy system wykonuje to w wątku interfejsu użytkownika, czy nie?

zawsze staram się pamiętać, że materiał dotyczący UI powinny być wykonywane w wątku UI, a reszta w wątków roboczych, zgodnie z sugestią Android doc o Processes And Threads:

Dodatkowo zestaw narzędzi Andoid UI nie jest bezpieczny dla wątków. Tak więc, nie musisz manipulować swoim interfejsem użytkownika z wątku roboczego - musisz wykonać wszystkie manipulacje do interfejsu użytkownika z poziomu wątku interfejsu użytkownika. Tak więc, nie są po prostu dwie reguły do ​​jednego modelu gwintu Android:

  • Nie blokuj wątku UI
  • nie korzysta z zestawu narzędzi Android UI spoza wątku UI

JEDNAK Byłem zaskoczony przykładem podanym przez sam dokument Android (about showing progress in Notifications), w którym stały postęp powiadomienia został zaktualizowany bezpośrednio z wątku roboczego:

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

Dlatego właśnie zastanawiam się, czy to naprawdę konieczne, aby uruchomić go na głównym wątku, lub jeśli system się nim zajmie.

Dzięki za pomoc!

Odpowiedz

65

Dopuszcza się aktualizację Notification z wątku roboczego, ponieważ Notification nie działa w procesie aplikacji, dlatego nie aktualizuje się bezpośrednio interfejsu użytkownika. Powiadomienie jest utrzymywane w procesie systemowym, a interfejs użytkownika Notification jest aktualizowany poprzez RemoteViews (doc), który umożliwia manipulację hierarchią widoku, która jest utrzymywana przez proces inny niż własny. Jeśli spojrzeć na źródło dla Notification.Builderhere widać, że ostatecznie buduje się RemoteViews.

A jeśli spojrzeć na źródło RemoteViewshere zobaczysz, że podczas manipulowania widok jest naprawdę tylko tworzenie się Action (source) obiektu i dodanie go do kolejki do przetworzenia. Numer Action to Parcelable, który jest ostatecznie wysyłany za pośrednictwem IPC do procesu, który jest właścicielem widoku Notification, gdzie może rozpakować wartości i zaktualizować widok, jak wskazano ... w jego własnym wątku interfejsu użytkownika.

Mam nadzieję, że wyjaśniono, dlaczego można zaktualizować Notification z wątku roboczego w aplikacji.

+1

Dokładnie tego szukałem, dziękuję bardzo! – Joffrey

+0

Cześć, czytając odpowiedź, Próbowałem utworzyć powiadomienie w SyncAdapter (AbstractThreadedSyncAdapter). Powiadomienia działają poprawnie, ale nie mogę ich anulować. Czy są jakieś ograniczenia lub różnice w porównaniu do wyświetlania w wątku interfejsu użytkownika? Gist z przykładem: https://gist.github.com/mauron85/f8c40096643f5bb08fcb7d77ff30e4b1 – mauron85

Powiązane problemy