Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Android:Looper,Handler,HandlerThread.PartI.
HOME
SUBSCRIBE
What do you know about threads in Android? You may say "I've
used AsyncTask to run tasks in background". Nice, but what else?
"Oh, I heard something about Handlers , because I used them to
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
1/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
//MyActivity.java
publicclassMyActivityextendsActivity{
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MyAsyncTaskmyTask=newMyAsyncTask(this);
myTask.execute("http://developer.android.com");
}
}
//MyAsyncTask.java
publicclassMyAsyncTaskextendsAsyncTask<String,Void,
Integer>{
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
2/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
privateContextmContext;
publicMyAsyncTask(Contextcontext){
mContext=context.getApplicationContext();
}
@Override
protectedvoidonPreExecute(){
Toast.makeText(mContext,"Let'sstart!",
Toast.LENGTH_LONG).show();
}
@Override
protectedIntegerdoInBackground(String...params){
HttpURLConnectionconnection;
try{
connection=(HttpURLConnection)new
URL(params[0])
.openConnection();
returnconnection.getResponseCode();
}catch(IOExceptione){
e.printStackTrace();
}
return1;
}
@Override
protectedvoidonPostExecute(Integerinteger){
if(integer!=1){
Toast.makeText(mContext,"Gotthefollowingcode:
"+integer,
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
3/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
Toast.LENGTH_LONG).show();
}
}
}
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progressBar"/>
</LinearLayout>
4/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
java.lang.RuntimeException:Can'tcreatehandlerinside
threadthathasnotcalledLooper.prepare()
atandroid.os.Handler.<init>(Handler.java:121)
atandroid.widget.Toast$TN.<init>(Toast.java:322)
atandroid.widget.Toast.<init>(Toast.java:91)
atandroid.widget.Toast.makeText(Toast.java:238)
at
com.example.testapp.MyActivity$MyAsyncTask.doInBackground(MyA
ctivity.java:25)
at
com.example.testapp.MyActivity$MyAsyncTask.doInBackground(MyA
ctivity.java:21)
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
5/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
Why did we face this error? The simple answer: because Toast
can be shown only from UI thread, the correct answer: because it
can be shown only from thread with Looper . You may ask "What
is a Looper ?". Ok, it's time to dig deeper. AsyncTask is a nice class,
but what if the functionality it has is not enough for your needs?
If we take a look under the hood of AsyncTask , we will nd, that
actually it is a box with tightly coupled components: Handler ,
Runnable , Thread . Let's work with this zoo. Each of you is familiar
with threads in Java , but in Android you may nd one more class
HandlerThread derived from Thread . The only signicant
dierence between HandlerThread and Thread you should turn your
attention to is that the rst one incorporates Looper, Thread and
MessageQueue. Looper is a worker, that serves a MessageQueue for
a current thread. MessageQueue is a queue that has tasks called
messages which should be processed. Looper loops through this
queue and sends messages to corresponding handlers to process.
Any thread can have only one unique Looper , this constraint is
achieved by using a concept of ThreadLocal storage. The bundle
of Looper + MessageQueue is like a pipeline with boxes.
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
6/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
You may ask "What's the need in all this complexity, if tasks will
be processed by their creators - Handlers ?". There are at least 2
advantages:
As mentioned above, it helps you to avoid race conditions,
when concurrent threads can make changes and when
sequential execution is desired.
Thread cannot be reused after the job is completed while
thread with Looper is kept alive by Looper until you call quit
method, so you don't need to create a new instance each time
you want to run a job in background.
You can make a Thread with Looper on your own if you want, but I
recommend you to use HandlerThread (Google decided to call it
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
7/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
its Looper at the constructor call as well. Now it's time to put all
pieces of theory together and look on real example. Let's imagine
we have an Activity and we want to post tasks (in this article
tasks are represented by the Runnable interface, what they
actually are will be shown in next part) to its MessageQueue (all
Activities and Fragments are living on UI thread), but they should
publicclassMyActivityextendsActivity{
privateHandlermUiHandler=newHandler();
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ThreadmyThread=newThread(newRunnable(){
@Override
publicvoidrun(){
for(inti=0;i<4;i++){
try{
TimeUnit.SECONDS.sleep(2);
}catch(InterruptedExceptione){
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
8/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
e.printStackTrace();
}
if(i==2){
mUiHandler.post(newRunnable(){
@Override
publicvoidrun(){
Toast.makeText(MyActivity.this,
"Iamatthemiddle
ofbackgroundtask",
Toast.LENGTH_LONG)
.show();
}
});
}
}
mUiHandler.post(newRunnable(){
@Override
publicvoidrun(){
Toast.makeText(MyActivity.this,
"Backgroundtaskis
completed",
Toast.LENGTH_LONG)
.show();
}
});
}
});
myThread.start();
}
}
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
9/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
//MyActivity.java
publicclassMyActivityextendsActivity{
privateHandlermUiHandler=newHandler();
privateMyWorkerThreadmWorkerThread;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mWorkerThread=newMyWorkerThread("myWorkerThread");
Runnabletask=newRunnable(){
@Override
publicvoidrun(){
for(inti=0;i<4;i++){
try{
TimeUnit.SECONDS.sleep(2);
}catch(InterruptedExceptione){
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
10/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
e.printStackTrace();
}
if(i==2){
mUiHandler.post(newRunnable(){
@Override
publicvoidrun(){
Toast.makeText(MyActivity.this,
"Iamatthemiddle
ofbackgroundtask",
Toast.LENGTH_LONG)
.show();
}
});
}
}
mUiHandler.post(newRunnable(){
@Override
publicvoidrun(){
Toast.makeText(MyActivity.this,
"Backgroundtaskis
completed",
Toast.LENGTH_LONG)
.show();
}
});
}
};
mWorkerThread.start();
mWorkerThread.prepareHandler();
mWorkerThread.postTask(task);
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
11/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
mWorkerThread.postTask(task);
}
@Override
protectedvoidonDestroy(){
mWorkerThread.quit();
super.onDestroy();
}
}
//MyWorkerThread.java
publicclassMyWorkerThreadextendsHandlerThread{
privateHandlermWorkerHandler;
publicMyWorkerThread(Stringname){
super(name);
}
publicvoidpostTask(Runnabletask){
mWorkerHandler.post(task);
}
publicvoidprepareHandler(){
mWorkerHandler=newHandler(getLooper());
}
}
12/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
privateclassMyWorkerThreadextendsHandlerThread{
privateHandlermWorkerHandler;
publicMyWorkerThread(Stringname){
super(name);
}
@Override
protectedvoidonLooperPrepared(){
mWorkerHandler=newHandler(getLooper());
}
publicvoidpostTask(Runnabletask){
mWorkerHandler.post(task);
}
}
Sometimes it will work ne, but sometimes you'll get NPE at the
postTask call stating, that mWorkerHandler is null . Surpise!
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
13/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
Why does it happen? The trick here is in native call needed for
new thread creation. If we take a loop on piece of code, where
onLooperPrepared is called, we will nd the following fragment in
publicvoidrun(){
mTid=Process.myTid();
Looper.prepare();
synchronized(this){
mLooper=Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid=1;
}
The trick here is that run method will be called only after new
thread is created and started. And this call can sometimes happen
after your call to the postTask method (you can check it by
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
14/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
Nikita
Moscow
http://blog.nikitaog.me/about
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
15/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
6Comments
DeveloperNotes
Recommend 5
Share
Login
SortbyBest
Jointhediscussion
phreakhead2monthsago
"NPEatthepostTaskcallstating,thatmWorkerHandlerisnull"
Okyesbuthowdoyoufixit?
Reply Share
metrophobe3monthsago
Justtoadd....theDIAGRAMisPRICELESS!
Reply Share
metrophobe3monthsago
Beautifullyexplainedsir!
Reply Share
blackkara8monthsago
Veryuseful,thanks
Reply Share
AlexanderSanchez8monthsago
ThatprepareLooper()bitisveryimportant.Thanks!
Reply Share
VinothVino8monthsago
Nicearticle
Reply Share
ALSOONDEVELOPERNOTES
Android:Looper,Handler,
HandlerThread.PartI.
Android:Looper,Handler,
HandlerThread.PartII.
16comments2yearsago
15comments2yearsago
NikitaOgorodnikovHiOman!Calling
NikitaOgorodnikovthanksforthe
start()inconstructorisnotasafe
approach,youcantakealookonthis
question
question!Thepurposeofthe`Looper`
isdescribedinthe1stparthere
http://blog.nikitaog.me/2014/1...,itis
Subscribe d AddDisqustoyoursiteAddDisqusAdd
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
Privacy
16/17
11/3/2016
Android:Looper,Handler,HandlerThread.PartI.
https://blog.nikitaog.me/2014/10/11/androidlooperhandlerhandlerthreadi/
17/17