Başka bir iş parçacığından ana iş parçacığında çalışan kod


326

Bir android hizmetinde bazı arka plan görevi yapmak için iplik (ler) oluşturduk.

Bir iş parçacığının, örneğin ana iş parçacığının ileti kuyruğunda belirli bir görev göndermek gerekiyor bir durum var Runnable.

Almanın bir yolu var mı Handlerana iş parçacığı ve yazının Message/ Runnablebenim diğer iplikten buna?

Teşekkürler,


2
Özel yayın alıcısını da kullanabilirsiniz .... Cevabımı burada deneyin, [İç Yayın Alıcısı] [1] [1]: stackoverflow.com/a/22541324/1881527
Melbourne Lopes

Birçok yolu var. David'in yanıtı ve dzeikei'nin cevabındaki yorumu dışında, (3) bir Yayın Alıcısı kullanabilir veya (4) işleyiciyi hizmeti başlatmak için kullanılan Niyet ekstralarından geçirebilir ve daha sonra getIntent'i kullanarak ana iş parçacığının hizmet içindeki hizmetini alabilirsiniz ( ) .getExtras ().
Ashok Bijoy Debnath

2
@ sazzad-hissain-khan, Neden 2012'den bu soruyu Java'da kotlin etiketi ile çoğunlukla cevaplarla etiketliyorsunuz?
Tenfour04

Yanıtlar:


617

NOT: Bu cevap o kadar çok dikkat çekti ki güncellemem gerekiyor. Orijinal cevap gönderildiğinden, @dzeikei'nin yorumu orijinal cevap kadar neredeyse dikkat çekti. İşte size 2 olası çözüm:

1. Arka plan iş parçacığınızda bir Contextnesneye başvuru varsa :

Arka plan çalışan iş parçacıklarınızın bir Bağlam nesnesine erişimi olduğundan emin olun (Uygulama bağlamı veya Hizmet bağlamı olabilir). Sonra sadece arka plan işçi iş parçacığında bunu yapın:

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(context.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);

2. Arka plan iş parçacığınızda bir Contextnesne yoksa (veya gerekiyorsa)

(@dzeikei tarafından önerilmiştir):

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(Looper.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);

1
Teşekkürler David benim için çalıştı, bana yardımcı olabilir bir şey daha, Handler uzatmak ve handleMessage () impl ana mesajların işlenmesi engeller misiniz? bu sadece curosity'den bir soru ..
Ahmed

2
Hayır. Alt sınıf Handler(veya Handler.Callbackarabirim kullanıyorsanız) handleMessage()yönteminiz SADECE işleyicinizi kullanarak gönderilen iletiler için çağrılır. Ana iş parçacığı, mesaj göndermek / işlemek için farklı bir işleyici kullanarak çakışma olmaz.
David Wasser

205
Handler mainHandler = new Handler(Looper.getMainLooper());
Kullanırsanız

6
Küçük nokta; kodunuz şu anda olduğu yere gitmiyor. O olmalınew Runnable(){@Override public void run() {....}};
Richard Tingle

1
@SagarDevanga Farklı bir soru sormak için doğru yer bu değil. Lütfen alakasız bir cevaba yorum değil, yeni bir soru gönderin. Bu şekilde daha iyi ve daha hızlı yanıt alacaksınız.
David Wasser

138

Aşağıdaki yorumcuların doğru bir şekilde işaret ettiği gibi, bu hizmetler için yalnızca etkinliğinizden başlatılan iş parçacıkları için genel bir çözüm değildir (bir hizmet böyle bir iş parçacığı olabilir, ancak bunların hepsi değildir). Karmaşık hizmet-etkinlik iletişimi konusunda lütfen resmi dokümanın tüm Hizmetler bölümünü okuyun - karmaşıktır, bu nedenle temel bilgileri anlamak için ödeme yapar: http://developer.android.com/guide/components/services.html #Bildirimler

Aşağıdaki yöntem en basit durumlarda işe yarayabilir.

Eğer doğru anlıyorsanız uygulamanın GUI iş parçacığında yürütülmesi için bazı kod gerekir ("ana" iş parçacığı denilen başka bir şey düşünemiyorum). Bunun için bir yöntem var Activity:

someActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
           //Your code to run in GUI thread here
        }//public void run() {
});

Doküman: http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29

Umarım aradığınız şey budur.


20
OP, a Service. Sen kullanamazsınız runOnUiThread()bir yer Service. Bu cevap yanıltıcıdır ve sorulan soruya cevap vermemektedir.
David Wasser

31

Bağlam'a erişiminiz yoksa başka bir basit yol daha vardır.

1). Ana lüperden bir işleyici oluşturun:

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

