Android: İşleyiciyi () ne zaman kullanmalıyım ve İş Parçacığını ne zaman kullanmalıyım?


129

Uzun süre çalışan bir görev veya ağı kullanan bir mantık gibi eşzamansız olarak çalışacak bir şeye ihtiyacım olduğunda veya herhangi bir nedenle, Yeni bir İş Parçacığı başlatmak ve çalıştırmak iyi çalışıyor. İşleyici oluşturmak ve çalıştırmak da işe yarar . Fark ne? Her birini ne zaman kullanmalıyım? A kullanmanın ve a kullanmanın avantajları / nedenleri nelerdir?HandlerThread

PS. - Bu soru aşkına, görmezden gelelim AsyncTask. - Handler().postDelayedKullanım durumu benim için net, bu soru için, göreve hemen başlamak için ihtiyacım olduğunu varsayalım.


Sizin durumunuzda, dümdüz gidin ve yeni bir İş Parçacığı kullanın, bir sonraki önerim AsyncTask olacaktır, ancak açıkça istediğiniz şey bu değil. İşleyiciler çoğunlukla, çalıştırılabilir bir dosyaya bir gecikme veya başka tür bir özelleştirme eklemek istiyorsanız kullanılır.
kabuto178

1
@ kabuto178 iyi, işleyicilerin atladığınızdan bahsetmeye değer başka faydaları da var. Örneğin, UI iş parçacığı ile ayrı bir iş parçacığından etkileşime girebilmek gibi ..
tony9099

Yanıtlar:


168

Yaptığınız şey "ağır" ise, bunu bir İş Parçacığı içinde yapmalısınız. Bunu açıkça kendi iş parçacığında başlatmazsanız, kullanıcılarınız tarafından titrek veya yavaş yanıt veren arabirim olarak fark edilebilecek ana (UI) iş parçacığı üzerinde çalışacaktır.

İlginç bir şekilde, bir iş parçacığı kullanırken, başlattığınız iş parçacığı ile ana iş parçacığı arasında bir iletişim aracı olarak bir İşleyiciyi kullanmak da genellikle yararlıdır.

Tipik bir İş Parçacığı / İşleyici etkileşimi şunun gibi görünebilir:

Handler h = new Handler(){
    @Override
    public void handleMessage(Message msg){
        if(msg.what == 0){
            updateUI();
        }else{
            showErrorDialog();
        }
    }
};

Thread t = new Thread() {
    @Override
    public void run(){
        doSomeWork();
        if(succeed){
            //we can't update the UI from here so we'll signal our handler and it will do it for us.
            h.sendEmptyMessage(0);
        }else{
            h.sendEmptyMessage(1);
        }
    }   
};

Genel olarak, eve götürmek, uzun süren veya çok yoğun olabilecek bazı işler yaparken (yani herhangi bir ağ, dosya IO, ağır aritmatik vb.) Bir İş Parçacığı kullanmanız gerektiğidir.


Hızlı yanıtınız ve harcadığınız zaman (ve yanıtınızın hızı !!) için teşekkürler! Öyleyse, şunu anladığımı görmeme izin verin: İşleyici, çalışan iş parçacıkları ve UI iş parçacığı arasındaki engellemesiz iletişimi kolaylaştırmak için mi tasarlandı?
JRun

3
@JRun Bu evet kullanımlarından biridir. Bununla ilgili bazı harika bilgiler için java belgelerindeki İşleyici açıklamasına bakın . Başka kullanımları dahil (gelecekte bir noktada yürütülecek mesajları ve çalıştırılabilirleri programlamak için).
FoamyGuy

güzelce açıkladı @FoamyGuy!
tony9099

Merhaba, daha updateUI()sonra çalışacağı garantili mi onCreateView(yeni görünümler yüklendikten sonra)?
Zyoo

1
Neden message.what()? Sadece olmaz mıydı if(msg == 0){? Çok teşekkürler! :)
Ruchir Baronia

64

Handler ve Thread gerçekten 2 farklı şeydir.

Uzun süre çalışan işleri yürütmek için bir iş parçacığı oluşturulmalıdır.

