Mengakses penangan utas UI dari layanan


90

Saya mencoba sesuatu yang baru di Android yang saya perlukan untuk mengakses handler UI thread.

Saya tahu yang berikut:

  1. Rangkaian UI memiliki penangan dan loopernya sendiri
  2. Pesan apa pun akan dimasukkan ke dalam antrian pesan dari UI thread
  3. Looper mengambil event tersebut dan memberikannya ke handler
  4. Handler menangani pesan tersebut dan mengirimkan peristiwa specfic ke UI

Saya ingin memiliki layanan saya yang harus mendapatkan penangan utas UI dan memasukkan pesan ke penangan ini. Sehingga pesan ini akan diproses dan akan dikeluarkan ke UI. Disini service akan menjadi service normal yang akan dijalankan oleh beberapa aplikasi.

Saya ingin tahu apakah ini mungkin. Jika demikian, harap sarankan beberapa cuplikan kode, agar saya dapat mencobanya.

Salam Girish

Jawaban:


179

Cuplikan kode ini menyusun Handler yang terkait dengan utas utama (UI):

Handler handler = new Handler(Looper.getMainLooper());

Anda kemudian dapat memposting barang untuk dieksekusi di utas utama (UI) seperti:

handler.post(runnable_to_call_from_main_thread);

Jika penangan itu sendiri dibuat dari utas utama (UI), argumennya dapat dihilangkan agar singkat:

Handler handler = new Handler();

The Android Dev Panduan tentang proses dan benang memiliki informasi lebih lanjut.


2
Mengujinya dan berhasil dengan baik! Contoh kasus penggunaan: Saya memiliki antarmuka web yang dilayani oleh server yang berjalan langsung di perangkat. Karena antarmuka dapat digunakan untuk berinteraksi langsung dengan UI, dan karena server perlu berjalan di utasnya sendiri, saya memerlukan cara untuk menyentuh utas UI dari luar Aktivitas. Metode yang Anda jelaskan bekerja dengan baik.
mrPjer

1
Cemerlang. Bekerja seperti pesona, dan sangat berguna. TERIMA KASIH.
JRun

perfect ^^ baru saja digunakan untuk memperbarui ui saya dari StreamingService. persis apa yang saya butuhkan terima kasih!
An-droid

tahukah Anda jika saya dapat membuat instance tunggal dari sebuah penangan, dan menggunakannya setiap kali saya perlu menjalankan sesuatu di utas ui?
HelloWorld

Saya kira kita tidak akan pernah tahu
Denny

28

Buat Messengerobjek yang melekat pada Anda Handlerdan berikan itu Messengerke Service(misalnya, dengan Intenttambahan untuk startService()). Kemudian Servicedapat mengirim Messageke Handlermelalui Messenger. Berikut adalah contoh aplikasi yang mendemonstrasikan hal ini.


Terima kasih atas tip ini. Ini sangat membantu. Silakan lihat tumpukan berikut untuk aliran peristiwa sentuh ke aktivitas saya MyDemo.dispatchTouchEvent (MotionEvent) baris: 20 PhoneWindow $ DecorView.dispatchTouchEvent (MotionEvent) baris: 1696 ViewRoot.handleMessage (Message) baris: 1658 ViewRoot (Handler) .dispatchMessage (Message ) baris: 99 Looper.loop () baris: 123 // Penanganan peristiwa dimulai di sini ActivityThread.main (String []) baris: 4203 Di sini ViewRoot adalah Handler. Saya ingin mendapatkan referensi dari penangan ini ... apakah mungkin mendapatkan ini dari aplikasi saya?
iLikeAndroid

@iLikeAndroid: Jika Anda tidak membuatnya Handler, Anda tidak dapat mengaksesnya, AFAIK.
CommonsWare

Terima kasih. Saya telah mencoba membuat instance ViewRoot. Ini hanyalah pawang. Sekarang saya bisa mengeluarkan pesan di handler ini. Pawang menerima pesan tersebut. Tetapi ViewRoot tidak dapat memproses pesan karena tidak diinisialisasi dengan benar. Saya perlu memanggil ViewRoot.setView () untuk menginisialisasi data yang tepat ke ViewRoot. Saya ingin tahu apakah ada tampilan default atau tampilan dasar dll, yang dapat saya gunakan untuk menginisialisasi?
iLikeAndroid