2). Çalıştırılabilir bir arayüz uygulayın:

Runnable runnable = new Runnable() { // your code here }

3). Runnable'ınızı uiHandler'a gönderin:

uiHandler.post(runnable);

Hepsi bu ;-) Konu ile eğlenin, ama onları senkronize etmeyi unutmayın.


29

Bir iş parçacığında kod çalıştırırsanız, örneğin bazı eylemleri geciktirirseniz runOnUiThread, bağlamdan çağırmanız gerekir . Örneğin, kodunuz MainActivitysınıfın içindeyse bunu kullanın:

MainActivity.this.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        myAction();
    }
});

Yönteminiz ana (UI iş parçacığı) veya diğer iş parçacıklarından çağrılabilirse, aşağıdaki gibi bir denetime ihtiyacınız vardır:

public void myMethod() {
   if( Looper.myLooper() == Looper.getMainLooper() ) {
       myAction();
   }
   else {

}

7
OP, a Service. Sen kullanamazsınız runOnUiThread()bir yer Service.
David Wasser

@DavidWasser Bu herhangi bir yerde belgelenmiş mi? Docs yöntemi bu konuda hiçbir şeyden bahsetmiyor. developer.android.com/reference/android/app/…
Greg Brown

1
@GregBrown ActivityBelgelere bağlantınızla belirttiğiniz gibi runOnUiThread(), bir yöntemdir Activity. Bu bir yöntem değildir Service, bu yüzden kullanamazsınız. Bundan daha net ne olabilir?
David Wasser

@DavidWasser Fuarı yeterince. Bu soruyu neden şimdi sorduğumu bile hatırlamıyorum (neredeyse bir yıl önce gönderildi).
Greg Brown

24

Kısaltılmış kod bloğu aşağıdaki gibidir:

   new Handler(Looper.getMainLooper()).post(new Runnable() {
       @Override
       public void run() {
           // things to do on the main thread
       }
   });

Bu, Faaliyet referansının veya Uygulama referansının geçilmesini içermez.

Kotlin Eşdeğeri:

    Handler(Looper.getMainLooper()).post(Runnable {
        // things to do on the main thread
    })

20

Kotlin versiyonları

Bir etkinlikteyken şunu kullanın:

runOnUiThread {
    //code that runs in main
}

Ne zaman sen aktivite bağlamı var , mContext sonra kullanmak

mContext.runOnUiThread {
    //code that runs in main
}

Eğer bir yere olduğunuz zaman nerede hiçbir bağlam mevcut , daha sonra kullanım

Handler(Looper.getMainLooper()).post {  
    //code that runs in main
}

Kotlin'in bu sürümünün ne olduğundan emin değilim, ama diş telleri eklemek zorunda kaldım:runOnUiThread(){...}
Wex

5

Özellikle bir bağlamınız yoksa, en basit yol RxAndroid kullanıyorsanız şunları yapabilirsiniz:

AndroidSchedulers.mainThread().scheduleDirect {
    runCodeHere()
}

5

İşleyiciyi kullanarak daha hassas Kotlin kodu:

Handler(Looper.getMainLooper()).post {  
 // your codes here run on main Thread
 }

4

Düşünebileceğim bir yöntem şudur:

1) Kullanıcı arayüzünün hizmete bağlanmasına izin verin.
2) tarafından aşağıdaki gibi bir yöntem ortaya çıkarın Bindersenin kaydeder Handler:

public void registerHandler(Handler handler) {
    mHandler = handler;
}

3) UI iş parçacığında, hizmete bağlandıktan sonra yukarıdaki yöntemi çağırın:

mBinder.registerHandler(new Handler());

4) Görevinizi göndermek için Hizmet dizisindeki işleyiciyi kullanın:

mHandler.post(runnable);

3

HandlerThread Android'de normal Java Konuları için daha iyi bir seçenektir.

  1. Bir HandlerThread oluşturun ve başlatın
  2. Bir oluşturun işleyicisi ile Lüper HandlerThread dan:requestHandler
  3. postbir RunnablegörevrequestHandler

UI İş Parçacığı ile iletişim HandlerThread

  1. Ana iş parçacığı için bir Handlerile oluşturun Looper: responseHandlerve geçersiz kılma handleMessageyöntemi
  2. RunnableDiğer iş parçacığının ( HandlerThreadbu durumda) iç görevi sendMessage,responseHandler
  3. Bu sendMessagesonucu çağırma handleMessageiçinde responseHandler.
  4. Özellikleri alın Messageve işleyin, kullanıcı arayüzünü güncelleyin