Bir İşleyici, 2 iş parçacığı arasında iletişim kurmak için çok uygun bir nesnedir (örneğin: bir arka plan iş parçacığının kullanıcı arayüzünü güncellemesi gerekir. Arka plan iş parçacığınızdan UI iş parçacığına bazı Çalıştırılabilir öğeler göndermek için bir İşleyici kullanabilirsiniz).

Yani İşleyici veya İş Parçacığı arasında seçim yapma şansınız yok. Ağır işler yapmak için iplik kullanın! (Arka plan iş parçacığınız başka bir iş parçacığında (çoğu zaman kullanıcı arabirimi iş parçacığında) yapılacak bazı işleri tetikleyecekse bir İşleyici kullanabilirsiniz)


Hızlı yanıtınız ve harcadığınız zaman (ve yanıtınızın hızı !!) için teşekkürler!
JRun

28

Handlerve Threadiki farklı şeydir, ancak birbirleriyle çelişmezler. Aynı anda a Handlerve a'ya sahip olabilirsiniz Threadve aslında her biri Handlerbir Thread.

Daha fazla ayrıntı için bu makaleye göz atmak isteyebilirsiniz .

görüntü açıklamasını buraya girin


19

Bir HandlerAynı üzerinde çalışır Thread, bir Threadfarklı bir iş parçacığı üzerinde çalışır.

Aynı iş parçacığı üzerinde , genellikle bir GUI öğesi veya bunun gibi bir şey üzerinde bir şey çalıştırmanız gerekirse, bir İşleyici kullanın .

Ana iş parçacığını başka şeyler yapmak için serbest bırakmak istiyorsanız bir İş Parçacığı kullanın . Bunu önemli miktarda zaman alan her şey için kullanın.


6
Aynı iş parçacığı üzerinde bir şey çalıştırmak istersem neden bir eylemci kullanmalıyım? mHandler.post (...) yönteminin amacı nedir?
Elias

1
Elias, böyle bir durumda, belirli bir görevin belirli bir süre sonra çalışmasını veya bir görevi her X zaman diliminde tekrar etmesini istiyorsan işleyiciyi kullanabilirsin. Bunları kullanmak istemiyorsanız haklısınız. işleyici kullanmak değersizdir. GUI işlerini hemen orada yapabilirsiniz ve sonra, UI iş parçacığının içindesiniz, çünkü işleyici yaratıldığı iş parçacığı üzerinde çalışır.
tony9099

14

İşleyiciler, arka plan ile UI iş parçacığı arasındaki iletişimin en iyi yoludur. Genellikle İşleyiciler, bir İş Parçacığının ileti Sırası ile ilişkilendirilir ve ileti göndermek için kullanılır ve İletiye çalıştırılabilir.

KULLANIM:

İş Parçacığı: UI iş parçacığından daha farklı (Arka Plan) iş parçacığı içinde görevler yapmak için. (UI iş parçacığının engelini kaldırmaya yardımcı olur)

İşleyici UI ve Arka Plan iş parçacığı arasında iletişim kurmak için kullanılır.

Bu makaleye bir göz atın


4

Kullanıcı arayüzünü yeni bir İş Parçacığından güncellemeniz gerekiyorsa, kullanıcı arabirimi iş parçacığı ile senkronize etmeniz gerekir.

Bunun için android.os.Handler sınıfını veya AsyncTasks sınıfını kullanabilirsiniz.

Handler sınıfı, kullanıcı arayüzünü güncelleyebilir. İşleyici, Message veya Runnable sınıfının örneklerini almak için yöntemler sağlar.

İş parçacığı, sendMessage (Mesaj mesajı) yöntemi veya sendEmptyMessage () yöntemi yoluyla mesaj gönderebilirsiniz.

... iş parçacıkları vb. hakkında daha fazla bilgi burada (farklı iş parçacığı ve senkronizasyon mekanizmaları için türler ve neyin ne zaman kullanılacağı dahil)


Soruma cevap vermeye zaman ayırdığınız için teşekkürler. Lars Vogel'in blogunu seviyorum, çok anlayışlı ve takip etmesi kolay. Teşekkürler!
JRun

2

İş Parçacığı değil de İşleyici kullanmanın avantajları / nedenleri nelerdir?

