Bir hizmetten kullanıcı arabirimi işleyicisine erişme


90

Android'de UI iş parçacığının işleyicisine erişmem gereken yeni bir şey deniyorum.

Aşağıdakileri biliyorum:

  1. UI iş parçacığının kendi işleyicisi ve döngüleyicisi vardır
  2. Herhangi bir mesaj, UI iş parçacığının mesaj kuyruğuna konulacaktır
  3. İlmek yapıcı, olayı alır ve işleyiciye iletir
  4. İşleyici, mesajı işler ve özel olayı kullanıcı arayüzüne gönderir.

UI iş parçacığı işleyicisini almak ve bu işleyiciye bir mesaj koymak zorunda olan hizmetime sahip olmak istiyorum. Böylece bu mesaj işlenecek ve kullanıcı arayüzüne gönderilecektir. Burada hizmet, bazı uygulamalar tarafından başlatılacak olan normal bir hizmet olacaktır.

Bunun mümkün olup olmadığını bilmek isterim. Öyleyse, deneyebilmem için lütfen bazı kod parçacıkları önerin.

Saygılarımızla Girish

Yanıtlar:


179

Bu kod parçacığı, ana (UI) iş parçacığı ile ilişkili bir İşleyici oluşturur:

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

Daha sonra ana (UI) iş parçacığına aşağıdaki gibi yürütme için şeyler gönderebilirsiniz:

handler.post(runnable_to_call_from_main_thread);

İşleyicinin kendisi ana (UI) iş parçacığından oluşturulmuşsa, argüman kısalık için ihmal edilebilir:

Handler handler = new Handler();

Android Geliştirici Kılavuzu süreçleri ve iş parçacığı hakkında daha fazla bilgi vardır.


2
Test ettik ve harika çalışıyor! Bir kullanım durumu örneği: Doğrudan cihaz üzerinde çalışan bir sunucu tarafından sunulan bir web arayüzüne sahibim. Arayüz, kullanıcı arayüzü ile doğrudan etkileşim için kullanılabildiğinden ve sunucunun kendi iş parçacığı üzerinde çalışması gerektiğinden, UI iş parçacığına bir Aktivite dışından dokunmanın bir yoluna ihtiyacım vardı. Tarif ettiğiniz yöntem harika çalıştı.
mrPjer

1
Parlak. Bir cazibe gibi çalışıyor ve çok kullanışlı. TEŞEKKÜR EDERİM.
JRun

mükemmel ^^ sadece bir StreamingService'den kullanıcı arayüzümü güncellemek için kullandım. tam olarak ihtiyacım olan şey teşekkürler!
An-droid

Bir işleyicinin tekil bir örneğini yaratıp, ui iş parçacığında bir şey çalıştırmam gerektiğinde bunu kullanıp kullanamayacağımı biliyor musunuz?
HelloWorld

Sanırım asla bilemeyeceğiz
Denny

28

Bir oluşturma Messengeradresinden Müşteri ekli nesne Handlerve o geçmesi Messengeriçin Service(bir in, örneğin Intentilave için startService()). ServiceDaha sonra gönderebilir Messageiçin Handlerüzeri Messenger. İşte bunu gösteren örnek bir uygulama .


Bu ipucu için teşekkürler. Bu yardımcı oldu. MyDemo.dispatchTouchEvent (MotionEvent) satır: 20 PhoneWindow $ DecorView.dispatchTouchEvent (MotionEvent) satır: 1696 ViewRoot.handleMessage (Mesaj) satır: 1658 ViewRoot (Handler) .dispatchMessage (Message ) satır: 99 Looper.loop () satır: 123 // Olay işleme burada başlar ActivityThread.main (String []) satır: 4203 Burada ViewRoot bir İşleyicidir. Bu işleyicinin referansını almak istiyorum ... bunu uygulamamdan almak mümkün mü?
iLikeAndroid

@iLikeAndroid: Eğer oluşturmadıysanız, Handlerona erişemezsiniz, AFAIK.
CommonsWare

Teşekkür ederim. ViewRoot'un bir örneğini oluşturmaya çalıştım. Bu bir işleyiciden başka bir şey değil. Şimdi bu işleyicideki mesajları yayınlayabiliyorum. İşleyici mesajı alıyor. Ancak ViewRoot, düzgün şekilde başlatılmadığından mesajı işleyemez. ViewRoot'a uygun verileri başlatmak için ViewRoot.setView () 'ı çağırmam gerekiyor. Başlatmak için kullanabileceğim bir varsayılan görünüm veya temel görünüm vb. Olduğunu bilmek istiyorum.
iLikeAndroid

@iLikeAndroid: ViewRootAndroid SDK, AFAICT'de yoktur.
CommonsWare

1
@ hadez30: Şahsen, bağlı hizmetleri pek kullanmıyorum. Yine de Handler/ kullanabilirsiniz Messenger, ancak tüm bunları bir olay veri yolu ile değiştiririm (örneğin, greenrobot'un EventBus'u).
CommonsWare

4

Şu anda bu tür problemler için Otto gibi etkinlik otobüsü kütüphanesini kullanmayı tercih ediyorum . Sadece istenen bileşenleri (aktivite) abone olun:

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

Ardından bir geri arama yöntemi sağlayın:

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

ve sonra hizmetiniz böyle bir ifade yürüttüğünde:

bus.post(new TimeLeftEvent(340));

Bu POJO, yukarıdaki etkinliğinize ve diğer tüm abone bileşenlerine aktarılacaktır. Sade ve zarif.


3

Aşağıdaki kodu denemenizi öneririm:

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

        //UI THREAD CODE HERE



    });

OP'ye yardımcı olmak için bazı ek açıklamalara ihtiyaç vardır.
Moog

2

Değerleri yayın alıcısı üzerinden alabilirsiniz ...... aşağıdaki gibi, Önce kendi IntentFilter'ınızı oluşturun,

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

Ardından, BroadcastReceiver iç sınıfını şu şekilde oluşturun:

    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");
        }
    }
};

Şimdi Yayın alıcınızı onResume () 'de şu şekilde kaydedin:

registerReceiver(broadcastReceiver, intentFilter);

Ve son olarak, onDestroy () içindeki BroadcastReceiver'ın kaydını şu şekilde kaldırın:

unregisterReceiver(broadcastReceiver);

Şimdi en önemli kısım ... Değerleri göndermek istediğiniz her yerden yayını ateşlemelisiniz ..... öyle yapın,

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

.... şerefe :)


1

Bu kotlinnasıl yapabilirsin

Servisten Toast mesajını göstermek isteyip istemediğinizi varsayalım

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

0

Çözüm:

  1. Ana İş Parçacığından Looper ile İşleyici Oluşturun : requestHandler
  2. Main Thread: responseHandler öğesinden bir Handlerile oluşturma Looperve geçersiz kılma handleMessageyöntemi
  3. requestHandler üzerine bir Runnable görevi gönder
  4. İçinde Runnablegöreve responseHandler üzerinde sendMessage çağrı
  5. Bu sendMessagesonuç, responseHandler'da handleMessage'ın çağrılmasıdır.
  6. Özelliklerini alın Messageve işleyin, kullanıcı arayüzünü güncelleyin

Basit kod:

    /* 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);
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.