@iLikeAndroid: Tidak ada ViewRootdi Android SDK, AFAICT.
CommonsWare

1
@ hadez30: Secara pribadi, saya tidak banyak menggunakan layanan terikat. Anda masih dapat menggunakan Handler/ Messenger, meskipun saya akan mengganti semua itu dengan bus acara (misalnya, EventBus greenrobot).
CommonsWare

4

Saat ini saya lebih suka menggunakan perpustakaan bus acara seperti Otto untuk masalah semacam ini. Cukup berlangganan komponen yang diinginkan (aktivitas):

protected void onResume() {
    super.onResume();
    bus.register(this);
}

Kemudian berikan metode callback:

public void onTimeLeftEvent(TimeLeftEvent ev) {
    // process event..
}

dan kemudian ketika layanan Anda menjalankan pernyataan seperti ini:

bus.post(new TimeLeftEvent(340));

POJO itu akan diteruskan ke aktivitas Anda di atas dan semua komponen langganan lainnya. Sederhana dan elegan.


3

Saya sarankan mencoba kode berikut:

    new Handler(Looper.getMainLooper()).post(() -> {

        //UI THREAD CODE HERE



    });

Beberapa penjelasan tambahan diperlukan untuk membantu OP.
Moog

2

Anda bisa mendapatkan nilai melalui penerima siaran ...... sebagai berikut, Pertama buat IntentFilter Anda sendiri sebagai,

Intent intentFilter=new IntentFilter();
intentFilter.addAction("YOUR_INTENT_FILTER");

Kemudian buat kelas dalam BroadcastReceiver sebagai,

    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
    /** Receives the broadcast that has been fired */
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getAction()=="YOUR_INTENT_FILTER"){
           //HERE YOU WILL GET VALUES FROM BROADCAST THROUGH INTENT EDIT YOUR TEXTVIEW///////////
           String receivedValue=intent.getStringExtra("KEY");
        }
    }
};

Sekarang Daftarkan penerima Siaran Anda di onResume () sebagai,

registerReceiver(broadcastReceiver, intentFilter);

Dan terakhir Batalkan pendaftaran BroadcastReceiver di onDestroy () sebagai,

unregisterReceiver(broadcastReceiver);

Sekarang bagian terpenting ... Anda perlu mengaktifkan siaran dari mana pun Anda perlu mengirim nilai ..... jadi lakukan seperti,

Intent i=new Intent();
i.setAction("YOUR_INTENT_FILTER");
i.putExtra("KEY", "YOUR_VALUE");
sendBroadcast(i);

....Bersulang :)


1

Dalam kotlinthats bagaimana Anda dapat melakukannya

Katakanlah jika Anda ingin menampilkan pesan Toast dari layanan

val handler = Handler(Looper.getMainLooper())
handler.post {
   Toast.makeText(context, "This is my message",Toast.LENGTH_LONG).show()
}

0

Larutan:

  1. Buat Handler dengan Looper dari Main Thread: requestHandler
  2. Buat Handlerdengan Looperdari Main Thread: responseHandler dan handleMessagemetode override
  3. memposting tugas Runnable di requestHandler
  4. Di dalam Runnabletugas, panggil sendMessage on responseHandler
  5. Ini sendMessagemenghasilkan pemanggilan handleMessage di responseHandler.
  6. Dapatkan atribut dari Messagedan proses, perbarui UI

Kode sampel:

    /* Handler from UI Thread to send request */

    Handler requestHandler = new Handler(Looper.getMainLooper());

     /* Handler from UI Thread to process messages */

    final Handler responseHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {

            /* Processing handleMessage */

            Toast.makeText(MainActivity.this,
                    "Runnable completed with result:"+(String)msg.obj,
                    Toast.LENGTH_LONG)
                    .show();
        }
    };

    for ( int i=0; i<10; i++) {
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                try {
                   /* Send an Event to UI Thread through message. 
                      Add business logic and prepare message by 
                      replacing example code */

                    String text = "" + (++rId);
                    Message msg = new Message();

                    msg.obj = text.toString();
                    responseHandler.sendMessage(msg);
                    System.out.println(text.toString());

                } catch (Exception err) {
                    err.printStackTrace();
                }
            }
        };
        requestHandler.post(myRunnable);
    }
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.