Misal : TextViewBir web servisinden alınan verilerle güncelleme . Web hizmeti UI olmayan iş parçacığında çağrılması gerektiğinden, HandlerThreadAğ İşlemi için oluşturulmuştur . İçeriği web hizmetinden aldıktan sonra, ana iş parçacığınıza (UI İş Parçacığı) işleyicinize mesaj gönderin; Handlerbu, mesajı işleyecek ve kullanıcı arayüzünü güncelleyecektir.

Basit kod:

HandlerThread handlerThread = new HandlerThread("NetworkOperation");
handlerThread.start();
Handler requestHandler = new Handler(handlerThread.getLooper());

final Handler responseHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        txtView.setText((String) msg.obj);
    }
};

Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Log.d("Runnable", "Before IO call");
            URL page = new URL("http://www.your_web_site.com/fetchData.jsp");
            StringBuffer text = new StringBuffer();
            HttpURLConnection conn = (HttpURLConnection) page.openConnection();
            conn.connect();
            InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
            BufferedReader buff = new BufferedReader(in);
            String line;
            while ((line = buff.readLine()) != null) {
                text.append(line + "\n");
            }
            Log.d("Runnable", "After IO call:"+ text.toString());
            Message msg = new Message();
            msg.obj = text.toString();
            responseHandler.sendMessage(msg);


        } catch (Exception err) {
            err.printStackTrace();
        }
    }
};
requestHandler.post(myRunnable);

Yararlı makaleler:

handlerthreads-niçin-sen-kullanarak olmalıdır-onları-in-your-android-uygulamalar

robot-ilmek işleyicisi-handlerthread-ı


2

Bu eski bir soru olduğunu biliyorum, ama Kotlin ve Java hem de kullandığım bir ana iplik tek astar karşılaştım. Bu, bir hizmet için en iyi çözüm olmayabilir, ancak bir parçanın içindeki kullanıcı arayüzünü değiştirecek bir şeyi çağırmak için bu son derece basit ve açıktır.

Java (8):

 getActivity().runOnUiThread(()->{
      //your main thread code
 });

Kotlin:

this.runOnUiThread {
     //your main thread code
}

1

Bu yöntemi takip edin. Bu şekilde, UI'yi bir arka plan iş parçacığından güncelleyebilirsiniz. runOnUiThread (UI) iş parçacığı üzerinde çalışma. Bu kod snippet'inin özellikle yeni başlayanlar için daha az karmaşık ve kolay olduğunu düşünüyorum.

AsyncTask.execute(new Runnable() {
            @Override
            public void run() {

            //code you want to run on the background
            someCode();

           //the code you want to run on main thread
 MainActivity.this.runOnUiThread(new Runnable() {

                    public void run() {

/*the code you want to run after the background operation otherwise they will executed earlier and give you an error*/
                        executeAfterOperation();

                   }
                });
            }
        });

bir servis durumunda

oncreate'da bir işleyici yarat

 handler = new Handler();

o zaman böyle kullan

 private void runOnUiThread(Runnable runnable) {
        handler.post(runnable);
    }

Sınırlı ve anında yardım sağlayabilecek bu kod snippet'i için teşekkür ederiz. Bir Doğru bir açıklama ölçüde uzun vadeli değer artıracak göstererek neden bu soruna iyi bir çözüm olduğunu ve diğer benzer sorularla gelecek okuyucularına daha kullanışlı bir hale getirecektir. Yaptığınız varsayımlar dahil bazı açıklamalar eklemek için lütfen yanıtınızı düzenleyin .
iBug

1

Kotlin için Anko korountinlerini kullanabilirsiniz :

Güncelleme

doAsync {
   ...
}

Kullanımdan kaldırılan

async(UI) {
    // Code run on UI thread
    // Use ref() instead of this@MyActivity
}

1

Bu yüzden en kullanışlı olanı:

import android.os.AsyncTask
import android.os.Handler
import android.os.Looper

object Dispatch {
    fun asyncOnBackground(call: ()->Unit) {
        AsyncTask.execute {
            call()
        }
    }

    fun asyncOnMain(call: ()->Unit) {
        Handler(Looper.getMainLooper()).post {
            call()
        }
    }
}

Ve sonra:

Dispatch.asyncOnBackground {
    val value = ...// super processing
    Dispatch.asyncOnMain { completion(value)}
}

0
public void mainWork() {
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            //Add Your Code Here
        }
    });
}

Bu, sorunsuz bir hizmet sınıfında da çalışabilir.


Bu kod soruyu cevaplayabilirken, diğer kullanıcılar için cevabınızın değerini arttırdığından, hala birkaç açıklayıcı cümle eklemeyi düşünebilirsiniz!
MBT

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.