13 Şubat 2018 Salı

Android Dersleri 18 - Looper, MessageQueue Handler, HandlerThread, Thread, Runnable,Message


18 -Looper, MessageQueue Handler, HandlerThread, Thread, Runnable,Message

Overview
(http://stackoverflow.com/questions/12877944/what-is-the-relationship-between-looper-handler-and-messagequeue-in-android)
        It's widely known that it's illegal to update UI components directly from threads other than main thread in android.  if we need to start a separate thread to do some expensive work and update UI after it's done. The idea is to create a Handler object associated with main thread, and post a Runnable to it at appropriate time. This Runnable will be invoked on the main thread. This mechanism is implemented with Looper and Handler classes. ( Main thread'den başka bir thread'de UI component'leri update etmek illegaldir,yasaktır. Eğer ayrı bir thread'de ağır bir iş yapmak ve buiş bittikten sorna UI'ı update etmek istiyorsak şunları yapmalıyız:Main thread ile ilişkili bir Handler object yaratmalıyız. Ona(o kim?) uygun bir zaman bir Runnable object göndermeliyiz. Runnable object main thread'de invoke edilir. Bu mekanizma Looper ve Handler kullanılarak implement edilir. Bu paragrafı ben de tam anlamadım buraya daha sonra geri dönüp incele tekrar. )
        The Looper class maintains a MessageQueue, which contains a list of messages. An important character of Looper is that it's associated with the thread within which the Looper is created. This association is kept forever and can't be broken nor changed. ( Looper class'ı, bir MessageQueue içerir. MessageQueue ise Message object içeren bir LinkedList içerir. Looper, hangi thread içerisinde yaratıldıysa o thread ile ilişkilendirilir, bu özellik sonsuza kadar sürer asla bozulmaz ve değiştirilemez.  )
        Also note that a thread can't be associated with more than one Looper. In order to guarantee this association, Looper is stored in thread-local storage, and it can't be created via its constructor directly. The only way to create it is to call prepare static method on Looper. prepare method first examines ThreadLocal of current thread to make sure that there isn't already a Looper associated with the thread. After the examination, a new Looper is created and saved in ThreadLocal. Having prepared the Looper, we can call loop method on it to check for new messages and have Handler to deal with them.
( Ayrıca, 1 thread sadece 1 Looper ile ilişkilendirilebilir. Bu ilişkiyi garantilemek için, Looper thread'in scope'u içerisinde yaşar, yani Looper'ın doğrudan contructor'ını çağırarak bir Looper object yaratılamaz. Looper object yaratmanın yolu, Looper class'ının static bir method'u olan prepare() method'unu çağırmak gerekir. prepare() method'u, current thread ile ilişkili bir Looper var mı diye bakar, yoksa yeni bir Looper object yaratır, ve bu object'i ThreadLocal'a kaydeder. Sonra Looper object'in loop() method'unu çağırırız, bu method looper'ın messageQueue'sunda yeni bir mesaj var mı diye bakar. Varsa bu mesajı Handler'a verir.)
        As the name indicates, the Handler class is mainly responsible for handling (adding, removing, dispatching) messages of current thread's MessageQueue. A Handler instance is also bound to a thread. The binding between Handler and Thread is achieved via Looper and MessageQueue. A Handler is always bound to a Looper, and subsequently bound to the thread associated with the Looper. (Handler class'ı, current thread'in MessageQueue'sundaki mesajlar ile ilgilenmekten sorumludur. Bir Handler object, bir thread'e bound'dur, yani bir thread'e bağlıdır, bir thread ile ilişkilidir. Bir Handler genellikle bir Looper'a bağlıdır(bound) dolayısıyla Looper'ın bağlı olduğu thread'e bağlıdır. Dolayısıyla bir handler'ın bir thread ile ilişkilendirilmesi Looper ve MessageQueue aracılığıyla gerçekleştirilir. Nasıl ilişkilendirileceğini ben de bilmiyorum henüz. )
        Unlike Looper, multiple Handler instances can be bound to the same thread. Whenever we call post or any methods alike on the Handler, a new message is added to the associated  MessageQueue. The target field of the message is set to current  Handler instance. When the Looper  received this message, it invokes dispatchMessage on message's target field, so that the message routes back to the Handler instance to be handled, but on the correct thread. ( 1 Looper'ın sadece 1 thread ile ilişkili olabileceğini söylemiştik daha önce. Handler'larda ise durum farklıdır, 1'den fazla Handler aynı thread'e ilişkilendirilebilir. Handler class'ının post() method'unu veya buna benzer bir method'unu çağırdığımızda, Handler'ın ilişkili olduğu Looper'daki MessageQueue'ya bir mesaj eklenir. Bu mesajın target alanına mesajı gönderen Handler object set edilir, bu sayede bu mesajı looper'a gönderen handler bir süre sonra bu mesajı looper'dan geri alacaktır. Yani her mesaj göndericisine teslim edilir looper tarafından. Looper mesajı alınca, mesajın target alanındaki dispatchMessage'I invoke edince bu mesaj doğru thread'deki doğru handler'a gönderilir.  )
---
        Let's start with the Looper. You can understand the relationship between Looper, Handler and MessageQueue more easily when you understand what Looper is. Also you can better understand what Looper is in the context of GUI framework. Looper is made to do 2 things. ( Looper, Handler ve MessageQueue arasındaki ilişkiyi anlamak için önce Looper'ın ne olduğunu anlamak gerekir. Looper şu iki işi yapar. )
1) Looper transforms a normal thread, which terminates when its run() method return, into something run continuously until Android app is running, which is needed in GUI framework (Technically, it still terminates when run() method return. But let me clarify what I mean in below). ( Looper, Normal bir thread, run() method'u return ettikten sonra yok edilir. Looper normal bir thread'i Android uygulaması çalıştığı sürece çalışan bir thread'e dönüştürür. GUI framework için böyle bir thread'e ihtiyaç vardır. Teknik olarak run() method'U return ettikten sonra thread yok edilir ancak demek istediğimiz aşağıdakileri okuyunca anlayacaksınız. )
2) Looper provides a queue where jobs to be done are enqueued, which is also needed in GUI framework. (Looper bir mesaj kuyruğu içerir. Yapılacak işler bu kuyruğa sokulur, sonra single bir thread bu kuyruktaki işleri tek tek gerçekleştirir. Böyle bir şeye GUI framework'de de ihtiyaç vardır. )
        As you may know, when an application is launched, the system creates a thread of execution for the application, called “main”, and Android applications normally run entirely on a single thread by default the “main thread”. But main thread is not some secret, special thread. It's just a normal thread that you can also create with new Thread() code, which means it terminates when its run() method return! Think of below example. ( Bir uygulamayı çalıştırdığımızda, sistem bu uygulama için bir main thread yaratır. Bir Android uygulaması genellikle single bir thread'de(main ui thread'de) çalışır. main thread'in hiç bir ekstra özelliği yoktur, new Thread() diyerek yaratabileceğimiz normal bir thread'dir. Yani bu haliyle main thread run() method'u return ettikten sonra terminate olur(sonlanır, yok olur). Aşağıdaki örneği düşünelim, bu örnekteki thread hemencecik çalışır run() method'u return edince de thread biter, yok olur. )
public class HelloRunnable implements Runnable {
    public void run() {
        System.out.println("Hello from a thread!");
    }
    public static void main(String args[]) {
        (new Thread(new HelloRunnable())).start();
    }
}
        Now, let's apply this simple principle to Android app. What would happen if an Android app is run on normal thread? A thread called "main" or "UI" or whatever starts application, and draws all UI. So, the first screen is displayed to users. So what now? The main thread terminates? No, it shouldn’t. It should wait until users do something, right? But how can we achieve this behavior? Well, we can try with Object.wait() or Thread.sleep(). (Şimdi bir Android uygulamasındaki main thread'in de yukarıdaki örnekteki gibi çalıştığını düşünelim, yani uygulamamızın normal bir thread üzerinde çalıştığını düşünelim. Main thread çalışıp ui'ı çizdi, ilk ui ekranı kullanıcıya gösterildi diyelim. Kullanıcıdan bir action bekleniyor diyelim. Peki şu an main thread öldü mü sizce ne yapıyor? Hayır. Main thread, kullanıcının bir şeyler yapmasını bekliyor.  Peki bu davranışı nasıl implement edebiliriz? Object.wait() veya Thread().sleep() method'Unu çağırarak main thread'i bekletebiliriz. )       
        For example, main thread finishes its initial job to display first screen, and sleeps. It awakes, which means interrupted, when a new job to do is fetched. So far so good, but at this moment we need a queue-like data structure to hold multiple jobs. Think about a case when a user touches screen serially, and a task takes longer time to finish. So, we need to have a data structure to hold jobs to be done in first-in-first-out manner. Also, you may imagine, implementing ever-running-and-process-job-when-arrived thread using interrupt is not easy, and leads to complex and often unmaintainable code. We'd rather create a new mechanism for such purpose, and that is what Looper is all about. ( Örneğin, main thread, ilk ekranı gösterme işini bitirdi ve uyudu diyelim. Main thread, yapması gereken bir iş geldiğinde uyanır; peki birden fazla iş gelirse ne olur? bu işleri bir kuyruğa sokmamız gerekir yani main thread içerisinde queue'ya benzer bir data structure'a ihtiyacımız vardır. Örneğin, kullanıcı ekrana art arda hızlıca tıkladı, bir task'ın işinin bitmesi uzun zaman sürüyor diyelim, bu durumda yapılacak işleri first-in first out olarak tutaacak bir data structure'a yani queue'ya ihtiyacımız var. Sürekli çalışan ve gelen işleri yapan hiçbir zaman terminate olan bir thread implement etmek kolay değildir, çok complex'dir ve bu kodu sürdürmek çok zordur. Android böyle bir mekanizmayı bizim için zaten implement etmiştir, bu amaçla kullanmak için Looper class'ını sunar bize. )
        The official document of Looper class says, "Threads by default do not have a message loop associated with them", and Looper is a class "used to run a message loop for a thread". Now you can understand what it means. ( Looper class'ının resmi dökümanında şu yazar : Default olarak, Thread'ler bir message loop'a(message queue gibi düşün)  sahip değildir. Looper class'ı ise bize message loop'a(message queue'ya) sahip olan bir thread sağlar. )
        Looper, MessageQueue'ya sahiptir.
        Handler, çeşitli post(Runnable r) method'larından birini çağırarak ilişkili olduğu Looper'daki message queue'ya yeni bir Message ekler.
        My last word is, so basically Looper is a class that is made to address a problem that occurs in GUI framework. But this kind of needs also can happen in other situation as well. Actually it is a pretty famous pattern for multi threads application, and you can learn more about it in "Concurrent Programming in Java" by Doug Lea(Especially, chapter 4.1.4 "Worker Threads" would be helpful). Also, you can imagine this kind of mechanism is not unique in Android framework, but all GUI frameworks may need somewhat similar to this. You can find almost the same mechanism in Java Swing framework. ( Toparlayalım, Looper temel olarak GUI framework'de olabilecek bir problemi çözmek için implement edilmiştir. Bu çeşit ihtiyaçlar, başka durumlarda vardır. Aslında bu multithread uygulamalar için kullanılan ünlü bir pattern'dır. Ayrıca bu mekanizma Android' özel değildir, tüm GUI framework'leri buna benzer bir mekanizmaya ihtiyaç duyar, çünkü ekranda bir şey gösterdikten sonra thread'in terminate olmaması çalışmaya devam etmesi kuyruğa gelen işleri sırayla yapması için böyle bir mekanizmaya ihtiyaç vardır graphical user interface'ler için. )