Bir İşleyici , mesaj ve Runnablebir iş parçacığıyla ilişkili nesneleri göndermenize ve işlemenize olanak tanır MessageQueue. Her Handlerörnek tek bir iş parçacığı ve bu iş parçacığının ileti kuyruğu ile ilişkilendirilir.

Yeni bir oluşturduğunuzda Handler, onu oluşturan iş parçacığının iş parçacığı / ileti kuyruğuna bağlanır - bu noktadan sonra, iletileri ve çalıştırılabilirleri bu ileti kuyruğuna gönderir ve ileti kuyruğundan çıktıkça bunları yürütür. .

İşleyicinin iki ana kullanımı vardır:

  1. Gelecekte bir noktada yürütülecek mesajları ve Runnable'ları planlamak için
  2. To enqueue bir eylem sizinkinden farklı bir iş parçacığı üzerinde gerçekleştirilecek.

Java dizileri kullanıyorsanız, bazı şeyleri kendi başınıza halletmeniz gerekir - ana iş parçacığı ile senkronizasyon, bir iş parçacığını iptal etme vb.

Bu tek İş Parçacığı, siz ThreadPoolExecutorveya ExecutorServiceAPI kullanmadığınız sürece bir iş parçacığı havuzu oluşturmaz .

(Bu sorguyu Blackbelt cevabındaki yorumlarınızdan aldınız)

Neden bir Cellat kullanmıyorsunuz? ve bunu yapmak için bir İşleyici kullanmak istesem bile, nasıl?

Referans: İş Parçacığı Performansı makalesi

Oldukça paralel, dağıtılmış görevlere indirgenebilecek belirli çalışma türleri vardır. Bu, iş paketlerinin büyük hacmiyle yaratır AsyncTaskve HandlerThreaduygun sınıflar değildir. Tek iş parçacıklı doğası, AsyncTasktüm iş parçacığı paylaşımlı işi doğrusal bir sisteme dönüştürecektir. HandlerThreadÖte yandan sınıfı kullanmak, programcının bir grup iş parçacığı arasındaki yük dengelemeyi manuel olarak yönetmesini gerektirecektir.

ThreadPoolExecutor , bu işlemi kolaylaştırmak için yardımcı bir sınıftır. Bu sınıf, bir grup iş parçacığının oluşturulmasını yönetir, önceliklerini belirler ve işin bu diziler arasında nasıl dağıtılacağını yönetir. İş yükü arttıkça veya azaldıkça, sınıf iş yüküne uyum sağlamak için daha fazla iş parçacığı döndürür veya yok eder.

 BlockingQueue workQueue= new LinkedBlockingQueue<Runnable>(100); // Work pool size
 ThreadPoolExecutor executor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),       // Initial pool size
            Runtime.getRuntime().availableProcessors(),       // Max pool size
            1, // KEEP_ALIVE_TIME
            TimeUnit.SECONDS, //  KEEP_ALIVE_TIME_UNIT
            workQueue);

Daha fazla ayrıntı için, iş parçacığı oluşturma hakkındaki bu geliştirici kılavuzu makalesine başvurabilirsiniz .

HandlerBirden çok Runnable örneğini çalıştırmak için kullanımı için bu gönderiye bir göz atın . Bu durumda, tüm Runnablegörevler tek bir İş Parçacığında çalışacaktır.

Android: Bir ileti dizisinde tost


1

HandlerThreadSıraya Alınmış bir mekanizma oluşturmak için ile birlikte kullanılabilir . Bir handlerşey göndermek için kullanabilirsiniz .Thread Looper


Soruma cevap vermeye zaman ayırdığınız için teşekkürler. Neden bir Cellat kullanmıyorsunuz? ve bunu yapmak için bir İşleyici kullanmak istesem bile, nasıl?
JRun

yürütücü biraz farklı. Bunu kullanmak için iş parçacığını genişletmeniz gerekir ve çalıştırmada Looper sınıfının static.metohd hazırlayın. Statik yöntem döngüsünü çağırdıktan sonra bir sıra oluşturulur ve istekleri iletmek ve sonuçları geri almak için bir işleyici sırası kullanabilirsiniz
Blackbelt
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.