---
        The Looper class is usually used in conjunction with a HandlerThread (a subclass of Thread). A Handler is a utility class that facilitates interacting with a Looper—mainly by posting messages and Runnable objects to the thread's MessageQueue. When a Handler is created, it is bound to a specific Looper (and associated thread and message queue). (Handler, Looper'daki MessageQueue'ya message ekler. Bir Handler yaratıldığında belirli bir Looper ile ilişkilendirilir, ayrıca Looper'ın MessageQueue'su ile de ilişkilendirilmiş olur, ayrıca looper ile ilişkilendirilen Thread ile de ilişkilendirilmiş olur . Yani Handler şu 3 şeyle ilişkilendirilmiş olur : Looper, MessageQueue, Thread. )
        In typical usage, you create and start a HandlerThread, then create a Handler object (or objects) by which other threads can interact with the HandlerThread instance. The Handler must be created while running on the HandlerThread, although once created there is no restriction on what threads can use the Handler's scheduling methods (post(Runnable), etc.)
The main thread (a.k.a. UI thread) in an Android application is set up as a looper thread before your application is created. (Genellikle şöyle kullanırız : Bir HandlerThread yaratırız ve bu thread'i başlatırız. sonra bir Handler object yaratırız. Diğer thread'ler HandlerThread object ile iletişim kurabilir. Handler, HandlerThread içerisinde yaratılmak zorundadır; buna karşın Handler yaratıldıktan sonra Handler'ın scheduling method'larını (post(Runnable) vs method'larını) her Thread kullanabilir, bu konuda kısıtlama yoktur. Uygulamanızdaki main thread, looper thread olarak set edilir. Bu paragraftaki şeyleri çok anlamasam da açıkladım bunları tekrar incelemeliyim. )
----
AsynchronousAndroid.pdf kitabından :
http://files.dcarl.me/books/First_Collection_Programming_Books/Asynchronous%20Android%20%5BeBook%5D.pdf
https://github.com/steveliles/AsyncAndroid
        Looper is a simple class that quite literally loops forever, waiting for Messages to be added to its queue and dispatching them to target Handlers. Looper is an implementation of a common UI programming concept known an Event Loop. (Looper sonsuza kadar belirli bir döngüde çalışan basit bir class'dır. İçerdiği kuyruğa mesaj gelmesini bekler, mesaj gelince bu mesajı hedef Handler'a gönderir(dispatch). Looper class'ının yaptığı döngü budur işte. Looper aslında Event Loop diye bilinen UI programlama konsepti'nin implementation'ıdır. )
        To set up a Looper thread, we need to invoke two static methods of Looper - prepare and loop - from within the thread that will handle the message loop.( Looper object'i yaratmak için prepare() method'unu, çalışmaya başlatmak için loop() method'Unu çağırırız. Looper'ın hangi thread ile ilişkili olmasını istiyorsak, o thread'İn run() method'unun içerisinde çağırırız Looper.prepare() ve Looper.loop() method'larını.  )
class SimpleLooper extends Thread {
public void run() {
   Looper.prepare();
   Looper.loop();
}
}
       That was easy; however, the SimpleLooper class defined here provides no way to add messages to its queue, which is where Handler comes in. ( SimpleLooper isimli bir thread tanımladık, bu thread içerisinde bir looper tanımladık. Ancak bu looper'ın message queue'suna mesaj eklemek için Handler'a ihtiyacımız var.  )
        Handler serves two purposes—to provide an interface to submit Messages to its Looper queue and to implement the callback for processing those Messages when they are dispatched by the Looper. ( Handler'ın 2 amacı vardır :
- Looper'ın mesaj kuyruğuna mesaj eklemek
- Looper handler'a kuyruktaki bir mesajı gönderince handler bu mesajı işlemek için bir callback implement eder, yani handler mesajları işler diye anladım doğru mu emin değilim.  )
        To attach a Handler to SimpleLooper, we need to instantiate the Handler from within the same thread that prepared the Looper. The Handler is associated with the main Looper by the super-class constructor, which obtains the Looper using a static method. ( Yukarıda tanımladığımız Looper ile bir Handler'ı ilişkilendirelim. Bunun için hem looper'ı hem de handler'ı aynı thread içerisinde yaratırız. Yani, looper'ı yarattığımız thread içerisinde, handler class'ından bir object yaratırız. Son cümleyi anlamadım. )
class SimpleLooper extends Thread {
public Handler handler;
public void run() {
   Looper.prepare();
   handler = new Handler();
   Looper.loop();
}
}
        Once started, the Looper thread will wait (Object.wait) inside Looper.loop() for Messages to be added to its queue.
        When another thread adds a Message to the queue it will notify (Object.notify) the waiting thread, which will then dispatch the Message to its target Handler by invoking the Handler's dispatchMessage method. ( Looper thread çalışmaya başladıktan sonra Looper.loop() olduğu satırda mesaj gelmesini bekler. Başka bir thread, bizim thread'imizin queue'suna bir mesaj ekleyince, thread'imizi uyarır(notify). Bizim thread'imizin looper'ı gelen mesajı target handler'a dispatch eder(hemencecik gönderir). )
        The wait/notify mechanism is a very efficient way of suspending activity on a particular thread while there is no work for it to do, so that it doesn't waste CPU cycles, then resuming work once there is something for it to do. ( wait/notify mekanizması, bir activity'yi belirli bir thread üzerinde yapacak bir iş yokken bekletmek için kullanılan çok verimli bir mekanizmadır. Bu sayede CPU cycle israfı önlenir. Yapacak bir iş gelince de activty thread üzerinde çalışmaya devam eder. )
        Because dispatchMessage is invoked by the thread running the message loop, we can send Messages to the Handler from any thread and they will always be dispatched by the message loop thread as shown in the following diagram: ( Looper'ı çalışan thread'in dispatchMessage() method'u çağırıldığı için, Handler'a herhangi bir thread'den mesaj gönderebiliriz. Aşağıdaki diagramı bakınca daha iyi anlayacağız. Ortadaki thread bizim thread'imizdir. Soldaki ve sağdaki thread'lerin handler'larının sendMessage()method'u çağırılarak bizim thread'imizin message loop'una Runnable object veya Message ekler. Bizim thread'imizin handler'ının dispatchMessage() method'u çağırılarak, looper'ımızın handler'ımıza mesajı göndermesi sağlanır. )
        We already saw that we can create our own Looper threads, but here's the fun part and this may come as a surprise: the main thread is in fact a Looper thread, as we can see in the following stack trace: ( Main thread aslında looper thread'dir, aşağıdaki stack trace'den de bunu anlayabilirsin. )
at example.handler.MyActivity.onCreate(Example1Activity.java:19)
at android.app.Activity.performCreate(Activity.java:5206)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4898)
        That's right! Everything that happens in an Activity lifecycle callback method is running in a dispatchMessage call invoked by the main Looper! (main looper tarafından çağırılan dispatchMessage( ) method'unda, bir activity'nin yaşam döngüsü method'u çalışır. )
        The interesting thing to realize here is that we can send messages to the main thread from any other thread (or even from the main thread itself) and in doing so, hand over work from background threads to the main thread—for example, to have it update the user interface with the results of background processing. ( Burada şunu fark edelim: Diğer thread'lerden veya main thread'den main thread'e mesaj gönderebiliriz. Yani thread'ler arasında bir iletişim kurarız bu mekanizmayla. Bu sayede arka planda çalışan thread'ler main thread'e iş gönderip böylece ui'ı güncelleyebiliriz.  )
Building responsive apps with Handler
        The Handler class is fundamental to the infrastructure of Android apps—together with Looper. It underpins everything that the main thread does—including the invocation of the Activity lifecycle methods. ( Handler class'ı Looper ile birlikte Android uygulamalarının altyapısının temelini oluşturur. Handler class'ı main thread'in yaptığı işlerin temelini oluşturur, activity'nin lifecycle method'larının çağırılmasının da temelini oluşturur. )
        While Looper takes care of dispatching work on its message-loop thread, Handler provides the means to add work to the message queue belonging to a Looper. ( Looper'ın görevi mesaj kuyruğundaki işleri Handler'a göndermektir(dispatch). Handler'ın görevi Looper'ın mesaj kuyruğuna iş eklemektir. )
        We can create a Handler to submit work to be processed on the main thread simply by creating a new instance of Handler from an Activity lifecycle method such as onCreate, shown as follows: ( Main thread'de çalışmasını istediğimiz bir iş istiyoruz diyelim. Bunun için activity'mizin lifecycle method'larından birinde mesela onCreate() method'unda Handler class'ından bir object yaratırız. Handler object hangi thread içerisinde yaratılırsa o  thread ile ilişkilendirilir, hatırla! Dolayısıyla main thread'de bir handler object yarattığımız için handler'ımız main thread ile ve main looper ile ilişkilidir, main looper'daki kuyruğa iş ekleyebilir. Bu 1. yoldur. )
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Handler handler = new Handler();
// …
}
        We could also be explicit that we want to submit work to the main thread by passing a reference to the main Looper instance into the Handler constructor. ( Ayrıca, Handler'ın işi main thread'e göndermesini de explicit bir şekilde belirtebiliriz. Handler'ın constructor'ına main Looper instance'ı veririz. Artık bu handler işleri main thread'e gönderecektir.  Bu 2. yoldur.  )
Handler handler = new Handler(Looper.getMainLooper());
        Exactly what we mean by "work" can be described by subclasses of java.lang. Runnable, or instances of android.os.Message. We can post Runnables to a Handler instance or send Messages to it, and it will add them to the queue belonging to the associated Looper instance. ( Mesaj kuyruğuna ekleyeceğimiz object ya Runnable ya da Message class'ının instance'ıdır. Bir Handler'a Runnables veya Messages send ederiz, Handler da bunları ilişkili olduğu Looper'ın mesaj kuyruğuna ekler.   )
Scheduling work with post
        We can post work to a Handler very simply, for example, by creating an anonymous inner Runnable:  ( Bir handler'a bir işi nasıl post ederiz? handler object'in post method'unu çağırırız. post() method'una argument olarak yarattığımız anonymous Runnable object'i veririz. )
handler.post(new Runnable(){
         public void run() {
                   // do some work on the main thread.
         }
});
        The Looper instance to which the Handler is bound works its way through the queue, executing each Runnable as soon as possible. Posting with the post method simply adds a new Runnable at the end of the queue. ( Yukarıda kod çalışınca handler'ın ilişkili olduğu looper'ın kuyruğunun sonuna bir Runnable object eklenir. )
        If we want our Runnable to take priority over anything currently in the queue, we can post it to the front of the queue ahead of existing work: (Aşağıdaki kod çalışınca handler'ın ilişkili olduğu looper'ın kuyruğunun başına bir Runnable object eklenir. handler object'in postAtFrontOfQueue  method'unu çağırılarak kuyruğa en öncelikli bir iş eklemiş oluruz.   . )
handler.postAtFrontOfQueue(new Runnable(){
        public void run() {
                // do some work on the main thread.
        }
});  
        What if we want to schedule some work in 10 seconds time? One way to do this would be to Thread.sleep the main thread for 10 seconds, but that would mean the main thread can't do anything else in the meantime. Also, remember that we must never block the main thread! The alternative is to post a delayed Runnable to the Handler. ( 10 saniye sonra bir iş yapılmasını istiyoruz diyelim, bu durumda main thread'i uyutmayı deneyebiliriz ancak böyle yaparsak main thread bu esnada hiçbir şey yapmaz, main thread'i asla block etmemeliyiz. handler'ın postDelayed() method'u çağırılarak, handler'ın ilişkili olduğu looper'ın kuyruğuna 10 sn bekledikten sonra bir Runnable object eklenmesi sağlanır. )
handler.postDelayed(new Runnable(){
public void run() {
    // do some work on the main thread
        // in 10 seconds time
     }
}, TimeUnit.SECONDS.toMillis(10) );
        We can still post additional work for execution in the meantime, and our delayed Runnable instance will execute after the specified delay. Note that we're using the TimeUnit class from the java.lang.concurrent package to convert seconds to milliseconds. ( Runnable object 10 saniye sonra çalışacaktır. Bu örnekte concurrent package'ını kullanarak saniyeleri milisaniyelere çevirdik. )
        A further scheduling option for posted work is postAtTime, which schedules Runnable to execute at a particular time relative to the system uptime (how long it has been since the system booted):
handler.postAtTime(new Runnable(){
public void run() {
// … do some work on the main thread
}
}, SystemClock.uptimeMillis() + TimeUnit.SECONDS.toMillis(10));
        Since postDelayed is implemented in terms of an offset from the SystemClock uptime, it is usually easier to just use postDelayed. (postAtTime method'unu kullanmaktasnsa postDelayed() method'Unu kullan postDelayed()method'U daha basittir.  )

        As we'll see in the Issues section, posting an anonymous Runnable makes for concise examples but when used with postDelayed or postAtTime requires care to avoid potential resource leakage. (postDelayed ve postAtTime method'larını kullanırken çok dikkatli olmalıyız çünkü bu method'ların yanlış kullanımı genellikle resource leakage'a neden olur. )
        Since we instantiated our Handler on the main thread, all work submitted to it executes on the main thread. This means that we must not submit long running operations to this particular Handler, but we can safely interact with the user interface:  ( Handler object'i main thread'de yarattığımız için Handler'a post edilen işler main thread'de çalışır. Dolayısıyla bu Handler'a uzun süren işler post etmemeliyiz,  çünkü main thread'de uzun süren işler yapıp main thread'i meşgul etmemeliyiz. Handler object'e post edeceğimiz iş user interface'i değiştirebilir. )
handler.post(new Runnable(){
public void run() {
     TextView text = (TextView) findViewById(R.id.text);
     text.setText("updated on the UI thread ! ");
}
});
        This applies regardless of which thread posts the Runnable, which makes Handler an ideal way to send the results of work performed by other threads to the main thread. ( Başka thread'ler, main thread'e iş göndererek de ui güncellenebilir. Aşağıdaki kodu inceleyelim. Handler object'i activity'nin onCreate() method'unda yaratmıştık. Dolayısıyla bu handler object'in post method'una çağırarak handler'a post edeceğimiz işler main thread'de yapılacaktır, dolayısıyla bu handler'a uzun süren bir iş post etmememiz gerektiğii daha önce söylemiştik. Aşağıda bir thread object tanımladık. Bu thread'in run() method'unda calculatePrime() method'unu çağırdık, bu method'un return etmesi uzun sürecektir. Sonra handler object'in post method'una bir Runnable object veririz, bu Runnable object'in run method'unda textview'e hesapladığımız değeri set ederiz. En son bu thread'in priority'isini set ederiz(thread.setPriority) ve thread'in çalışmasını başlatırız(thread.start()). Aşağıdaki kodda, background'da çalışan bir thread'de uzun süren bir iş yapılmış, sonuç elde edilince handler'ın post method'u çağırılarak main thread'in ilişkili olduğu looper'ın mesaj kuyruğuna iş eklenir, bu iş main thread'de çalışıp textview'in içeriği set edilir. )
Thread thread = new Thread(){
        public void run()
        {
                final BigInteger result = calculatePrime(500);
                handler.post(new Runnable()
                {
                        public void run(){
                               TextView text = (TextView)  findViewById(R.id.text);
                               text.setText(result.toString());
                        }
                });
        }
};
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
        If you start your own threads for the background work, make sure to set the priority to Thread.MIN_PRIORITY to avoid starving the main thread of CPU time. ( Arka planda çalışmak için bir thread başlatacağımız zaman bu thread'in priority'sini Thread.MIN_PRIORITY olarak set etmeliyiz. Aksi takdirde main thread CPU'dan yeteri kadar istifade edemeyebilir. )
        Handler is so fundamental that it is integrated right into the View class hierarchy, so we can rewrite the last example as follows: ( Handler o kadar temel ve önemli bir kavramdır ki, View class ile de entegre edilmiştir. Dolayısıyla biraz önceki örneği aşağıdaki şekilde de yazabiliriz, yukarıdaki kod ve aşağıdaki kod aynı işi yapar. Önceki kodda, main thread'de yarattığmız handler object'in post method'unu çağırmıştık, post method'unun aldığı Runnable object'İn run() method'unda textview'i set etmiştik. Aşağıda ise, önce textview object'i elde ettik. Sonra yeni bir thread'İn run() method'Unda handler'ın değil textview'in post method'unu çağırdık. Yani textview object'e handler object gibi davrandık bu örnekte. Yani bir handler ile yapabileceğin bir işlemi textview ile dde yapabiliyorsun demekki. )
final TextView text = (TextView) findViewById(R.id.text);
Thread thread = new Thread()
{
        public void run()
        {
                final BigInteger result = calculatePrime(500);
                text.post(new Runnable()
                {
                        public void run() {
                               text.setText(result.toString());
                        }
                });
        }
};
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
Bu iki kod arasındaki farkı aşağıdaki resimden de inceleyebilirsin:

        For comparison, both of the previous examples are roughly equivalent to the following AsyncTask code: ( Yukarıdaki 2 kodun yaptığı işin aynısını, aşağıdaki kod AsyncTask kullanarak yapabilir. AsyncTask'ın doInBackGround()method'unda uzun süren işlemler yapılır,m bu method return ettikten sonra onPostExecute()method'u çağırılarak textview set edilir. Yani AsyncTask kullanarak ui'ı güncelleyebiliriz. )
new AsyncTask<Void, Void, BigInteger>()
{
        public BigInteger doInBackground(Void… params)
        {
                return calculatePrime(500);
        }
        public void onPostExecute(BigInteger result)
        {
                TextView text = (TextView) findViewById(R.id.text);
                text.setText(result.toString());
        }
}.execute();

        When writing code in an Activity class, there is an alternative way of executing a Runnable on the main thread using the runOnUiThread method of Activity. If invoked from a background thread, the Runnable will be posted to a Handler instance attached to the main thread. If invoked from the main thread, the Runnable will be executed immediately. ( Main thread'de bir runnable object çalıştırmanın farklı bir yolu da  runOnUiThread() method'unu kullanmaktır. Örneğin background'da çalışan bir thread yaratacağız diyelim, bu thread'den ui'i değiştirebilmek istiyoruz, ancak daha önce de öğrendiğimiz gibi background thread'ler yani non-ui thread'lerden ui değiştirilemez. UI sadece main thread(ui thread) içerisinde değiştirilebilir.
        Ancak bu kuralı esnetmenin bir yolu vardır. Bir background thread içerisinden runOnUiThread() method'unu çağırırız, bu method'unda aldığı argument olan Runnable object'İn run method'unda ui'ı değiştirebiliriz. Yarattıımız background thread arka planda çalışır, sadece runOnUiThread() method'unun aldığı Runnnable object'in run() method'unda ui thread'de çalışır.
        Aşağıdaki koddaki gibi, runOnUiThread()  method'unu bir background thread içerisinde çağırırsak bu method'Unda aldığı argument olan Runnable object, maiin thread'İn ilişkili olduğu Handler object'e post edilir. Eğer runOnUiThread()  method'unu main thread içerisinde çağırırsak, Runnnable anında execute edilir.   )
public class TestActivity extends Activity {
            Button btn;
            int i = 0;

            @Override
            public void onCreate(Bundle savedInstanceState) {
                        super.onCreate(savedInstanceState);
                        setContentView(R.layout.main);
                        btn = (Button)findViewById(R.id.btn);
                        btn.setOnClickListener(new View.OnClickListener() {
                                   @Override
                                   public void onClick(View v)
                                   {
                                               runThread();
                                   }
                         });
            }

            private void runThread()
            {
                        new Thread() {
                                   public void run() {
                                               while (i++ < 1000) {
                                                           try {
                                                                       runOnUiThread(new Runnable()
                                                                       {
                                                                                  @Override
                                                                                  public void run()
                                                                                  {
                                                                                              btn.setText("#" + i);
                                                                                  }
                                                                       });
                                                                       Thread.sleep(300);
                                                           } catch (InterruptedException e) {
                                                                       e.printStackTrace();
                                                           }
                                               }
                                   }
                        }.start();
            }
}
        When you explicitly spawn a new thread to do work in the background, this code is not run on the UIThread. So what happens if this background thread needs to do something that changes the UI? This is what the runOnUiThread is for. runOnUiThread provides these background threads the ability to execute code that can modify the UI. They do this by putting the UI-modifying code in a Runnable object and passing it to the runOnUiThread method.
        non-UI and UI thread'ler arasında iletişim kurmak için, runOnUiThread() method'unu kullanabiliriz. Bu method, activity class'ında tanımlıdır. Dolayısıyla activity class'ında kodyazarken kullanabiliriz bu method'u. Bir non-UI thread, UI thread'de çalışmasını istediği bir Runnable olduğunda ,ilgili Runnable object'i runOnUiThread() method'una verir. Bu runnable object, ui thread'in handler'ına post edilir, dolayısıyla ui thread'İn looper'ının event kuyruğuna eklenir. Sırası gelince kuyruktan çıkartılıp çalıştırılan bu Runnable iş, ui'ı değiştirir.
        runOnUiThread() method'u, UI thread'de çağırılırsa, main looper'ın kuyruğuna mesaj ekleme falan yapmaz , ilgili Runnable'ı anında çalıştırır. Yani bu sayede, bu method'u hangi thread'de çağırdığımızı check etmemize gerek kalmaz, ui thread'de de nonui thread'de çağırabiliriz bu method'u. Birisinde hemencecik çalıştırır diğerinde ise kuyruğa ekler.
Canceling a pending Runnable
        We can cancel a pending operation by removing a posted Runnable callback from the queue. ( Kuyruğa eklediğimiz bir Runnable iş gerçekleşmeden önce bu Runnable'ı iptal edebiliriz yani kuyruktan çıkartabiliriz. Ama bu Runnable iş çalışmaya başladıysa, çalışmanın ortasında bu işi iptal edemeyiz. )
final Runnable runnable = new Runnable(){
         public void run() {
                   // … do some work
         }
};

handler.postDelayed(runnable, TimeUnit.SECONDS.toMillis(10));
Button cancel = (Button) findViewById(R.id.cancel);

cancel.setOnClickListener(new OnClickListener(){
         public void onClick(View v) {
                   handler.removeCallbacks(runnable);
         }
});
        Notice that in order to be able to specify what to remove, we must keep a reference to the Runnable instance, and that cancellation applies only to pending tasks—it does not attempt to stop a Runnable that is already mid-execution. ( Kuyruktaki bir Runnable'I kuyruktan silmek, çalışmadan iptal etmek istiyorsak, bu Runnable object refer eden bir reference variable'a sahip olmak zorundayız. Yukarıdaki örnekte bir Runnable object yarattık, bu Runnnable object'e runnable isimli bir reference variable'ın refer etmesini sağladık. Sonra daha önceden yaratılmış olan handler object'İn postDelayed() method'unu çağırıp, runnable'ın 10 saniye sonra çağırılmasını istedik. Ancak 10 sn. geçmeden yani Runnable henüz çalışmadan, tanımladığımız butona tıklarsak handler object'in removeCallbacks(runnable) method'una argument olarak runnnable object'i verip çağırdık diyelim:
handler.removeCallbacks(runnable);
Bu durumda Runnable'In çalışması iptal edilir, kuyruktan silinir.  )
Scheduling work with send
        When we post a Runnable, we can—as seen in the previous examples—define the work at the call site with an anonymous Runnable. As such, the Handler does not know in advance what kind of work it might be asked to perform. ( Önceki örneklerde bir background thread'de main thread'İn handler'ına anonymous runnable object yaratıp post ettik handler.post(runnable,..) method'unu çağırarak. Handler ne çeşit bir iş yaptığını önceden bilmiyordu bu örneklerde. )
        If we often need to perform the same work from different call sites we could define a static or top-level Runnable class that we can instantiate from different call sites. ( Eğer handler'a sürekli olarak aynı işi göndereceksek, static bir Runnable class tanımlamalıyız. Farklı thread'lerde bu runnable class'dan bir object yaratıp handler'a post ederiz. tam anlamadım aslında bu paragrafı. )
        Alternatively, we can turn the approach on its head by sending Messages to a Handler, and defining the Handler to react appropriately to different Messages. ( Alternatif olarak, bir handler'a Runnable göndermek yerine Message göndeririz. Handler'ın gelen Mesajlara göre farklı davranmasını implement ederiz.  )
        Taking a simple example, let's say we want our Handler to display hello or goodbye, depending on what type of Message it receives. To do that, we'll extend Handler and override its handleMessage method. ( Aşağıdaki tanımladığımız Handler, aldığı Message'ın çeşidine göre(Message object'in what property'sine göre) ekranda hello veya goodbye gösterir. Message object'in what property'si 0 ise hello gösterir, 1 ise goodbye gösterir. Burada Handler class'ının handleMessage() method'unu override ettik, bu method'un aldığı Message object'e göre bir davranış gösterdik. )
public static class SpeakHandler extends Handler {
        public static final int SAY_HELLO = 0;
        public static final int SAY_BYE = 1;
        @Override
        public void handleMessage(Message msg) {
                switch(msg.what) {
                        case SAY_HELLO:
                               sayWord("hello"); break;
                        case SAY_BYE:
                               sayWord("goodbye"); break;
                        default:
                               super.handleMessage(msg);
                }
        }
        private void sayWord(String word) { … }
}
        You'll notice that we defined SpeakHandler class as a static class. Subclasses of Handler should always be declared as top-level or static classes to avoid inadvertent memory leaks! A top level class is a class that is not a nested class. A nested class is any class whose declaration occurs within the body of another class or interface. (SpeakHandler class'ını static olarak tanımladığımıza dikkat! Handler'ın subclass'ları top-level class olarak veya static class olarak tanımlanmalıdır. Top level class, nested olmayan class demektir. Nested class, bir class içerisinde tanımlanan class'a denir. Yani Bir nonstatic inner class olarak bir handler class tanımlamamalıyız sakın ha!! Ya nested olmayan bir class olarak ya da static bir class olarak tanımlamalıyız. Böylece yanlışlıkla bir memory leak gerçekleşmesini önlemiş oluruz.  )
        To attach an instance of our Handler to the main thread, we simply instantiate it from any method which runs on the main thread: ( Main thread'e bir handler bağlamak için, main thread'de çalışan bir method'da bir handler object yaratırız. )
private Handler handler;
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
     handler = new SpeakHandler();
// …
}
        Remember that we can send Messages to this Handler from any thread, and they will be processed by the main thread. We send Messages to our Handler as shown: ( Bu handler'a herhangi bir thread'den mesaj gönderebiliriz. Bu handler'a gönderilen mesajlar, main thread'de çalıştırılacaktır. Bu handler'a  handler'ın send() method'larından birini çağırarak bir mesaj gönderebiliriz, aşağıdaki  gibi:  )
handler.sendEmptyMessage(SAY_HELLO);
        Messages may also carry an object payload as context for the execution of the message. Let's extend our example to allow our Handler to say any word that the message sender wants: ( Handler'a gönderdiğimiz Message object, payload da içerebilir. Message object, obj isimli property'si, Message object'in içerdiği payload'a(object'e) refer eder. Az önce tanımladığımız SpeakHandler class'ını biraz daha geliştirelim. Bu örnekte farklı olarak, SpeakHandler class'ında SAY_WORD isimli bir int variable tanımlamıştır ve handleMessage() method'undaki switch statement'a yeni bir case eklenmiştir, bu case durumda message object'in içerdiği payload(object) elde edilip String'e çevrilip ekranda gösterilir.  )
public static class SpeakHandler extends Handler {
        public static final int SAY_HELLO = 0;
        public static final int SAY_BYE = 1;
        public static final int SAY_WORD = 2;
        @Override
        public void handleMessage(Message msg) {
                switch(msg.what) {
                        case SAY_HELLO:
                               sayWord("hello"); break;
                        case SAY_BYE:
                               sayWord("goodbye"); break;
                        case SAY_WORD:
                               sayWord((String)msg.obj); break;
                        default:
                               super.handleMessage(msg);
                }
        }
        private void sayWord(String word) { … }
}
        Within our handleMessage method, we can access the payload of the Message directly by accessing the public obj property. ( Yukarıdaki kodda, handleMessage(Message msg) method'unda, message object'in obj isimli public property'sine erişerek mesajın payload'una erişmiş oluruz.   )
        The Message payload can be set easily via alternative static obtain methods. ( Handler object'e göndereceğimiz Message object'i yaratma ve set etme ve gönderme işini aşağıdaki kod yapar. static obtain() method'larının varyasyonlarından birini çağırarak mesaja payload koyabiliriz aşağıdaki gibi.)
handler.sendMessage( Message.obtain(handler, SpeakHandler.SAY_WORD, "tada!"));
        While it should be quite clear what this code is doing, you might be wondering why we didn't create a new instance of Message by invoking its constructor, and instead invoked its static method obtain. ( Peki neden Message class'ından yeni bir object yaratmak için Message class'ının bir constructor'ını çağırmadık, bunun yerine static bir method olan obtain() method'unu çağırdık? )
        The reason is efficiency. Messages are used only briefly—we instantiate, dispatch, handle, and then discard them. So if we create new instances for each we are creating work for the garbage collector. ( Daha verimli bir kod yazmak için böyle yaptık. Çünkü Message object'ler çok küçük işler için kullanılırlar : yaratılırlar, gönderilirler, handle edilirler, çöp olurlar. Dolayısıyla contructor'ını kullanarak bir Message object yaratırsak ki bu mümkündür, garbage collector'un bunu temizlemesi gerekir. Garbage collector'a iş çıkartmış oluruz yani constructor'ı kullanırsak. )
        Garbage collection is expensive, and the Android platform goes out of its way to minimize object allocation whenever it can. While we can instantiate a new Message object if we wish, the recommended approach is to obtain one, which re-uses Message instances from a pool and cuts down on garbage collection overhead. ( Garbage collection pahalıdır, mümkün olduğunca object yaratma işini minimize etmek gereklidir dolayısıyla. Message() constructor'ı kullanarak da bir Message object yaratmak mümkün olmasına rağmen, tavsiye edilen yol değildir. obtain() method'unu kullandığımızda, bir havuzdaki varolan bir Message object tekrar tekrar kullanılabilecektir, yani sıfırdan bir object yaratmamış olacağız, bu sayede Garbage collector'i de ekstra bir zahmetten kurtarmış olacağız.  )
        Just as we can schedule Runnables with the variants of the post method, we can schedule Messages with variants of send. ( Runnable object'leri schedule etmek için gerekli post method'larını daha önce öğrenmiştik. Message object'leri schedule etmek için gerekli send method'larını ise aşağıdadır: )
handler.sendMessageAtFrontOfQueue(msg);
handler.sendMessageAtTime(msg, time);
handler.sendMessageDelayed(msg, delay);
        There are also empty-message variants for convenience, when we don't have a payload. ( Paylod'a sahip olmayan bir mesaj (Boş mesaj) göndermek için ise aşağıdaki method'ları çağırırız: )
handler.sendEmptyMessageAtTime(what, time);
handler.sendEmptyMessageDelayed(what, delay);
Canceling pending Messages
        Canceling sent Messages is also possible, and actually easier than canceling posted Runnables because we don't have to keep a reference to the Messages that we might want to cancel—instead we can just cancel Messages by their what value. ( Daha önce post edilmiş olan Runnable'ları iptal etmeyi öğrenmiştik, Runnable object'e refer eden reference variable'ı tutmamız gerekiyordu bunun için. Daha önce send edilmiş olan Message'ları iptal etmek de mümkündür, hatta daha kolaydır, çünkü Message object'e refer eden reference variable'ı tutmaya gerek yoktur, Message object'in sadece what değerini söyleyerek bir Mesajı iptal edebiliriz aşağıdaki gibi:  )
handler.removeMessages(SpeakHandler.SAY_WORD);
        Note that just as with posted Runnables, Message cancellation only removes pending operations from the queue—it does not attempt to stop an operation which is already being executed. ( Runnable object'leri iptal etmek konusunda da söylemiştik tekrar söyleyelim, Message iptali sadece bekleyen(pending) Message'ları kuyruktan silmeyi sağlar. Çalıştırılmakta olan bir Message'ı durdurmaya çalışmaz. )
Composition versus Inheritance
Bu konuyu tam anlamasam da açıklamaya çalıştım.
        Önce Handler.Callback nested interface'ini implement eden Speaker isimli bir class tanımladık. 
        Sonra aynı işi yapmak için 2 class tanımladık: Handler'ı extend eden SpeakHandler isimli bir class ve Handler.Callback nested interface'ini implement eden Speaker isimli bir class.
        Önceki yazdığımız class bizim işimizi görüyordu, neden aynı işi 2 class'a paylaştırıp yazdık anlamadım. Emin değilim ama nedeni şu olabilir : 1. class'da default durumda handleMessage() method'u sadece false return ediyor, halbuki biz Handle class'ının kendi handleMessage() method'unu çağırmak isityoruz default durumda bunu da ancak Handler class'ının bir subclass'ında yaparız. Dolayısıyla işin yapabildiğimiz kısmını Callback class'ında yapıyoruz böylece composition'dan istifade etmiş oluyoruz çünkü composition inheritance'dan daha verimlidir diye genel bir görüş vardır.İşin kalan kısmını ise inheritance ile yapıyoruz.

Nested classes

interface
Callback interface you can use when instantiating a Handler to avoid having to
implement your own subclass of Handler. 
Handler.Callback       : Callback interface you can use when instantiating a Handler to avoid having to implement your own subclass of Handler.( Handler class'ının bir subclass'ını implement etmek yerine callback isimli bu interface'i kullanabiliriz. )
        So far we subclassed Handler to override its handleMessage method, but that isn't our only option. We can prefer composition over inheritance by passing an instance of Handler.Callback during Handler construction. ( Şimdiye kadarki örneklerde, handleMessage() method'unu override etmek için Handler class'ını extend ettik yani inheritance kullandık. Ancak bu bizim tek seçeneğimiz değildir, başka bir seçeneğimiz daha vardır o da composition'dır. Handler class'ı, Callback isimli bir nested class içerir. Handler.Callback class'ı yani Handler class'Inın içerisindeki Callback isimli nested class handleMessage() abstract method'unu içerir. Yani Handler.Callback class'ını implement eden bir class tanımlarsak, handleMessage() method'unu override etmek zorundayız. Yani aslında Callback class'ı bir interface'dir, bir abstract class'dır. Aşağıdaki örnekte Speaker isimli bir static class Handler.Callback interface'ini implement eder, 3 tane int variable tanımlar, handleMessage() method'unu override eder. handleMessage() method'unun aldığı Message object'in what property'sinin değerine göre ekranda hello, goodbye, veya message object ile gönderilen payload'u gösterir. Handler class'ındaki handleMessage() method'u void return eder,  Handler.Callback class'ındaki handleMessage() method'u ise boolean return eder. Yukarıda Handler class'ını extend eden bir class tanımlamıştık o class ve aşağıdaki class'ı tanımı arasında 2 fark vardır aşağıdaki Handler.Callback'i implement eder ve handleMessage() boolean return eder. Yukarıdaki class'dan bir Handler object şöyle yaratabiliyorduk :
SpeakHandler s = new  SpeakHandler();
Aşağıdaki class'dan ise bir Handler object şöyle yaratabiliriz :
Handler handler = new Handler(new Speaker());    )

public static class Speaker implements Handler.Callback {
        public static final int SAY_HELLO = 0;
        public static final int SAY_BYE = 1;
        public static final int SAY_WORD = 2;
        @Override
        public boolean handleMessage(Message msg) {
                switch(msg.what) {
                        case SAY_HELLO:
                               sayWord("hello"); break;
                        case SAY_BYE:
                               sayWord("goodbye"); break;
                        case SAY_WORD:
                               sayWord((String)msg.obj); break;
                        default:
                               return false;
                }
                return true;
        }
        private void sayWord(String word) { … }
}
        Notice that the signature of handleMessage is slightly different here—we must return a boolean indicating whether or not the Message was handled. To create a Handler that uses our Callback, simply pass the Callback during Handler construction. (handleMessage() method'u boolean return eder, bu değer Message'ın handle edilip edilmediğini gösteri, yani ekranda bir yazı gösterileceği durumlarda bu method true return eder. Yukarıda tanımladığımız callback class'ını kullanan bir Handler yaratmak için Handler class'ının constructor'ına, Callback isimli class'dan yarattığmız object'i veririz, aşağıdaki koddaki gibi. )
Handler handler = new Handler(new Speaker());

        If we return false from the handleMessage method of our Callback, the Handler will invoke its own handleMessage method, so we could choose to use a combination of inheritance and composition to implement default behavior in a Handler subclass, and mix in special behavior by passing in an instance of Handler.Callback. ( Callback class'ının handleMessage() method'u false return ederse, Handler kendi handleMessage() method'unu çağıracaktır. Dolayısıyla inheritance ve composition'ın kombinasyonunu kullanabiliriz; default behaviour'ı yani handler'ın kendi handleMessage() method'unu çağırması durumunu Handler'ın subclass'ında implement ederiz, özel durumları yani message object'in what değeri şöyle gelirse şöyle yap gibi durumları ise Handler.Callback class'ında yapıp bu class'ın bir instance'ını Handler subclass'ının constructor'ına veririz. Handler subclass'ının constructor'ı argument olarak Callback object alıp super(callback) 'i çağırır.   )
public static class SpeakHandler extends Handler
{
        public static final int SAY_HELLO = 0;
        public static final int SAY_BYE = 1;
        public SpeakHandler(Callback callback) {
                super(callback);
        }
        @Override
        public void handleMessage(Message msg) {
                switch(msg.what) {
                        case SAY_HELLO:
                               sayWord("hello"); break;
                        case SAY_BYE:
                               sayWord("goodbye"); break;
                        default:
                               super.handleMessage(msg);
                }
        }
        private void sayWord(String word) { … }
}

public static class Speaker implements Handler.Callback {
        public static final int SAY_WORD = 2;
        @Override
        public boolean handleMessage(Message msg) {
                if (msg.what == SAY_WORD) {
                        sayWord((String)msg.obj);
                        return true;
                }
                return false;
        }
        private void sayWord(String word) { … }
}
        SpeakHandler isimli Handler subclass'ından aşağıdaki gibi bir object yaratırız. Sonra bu Handler'a bir message object yaratıp göndeririz.
Handler h = new SpeakHandler(new Speaker());
h.sendMessage(Message.obtain(handler, Speaker.SAY_WORD, "!?"));
        With SpeakHandler set up like this, we can easily send Messages from any thread to update the user interface. Sending from a background thread or the main thread itself is exactly the same—just obtain a Message and send it via SpeakHandler. ( SpeakHandler class'ını bu şekilde tanımladıktan sonra, herhangi bir thread'den bu handler'a message göndererek ui'ı güncelleyebiliriz. Background thread'den veya main thread'den göndermek aynıdır : bir message object elde edilip SpeakHandler'a gönderilir. )
Multithreaded example
        Let's extend our example to bind the app to a network socket and echo lines of text it receives from the socket to the screen. Listening for lines of text from the network socket is a blocking operation, so we must not do it from the main thread. (Yukarıdaki örneğimizi biraz daha geliştirelim. Aşağıda bir Thread class'ı tanımladık. Thread'de bir server çalıştıralım ve client server'a bir text gönderince bunu ekrana yazdıralım.Bir network socket'den text dinlemek(text gelmesini beklemek) blocking operation'dır, dolayısıyla bunu main thread'de yapmamalıyız. )
        We'll start a background thread, then bind the server socket and wait for a client to connect over the network. When this background thread receives text from the socket, it will send it in a Message to the SpeakHandler instance, which will update the user interface on the main thread. ( Arka planda bir thread başlatacağız, bunun için aşağıda bir class tanımladık bu class'dan bir object yaratılıp bu object'in start() method'u çağırılmalıdır. Bu class'da,  server socket'i 4444.port'a bind ettik(bağladık), client'ın bu server'a bağlanmasını bekledik. Bu background thread, socket'den bir text alınca, bu text'i bir Message object içerisinde, SpeakHandler isimli Handler object'e gönderir. Bu handler da main thread'deki ui'ı günceller.  )
static class Parrot extends Thread {
        private Handler handler;
        private InetAddress address;
        private ServerSocket server;
        public Parrot(InetAddress address, Handler handler)
        {
                this.handler = handler;
                this.address = address;
                setPriority(Thread.MIN_PRIORITY);
        }
        public void run() {
                try {
                        server = new ServerSocket(4444, 1, address);
                        while (true) {
                               Socket client = server.accept();
                                handler.sendMessage(
Message.obtain(handler, SpeakHandler.SAY_HELLO) );
                               BufferedReader in = new BufferedReader( new InputStreamReader( client.getInputStream()));
                               String word;
                               while (!"bye".equals(word = in.readLine())) {
                                       handler.sendMessage( Message.obtain(handler, SpeakHandler.SAY_WORD, word));
                               }
                               client.close();
                               handler.sendMessage(
                        Message.obtain(handler,SpeakHandler.SAY_BYE));
                        }
                } catch (Exception exc) {
                Log.e(TAG, exc.getMessage(), exc);
                }
        }
        Yukarıda tanımladığımız Thread class'ında 3 tane variable tanımladık:
        private Handler handler;
        private InetAddress address;
        private ServerSocket server;
        Thread class'ımızın constructor'ında bu variable'lardan ikisini set ettik. Yani thread class'ından bir object yaratılırken constructor'a handler ve InetAddress object verilmek zorundadır.
public Parrot(InetAddress address, Handler handler)
        {
                this.handler = handler;
                this.address = address;
                setPriority(Thread.MIN_PRIORITY);
        }
        Let's have a quick look at the key elements of the run method. First, we bind a socket to port 4444 (any port higher than 1024 will do) on the given address, which allows us to listen for incoming connections. The second parameter says we're only allowing one connection at a time: (Thread class'ımızın run() method'una bakalım.3. argument'deki adresin 4444.port'una bir socket bind ederiz. Böylece bu adresin 4444. portunda bağlantı kurulmasını bekleriz. ServerSocket constructor'ının aldığı 2.parametre, aynı anda kaç tane client'ın server'a bağlanabileceğini belirtir. )
server = new ServerSocket(4444, 1, address);
        We loop forever, or until an exception is thrown. Inside the loop we wait for a client to connect: (while(true) döngüsü sonsuza kadar çalışır, tabi bir exception olmadığı sürece. Döngü içerisinde bir client'ın server'a bağlanmasını bekleriz server.accept() ile. )
Socket client = server.accept();
        The accept method blocks, so our background thread is suspended until a client makes a connection. As soon as a client connects, we send a SAY_HELLO message to our Handler, so the main thread will update the user interface for us: ( accept method'u blocking bir operation'dır, return edene kadar kod bu satırda bekler, yani runtime bu kod bu satırda client bağlanana kadar bekler. Dolayısıyla bu thread bir client bağlanana kadar bu satırda bekler. Bir client bağlanınca Handler'a SAY_HELLO mesajı gönderilerek main thread'in ui'ı güncellemesi sağlanır.  )
handler.sendMessage( Message.obtain(handler, SpeakHandler.SAY_HELLO));
        Next, we wrap a buffering reader around our socket's input stream, and loop on its readLine method, which blocks until a line of text is available. ( Bağlanan client'dan bir text gelene kadar aşağıdaki satırda bekleriz, client bir text gönderince bu text okunur, "bye" değilse  aşağıdaki while döngüsünde kalır. )
BufferedReader in = new BufferedReader( new InputStreamReader( client.getInputStream()));
String word;
while (!"bye".equals(word = in.readLine()))
{
        When we receive some text from the socket, we send it in a Message to our Handler. ( client'dan gelen text okunup word isimli variable'a koyuldu, bu text, handler'a gönderilir. )
handler.sendMessage( Message.obtain(handler, SpeakHandler.SAY_WORD, word));
        If we receive bye, we'll break out of the loop, disconnect this client, and say goodbye: ( client'dan gelen text "bye" ise, loop'dan çıkılır, client ile bağlantı koparılır, handler'a SpeakHandler.SAY_BYE tipinde birMessage object gönderilir. Message.obtain() method'unun aldığı 2. parametre, Message object'in what variable'ını set eder, 3.parametre ise Message object'in içerdiği obj isimli object'i set eder. )
client.close();
handler.sendMessage( Message.obtain(handler, SpeakHandler.SAY_BYE));
        To obtain the address of the device, we can use the Wi-Fi service. We'll need to convert the value we get from the Wi-Fi service to an instance of the InetAddress class, elided here for brevity. ( anlamadım şu an için önemli değil zaten. )
private InetAddress getAddress()
{
   WifiManager wm = (WifiManager)getSystemService(WIFI_SERVICE);
   return asInetAddress(wm.getConnectionInfo().getIpAddress());
}
        Binding the socket and using the Wi-Fi service requires permissions to be requested in the Android manifest: ( Socket'i bind etmek ve WIFI service'i kullanmak için aşağıdaki izinleri almak gerekir. )
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
        Finally we need to create and start Parrot in a suitable Activity lifecycle method, for example, onResume. To make it easy to connect, we'll display the address and port on the screen. ( Parrot'ı Activity yaşam döngüsündeki uygun bir method içerisinde yaratmalı ve başlatmalıyız, örneğin onResume() method'unda yapabiliriz bunu. parrot daha önce yaratılmış mı diye check ederiz, yaratılmamışsa, önce getAddress() metod'unu çağırarak cihazımızın bağlı olduğu internetin ip adresini elde ederiz. Sonra Parrot constructor'a bu adresi ve handler object'i vererek Parrot isimli thread class'dan bir object yaratırız, sonra bu thread'i başlatırız start() method'unu çağırarak. Sonra ekrndaki textviewde ip adresini ve portu gösteririz. )
TextView view = (TextView) findViewById(R.id.speak);
if (parrot == null) {
        InetAddress address = getAddress();
        parrot = new Parrot(address, handler);
        parrot.start();
        view.setText("telnet " + address.getHostAddress() + " 4444");
}
        We should also remove pending messages in onPause, and disconnect the socket if the Activity is finishing—the complete code is available for download from the accompanying website. ( Pending mesajları onPause() method'unda silebiliriz, activity yok edilirken socket'le bağlantıyı koparabiliriz. Bu kodun source kodunun tamamı linkteki ch3. ex3 bölümünde mevcuttur : https://github.com/steveliles/AsyncAndroid  )
        When the app starts, you'll see a message on the device screen like telnet 192.168.0.4 4444. To connect and send messages to your device's screen, open the command prompt on your development computer and copy the text from your device screen to the command prompt. ( Uygulama başlatıldığnda ekranda şunu göreceğiz : telnet 192.168.0.4 4444 Uygulamaya mesaj gönderip bu mesajın ekranda gözükmesi için, komut satırı açalım, şu komutu girelim: telnet 192.168.0.4 4444 )
You should see the following output: ( Komut satırında aşağıdaki output'u görürüz, bilgisayarımız'dan telefona bağlandık demektir bu. )
Trying 192.168.0.4...
Connected to 192.168.0.4.
Escape character is '^]'.
        Congratulations! You're connected. Enter some words in the command prompt and they'll appear on your device screen. Enter bye to disconnect. ( Komut satırına bir şeyler yazıp enter'a basınca telefonun ekranında bu yazı gösterilecektir. Bağlantıyı koparmak için bye yazmalısınız. )
Sending Messages versus posting Runnables
        It is worth spending a few moments to consider the difference between posting Runnables and sending Messages. ( Handler'a Runnable post edebiliriz veya Message send edebiliriz demiştik. Peki bu ikisi arasındaki fark nedir? )
        The runtime difference mostly comes down to efficiency. Creating new instances of Runnable each time we want our Handler to do something adds garbage collection overhead, while sending messages re-uses Message instances, which are sourced from an application-wide pool. ( Runtime'da verimlilik açısından fark vardır. Handler'a vermek için Runnable instance yaratırsak, garbage collection'a iş çıkartmış oluruz. Message göndermeyi seçersek, Message object'ler tekrar tekrar kullanılacağı için yeni object yaratılmaz dolayısıyla garbage collection'a ekstra iş çıkmaz,. Bu yüzden Message kullanmak daha verimlidir. )
        The difference at development time is between allowing code at the call site to specify arbitrary work for the Handler to do (Runnable.run) potentially spreading similar code throughout the codebase, versus the Handler defining the work it is prepared to do in a single place (Handler.handleMessage). ( Geliştirme süreleri farklıdır. Handler'ın bağlı olduğu thread'de yapılacak bir iş belirtmek istediğimiz Runnable yazarız. Veya Handler'a bir mesaj gönderip bu mesaj ile ne yapılacağına Handler'ın handleMessage() method'unda karar veririz. )
        For prototyping and small one-offs, posting Runnables is quick and easy, while the advantages of sending Messages tend to grow with the size of the application. It should be said that Message sending is more "The Android Way", and is used throughout the platform to keep garbage to a minimum and apps running smoothly. ( Küçük ve tek seferlik işler için Runnable'ı kullanmak hızlı ve kolay sonuç verir. Ancak uygulamanın size'ı büyüdükçe Message send etmenin avantajları artar. Message kullanmak Android için daha uygundur, ekstra çöp çıkartmadığı için uygulamalar daha hızlı çalışır.)
Building responsive apps with HandlerThread
        So far we only really considered Handler as a way to request work be performed on the main thread—we've submitted work from the main thread to itself, and from a background thread to the main thread. ( Şimdiye kadarki gördüğümüz örneklerde, arka planda çalışan thread'ler main thread'e iş gönderiyordu veya main thread'de çalışan thread'ler main thread'e iş gönderiyordu. Handler main thread'de yaratılıyordu dolayısıyla handler main thread'e iş göndermek için kullanılıyordu. )
        In fact we can bind Handlers to any thread we create, and in doing so allow any thread to submit work for another thread to execute. For example, we can submit work from the main thread to a background thread or from one background thread to another. ( Aslında Handler'ı sadece main thread ile değil başka thread'ler ile de ilişkilendirebiliriz, diğer bir deyişle bir handler'ı bir background thread'e bağlayabiliriz, bu handler'ı kullanarak bu background thread'e diğer thread'ler iş gönderebilir. Örneğin, bir background thread'den bir main thread 'e iş gönderebiliriz, Bir main thread'den bir background thread'e iş gönderebiliriz, bir background thread'den başka bir background thread'e iş gönderebiliriz. )
        We saw one way of setting up a Looper thread with a Handler in the Understanding Looper section earlier in this chapter, but there's an easier way using a class provided by the SDK for exactly this purpose, android.os.HandlerThread. ( Yukarıdaki Understanding Looper başlığı altında, bir thread'in içerisinde Looper yaratmayı öğrenmiştik. Ancak bunun daha kolay bir yolu vardır, o da Android SDK'nın bize sağladığı android.os.HandlerThread class'ını kullanmaktır. Normal bir thread'in default olarak bir looper'ı yoktur, istersek kendimiz bir looper tanımlamalıyız normal bir thread için. Ancak bir HandlerThread'in default olarak bir looper'ı vardır doğru anladıysam. )
        When we create a HandlerThread, we specify two things: a name for the thread, which can be helpful when debugging; and its priority, which must be selected from the set of static values in the android.os.Process class. (HandlerThread class'ından bir object yaratırken, constructor 2 parametre vererek şu 2 şeyi belirtiriz:
- 1.parametre ile thread'e isim veririz. Debugging yaparken işe yarar bu, log'lardan thread'i ismiyle takip ederiz.
- 2. parametre Thread'in priority'sini(önceliğini) belirler. android.os.Process class'ındaki static değerlerden birisi argument olarak verilir. )
HandlerThread thread =
new HandlerThread("bg", Process.THREAD_PRIORITY_BACKGROUND);
        Adding THREAD_PRIORITY_MORE_FAVORABLE to THREAD_PRIORITY_BACKGROUND when configuring your HandlerThread moves the thread into the default cgroup, but always consider whether it is really necessary—it often isn't! ( Genellikle, thread'in priority'sini Process.THREAD_PRIORITY_BACKGROUND olarak set etmek gerekir. İstersek THREAD_PRIORITY_MORE_FAVORABLE olarak da set edebiliriz, ancak bunun gerçekten gerekli olduğundan eminseniz yapın bunu, genellikle bu priority'ye ihtiyaç yoktur.  )
        HandlerThread extends java.lang.Thread, and we must start() it before it will actually begin processing its queue: ( HandlerThread, java.lang.Thread class'ını extend eder. HandlerThread'in, kuyruğundaki işleri işlemeye başlaması için start() method'unu çağırmalıyız. )
thread.start();
        Now we need a Handler through which we can pass work to our HandlerThread. So we create a new instance, but this time we parameterize the constructor with the Looper associated with our HandlerThread. ( HandlerThread'e diğer thread'lerin iş gönderebilmesi için bir Handler'a ihtiyacımız vardır. Dolayısıyla bir Handler object yaratırız, ancak bu sefer Handler object'i yaratırken öncekilerden farklı olarak şunu yaparız : Handler'ın constructor'ına argument olarak HandlerThread ile ilişkili Looper'ı veririz. HandlerThread ile ilişkili olan Looper'ı elde etmek için, HandlerThread object'in getLooper() method'unu çağırırız. )
Handler handler = new Handler(thread.getLooper());
        That's all there is to it—we can now post Runnables for our HandlerThread to execute: ( İşte bu kadar !! Bu iş bitti!! Artık HandlerThread'imize iş gönderebiliriz bu handler object'in post() veya send() method'larını kullanarak.   )
handler.post(new Runnable(){
public void run() {
// ... do some work in the background thread
}
});
        To send Messages to our HandlerThread, we'll need to override handleMessage or provide a Callback via the alternate Handler constructor: (handler object'in send() method'unu çağırarak handler object'in ilişkili olduğu HandlerThread'e Message object gönderebiliriz. Bu durumda Handler class'ını extend eden bir subclass tanımlayıp bu class'da handleMessage() method'unu implement etmeliyiz. Veya Handler.Callback class'ından anonymously bir object yaratmalıyız, bu class'da handleMessage() method'unu da implement ederiz, sonra bu object'i Handler constructor'ına 2.argument olarak veririz; Handler constructor'ına 1. argument olarak HandlerThread ile ilişkili olan looper'ı veririz. )
Handler.Callback callback = new Handler.Callback(){ … };
Handler handler = new Handler(thread.getLooper(), callback);
        If we create a HandlerThread to do background work for a specific Activity, we will want to tie the HandlerThread's lifecycle closely to that of the Activity to prevent resource leaks. ( Eğer belirli bir activity için arka planda çalışacak bir HandlerThread yaratırsak, HandlerThread'in yaşam döngüsü method'ları ve Activity'nin yaşam döngüsü method'larını senkronize çalışacak şekilde ayarlamalıyız, mesela activity başlatılırken handlerThread'i başlatmalı activity yok edilirken handlerthread'in resource'larını free etmeliyiz, böylece resource leak olmasını önleriz. )
        A HandlerThread can be shut down by invoking quit, which will stop the HandlerThread from processing any more work from its queue. A quitSafely method was added at API level 18, which causes the HandlerThread to process all remaining tasks before shutting down. Once a HandlerThread has been told to shut down, it will not accept any further tasks. ( quit() method'unu çağırarak bir HandlerThread'i durdurabiliriz, böylece HandlerThread kuyruğundaki işleri çalıştırmayı durdurur. quitSafely() method'unu çağırarak bir HandlerThread'i durdurabiliriz, böylece HandlerThread kuyruğunda kalan işleri bu işler bitene kadar çalıştırır ama kuyruğuna yeni bir iş almaz, sonra thread durur. Bir HandlerThread'i kapatılmasını söylersek bu HandlerThread artık kuyruğuna çalıştırılacak yeni bir task almaz.  )
        Just as we did in the previous chapter with AsyncTask, we can use the Activity lifecycle methods to determine when we should quit the HandlerThread. ( AsyncTask'ı anlatan chapter'da da anlatıldığı gibi,activity yaratılırken, Handler object yaratırız, activity pause edilirse thread'in quit() method'unu çağırarak thread'i durdururuz. )
private HandlerThread thread;

protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       thread = new HandlerThread( … );
}

protected void onPause() {
       super.onPause();
       if ((thread != null) && (isFinishing()))
             thread.quit();
}
Handler programming issues
        The Handler class is truly fundamental to the Android platform and is used widely throughout, but there are plenty of ways we can get ourselves into trouble if we aren't careful.( Handler class'ı, Android platformunun temel yapıtaşlarından biridir ve gerçekten çok önemlidir. Ancak Handler kullanırken çok dikkatli olmalıyız, özellikle aşağıda konularda dikkatli olmalıyız aksi takdirde kendimizi sıkıntıya sokabiliriz. )
Leaking implicit references
        The biggest worry when using Handler within an Activity is resource leakage which, just as with AsyncTask, is very easy to do. Here's one of our earlier examples: ( Bir activity içerisinde handler kullanırken yaşayabileceğimiz en büyük endişe resource leakage'dır. Çok kolay bir şekilde resource leakage 'a neden olabilecek bir yanlış yapabiliriz. Önceki örneklerimizden birine şimdi daha yakından bakalım : )
final Runnable runnable = new Runnable(){
        public void run() {
                // … do some work
        }
};
handler.postDelayed(runnable, TimeUnit.SECONDS.toMillis(10));
        By declaring an anonymous inner Runnable inside an activity, we have made an implicit reference to that containing Activity instance. We've then posted the Runnable to a handler and told it to execute in 10 seconds time. ( Bir activity'nin içerisinde, bir anonymous inner Runnable object tanımlarsak, Activity instance'e implicit bir reference yapmış oluruz. )
        If the Activity finishes before the 10 seconds are up, it cannot yet be garbage collected because the implicit reference in our Runnable means that the Activity is still reachable by live objects.  ( Activity 10 saniye geçmeden biterse, activity garbage collector tarafından temizlenemez çünkü Runnable object'deki implicit reference activity'nin hala erişilebilir olduğunu söyler. )
        So, although it makes for a concise example, it is not a good idea in practice to post non-static Runnables onto the main thread's Handler queue (especially with postDelayed or postAtTime) unless we're very careful to clean up after ourselves. ( Bu örnekteki gibi, main thread'in Handler'ına nonstatic bir Runnable object post etmek iyi bir fikir değildir, özellikle postDelayed() ve postAtTime() method'larıyla birlikte nonstatic bir Runnable object post etmek çok çok kötü bir fikirdir. Bu kötü bir fikir olmasına rağmen bunu gene de yapacaksak, arta kalanları çok iyi temizlememiz çok dikkatli olmamız gerekir. )
        One way to minimize this problem is to avoid using non-static inner classes; for example, by always declaring Runnables as top-level classes in their own file, or as static classes in an Activity subclass. This means that references must be explicit, which makes them easier to spot and nullify. ( Bu problemi minimize etmek için, nonstatic inner class'lar kullanmaktan kaçınmalıyız. Örneğin Runnable'ları top-level class olarak ayrı bir dosyada tanımlamalıyız veya Activity class'ın içerisinde static inner class olarak tanımlamalıyız. Böylece bu Runnable object'lerin garbage collector tarafından bulunup temizlenmesi daha kolay hale gelir. )
        In addition, we can cancel pending tasks during Activity lifecycle callbacks such as onPause. This is easiest if we're working with Messages since we can remove them by their what value, and don't have to keep references as we would with Runnables. ( Ayrıca, activity'nin onPause() method'u çağırıldığında kuyrukta bekleyen task'ları iptal edebiliriz. Eğer Message object'ler ile çalışıyorsak bunu yapmak çok kolay olacaktır, çünkü what değerini kullanarak Message object'leri silebiliriz, Runnable'larda olduğu gibi Message object'e reference'ı tutmamıza gerek yoktur. )
        For HandlerThread instances we've created, we should make sure to quit when the Activity is finishing, which will prevent further execution and free up the Runnable and Message objects for garbage collection. (Activity bittiğinde, HandlerThread object'lerin quit() method'larını çağırarak durdurduğumuzdan emin olmalıyız. Bu sayede kuyruğa yeni iş gelmesini önleriz, Runnable ve Message object'leri free etmiş oluruz. )
Leaking explicit references
        If we are to interact with the user interface, we'll at least need a reference to an object in the View hierarchy, which we might pass into our static or top-level Runnable's constructor. ( User interface ile etkileşim içerisindeysek  bir view object'e refer eden bir reference variable'a ihtiyacımız olabilir, bu reference variable'ı static veya top-level olan Runnable class'ımızın constructor'ına parametre olarak verebiliriz aşağıdaki gibi, artık Runnable'ımızda view object'e refer eden reference variable'a sahibizdir. )
static class MyRunnable implements Runnable {
        private View view;
        public MyRunnable(View view) {
                this.view = view;
        }
        public void run() {
                // … do something with the view.
        }
}
        However, by keeping a strong reference to the View, we are again subject to potential memory leaks if our Runnable outlives the View; for example, if some other part of our code removes this View from the display before our Runnable executes. ( Yukarıdaki kodda, View object'e refer eden bir strong reference variable tutarız Runnable class'ında. Eğer Runnable'ımız View'den daha üzün süre yaşarsa, strong reference variable'dan dolayı muhtemel memory leak sorunuyla karşılaşabiliriz. Örneğin, kodumuzun başka bir yerinde Runnable çalışmadan ilgili view'i ekrandan siliyor olabiliriz. Bu durumda Runnable içerisindeki strong reference variable olmayan bir view object refer eder patlarız yani.  )
        One solution to this is to use a weak reference, and check for null before using the referenced View. ( Bu problemi çözmenin bir yolu weak reference kullanmak ve refer edilen View'i kullanmadan önce null olup olmadığını check etmektir. Aşağıdaki kodu inceleyelim, yukarıdaki Runnable'dan farklı olarak şunları yaptık: reference variable'ların View olan type'larını WeakReference<View> yaptık. run() metod'unda view object'in get() method'unu çağırdık, bu method null değilse view ile ilgili işlem yapabiliriz, null ise View object çöpe atılmıştır. )
static class MyRunnable implements Runnable
{
        private WeakReference<View> view;
        public MyRunnable(View view)
        {
                this.view = new WeakReference<View>(view);
        }
        public void run()
        {
                View v = view.get(); // might return null
                if (v != null) {
                        // … do something with the view.
                }
        }
}
        If you haven't used WeakReference before, what it gives us is a way to refer to an object only for as long as some other live object has a stronger reference to it (for example, a "normal" property reference). (WeakReference bize şunu sağlar: WeakReference variable bir view object'e refer etmesi için şu şart gerekir: yaşayan bir object'in sahip olduğu bir stronger reference variable, bu view object'e refer ediyor olmalı. )
        When all strong references are garbage collected, our WeakReference will also lose its reference to the View, get() will return null, and the View will be garbage collected.  ( Tüm strong reference'lar garbage collector tarafından temizlenince, bizim WeakReference'ımız da View'e reference'ını kaybeder. get() method'u null return eder. Ve view object garbage collector tarafından temizlenir.  )
        This fixes the resource leakage problem, but we must always check for null before using the returned object, to avoid potential NullPointerException's.
        If we're sending Messages to our Handler and expecting it to update the user interface, it will also need a reference to the View hierarchy. A nice way to manage this is to attach and detach the Handler from onResume and onPause. ( Eğer Handler'ımıza Message object gönderip, user interface'i güncellemek istiyorsak, Handler'ımızda ilgili View object'e refer eden bir reference variable'a sahip olmalıyız. Bunun için Handler class'ımızda 2 tane mothod tanımlayalım, bu method'lara 2 tane rastgele isim verelim: attach() ve detach(). Activity'nin onResume() method'u çağırıldığında attach(view method'u çağırılarak handler'a view'e refer eden reference variable'ı verelim. detach() method'u çağırıldığında ise Handler'ın içerdiği view isimli reference variable'ı null olarak set edelim. handleMessage() method'unu view variable'ı istediğimiz şekilde set edebiliriz. )
private static class MyHandler extends Handler
{
        private TextView view;
        public void attach(TextView view)
        {
                this.view = view;
        }
        public void detach()
        {
                view = null;
        }
        @Override
        public void handleMessage(Message msg)
        {
                //…
        }
}
Applications of Handler and HandlerThread
        The Handler class is incredibly versatile, which makes its range of applications very broad.  (Handler class'ı çok kullanışlıdır, beceriklidir bir çok uygulamada kullanılır. )
        The Android platform also uses Handler extensively as a mechanism for abstracting the work that needs doing from the thread that will do it. A nice example of this can be found in android.hardware. SensorManager, which allows listeners to be registered along with a Handler so that we can easily handle sensor data in a separate HandlerThread. You'll find an example of processing sensor data in the background, using the magnetic field sensor and the accelerometer in combination to create a simple compass.  ( Bu bölümün başında verdiğimiz github linkinde tekrar verelim hatta : https://github.com/steveliles/AsyncAndroid bu linkte chapter 3 örnek 5 'de SensorManager örneği implement edilmiştir. Handler thread'de yapılacak işi abstract etmek için kullanılmıştır, ne demek istediğini ben de anlamadım. Bu örnekte, listener'lar Handler'a register olurlar böylece ayrı bir HandlerThread'de sensor verileri handle edilir. Magnetic field sensor ve accelerometer kullanılarak basit bir compass yaratılmıştır bu örnekte.  )
Summary
        In this chapter we used Handler to queue work for the main thread to process, as a means of maintaining responsiveness in a single-threaded application. ( Main thread'İn iş kuyruğuna iş göndermek için Handler kullandık. )
        We saw the different ways we can define work with Handler—arbitrary work defined at the call site with Runnable, or predefined work implemented in the Handler itself and triggered by message sending. ( Handler ile çalışmanın 2 farklı yolu olduğunu öğrendik. Birincisi, Runnable object tanımlanır, Handler'a Runnable object gönderilir, sırası gelince bu Runnable object çalışır. İkincisi, Handler'da handleMessage() method'unu tanımlarız, bu method'da Handler'a bir Message object gelince ne yapılacağını belirleriz.)
        We learned how to use Handler in a multithreaded application to pass work and results back and forth between cooperating threads, performing blocking operations on an ordinary background thread, and communicating the results back to the main thread to update the user interface. (  )
        We also met HandlerThread and used it to create a background thread with its own Looper, allowing us to use these same techniques to queue work for background processing. ( HandlerThread'i öğrendik, HandlerThread kendisine ait looper'I olan bir background thread'dir. Bu thread'e verdiğimiz işler arka plandaki bir thread'de çalışır. )
        This isn't the last we'll see of Handler and HandlerThread—they can also be usefully put to work in other contexts, as we'll discover in Chapter 5, Queuing Work with IntentService and Chapter 6, Long-running Tasks with Service. ( Handler ve HandlerThread konularına IntentService ve Service konularında da değineceğiz. )
-*-*-
        A Looper is an Object associated with the Thread from which it is created. As you can guess by it's name a Looper is going to loop over something, but looping over what ? Over a message queue also associated with the same thread.
        Next question is: How can I put something in this message queue ? By using Handler.

        The Handler can play 2 roles (and that's maybe why it is confusing)
         First role of the Handler : you must use it to post messages to it's associated Looper (in fact to its message queue). You can use one of the various Handler.sendMessage* (or Handler.post*) methods to do that. (and note the sendMessageDelayed/postDelayed methods allowing you to post a Message/Runnable to be handled in future)
        What is the Looper associated with a Handler ? Very easy : the Looper of the current Thread if you don't specify it manually; but you can use the constructor with a Looper : new Handler(Looper looper) and in this case the handler is associated with looper in argument.
At this point, we know that :
- a Looper is associated with one and only one Thread.
- a Looper loops over it's associated message queue
- as a consequence : there is one message queue associated with one Thread (as soon as we have a Looper for the Thread)
- a Handler is always associated with one Looper
- a Handler can be used to post message to the message queue

        Now, let's see the second part : the message processing/message handling.
        First, let's look at the Looper looping over it's message queue.
        Is there is a message in the queue ? Yes (i.e. at some point, a Handler has posted it.) Is it time to handle this message (if it was posted with postDelayed) ? If not, wait a little. If it is time : let's dispatch this message.
        Remember that I told that the Handler have 2 roles... and here is the second role of the Handler : a Handler (as indicated by it's name) can handle messages. To be able to handle custom messages you must subclass the Handler class and implements the handleMessage(Message) method.
        So, the Looper will simply call the handleMessage of the Handler who posted the message and its job (i.e. dispatching the messages) is finished (the Looper can move on to the next Message in the queue).
Final note
·         UI-thread is a first class citizen :
        On Android, there is a main Looper associated with the main Thread (i.e. the UI-thread). You can get a reference to it with Looper.getMainLooper(), so you create a Handler associated with the main Looper with :
Handler myHandler = new Handler(Looper.getMainLooper());
and with that you can post a message from any thread to the UI-thread
·         Should you really use messages and subclassing Handler to use this ? No (not always).
        You don't always need to create message explicitly to use this mechanism. You can easily post a Runnable to a Handler and in this case you don't even need to override the handleMessage(Message) because the default implementation of the Handler will simply execute the Runnable (under the hood : a message is created with the Runnable associated to it)
·         Looper must be prepared (to receive messages).
        By default there is no Looper on every thread (by default, there is only a prepared one in the UI-Thread). To prepare a Looper for the current thread : call Looper.prepare()
----
https://developer.android.com/reference/android/os/Looper.html    
       Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.
       Most interaction with a message loop is through the Handler class.
       This is a typical example of the implementation of a Looper thread, using the separation of prepare() and loop() to create an initial Handler to communicate with the Looper.
  class LooperThread extends Thread {
      public Handler mHandler;

      public void run() {
          Looper.prepare();

          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          Looper.loop();
      }
  }
Additional Resources
       Bu kaynakları incelemedim ancak incelemekte fayda var,hatta vakit olursa bu kaynakları inceleyip buraya ekleyebilirim:
https://blog.nikitaog.me/2014/10/11/android-looper-handler-handlerthread-i/
https://blog.nikitaog.me/2014/10/18/android-looper-handler-handlerthread-ii/
http://skillgun.com/question/588/android/threads/what-is-the-difference-between-thread-and-handler-thread-in-android
https://www.safaribooksonline.com/library/view/efficient-android-threading/9781449364120/ch04.html
http://androidshortnotes.blogspot.com.tr/2013/02/thread-concept-in-android.html
http://mindtherobot.com/blog/159/android-guts-intro-to-loopers-and-handlers/
asynchronous android kitabını indirdim. yukarıda bu kitabın 3.chapter'ını inceledim linki de yukarıda.
http://guides.codepath.com/android/managing-threads-and-custom-services
https://medium.com/@ali.muzaffar/handlerthreads-and-why-you-should-be-using-them-in-your-android-apps-dc8bf1540341#.pt64dwm17
http://androidsrc.net/android-loopers-and-handlers-code-tutorial/
https://blog.mindorks.com/android-core-looper-handler-and-handlerthread-bd54d69fe91a#.6jz7wba6l
http://stackoverflow.com/questions/25094330/example-communicating-with-handlerthread
http://blog.xebia.com/android-looper-anatomy/
http://stephendnicholas.com/posts/android-handlerthread
http://codetheory.in/android-handlers-runnables-loopers-messagequeue-handlerthread/
https://www.safaribooksonline.com/library/view/efficient-android-threading/9781449364120/ch08.html
https://newfivefour.com/android-service-handler-tutorial.html
http://techtej.blogspot.com.tr/2011/02/android-passing-data-between-main.html
http://www.concretepage.com/android/android-start-stop-service-from-activity-example-using-handlerthread
http://alvinalexander.com/java/jwarehouse/android/core/java/android/os/HandlerThread.java.shtml

Hiç yorum yok:

Yorum Gönder