2014년 7월 17일 목요일

Getting Through the Handlers

The most flexible means of making an Android-friendly background thread is to create
an instance of a Handler subclass. You need only one Handler object per activity, and
you do not need to manually register it. Merely creating the instance is sufficient to
register it with the Android threading subsystem.

Your background thread can communicate with the Handler, which will do all of its work
on the activity’s UI thread. This is important, as UI changes, such as updating widgets,
should occur only on the activity’s UI thread.
You have two options for communicating with the Handler: messages and Runnable
objects.

Messages
To send a Message to a Handler, first invoke obtainMessage() to get the Message object
out of the pool. There are a few flavors of obtainMessage(), allowing you to create empty
Message objects or ones populated with message identifiers and arguments. The more
complicated your Handler processing needs to be, the more likely it is you will need to
put data into the Message to help the Handler distinguish different events.
Then, you send the Message to the Handler via its message queue, using one of the
sendMessage...() family of methods, such as the following:
  • sendMessage(): Puts the message on the queue immediately
  • sendMessageAtFrontOfQueue(): Puts the message on the queue immediately and places it at the front of the message queue (versus the back, which is the default), so your message takes priority over all others
  • sendMessageAtTime(): Puts the message on the queue at the stated time, expressed in the form of milliseconds based on system uptime (SystemClock.uptimeMillis())
  • sendMessageDelayed(): Puts the message on the queue after a delay, expressed in milliseconds
  • sendEmptyMessage(): Sends an empty Message object to the queue, allowing you to skip the obtainMessage() step if you were planning on leaving it empty anyway
To process these messages, your Handler needs to implement handleMessage(), which
will be called with each message that appears on the message queue. There, the
Handler can update the UI as needed. However, it should still do that work quickly, as
other UI work is suspended until the Handler is finished.
For example, let’s create a ProgressBar and update it via a Handler. Here is the layout
from the Threads/Handler sample project:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ProgressBar android:id="@+id/progress"
style="?android:attr/progressBarStyleHorizontal" android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>


package com.commonsware.android.threads;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ProgressBar;
import java.util.concurrent.atomic.AtomicBoolean;

public class HandlerDemo extends Activity {
ProgressBar bar;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
bar.incrementProgressBy(5);
}
};
AtomicBoolean isRunning = new AtomicBoolean(false);

@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
bar = (ProgressBar) findViewById(R.id.progress);
}

public void onStart() {
super.onStart();
bar.setProgress(0);
Thread background = new Thread(new Runnable() {
public void run() {
try {
for (int i = 0; i < 20 && isRunning.get(); i++) {
Thread.sleep(1000);
handler.sendMessage(handler.obtainMessage());
}
} catch (Throwable t) {
// just end the background thread
}
}
});
isRunning.set(true);
background.start();
}

public void onStop() {
super.onStop();
isRunning.set(false);
}
}

As part of constructing the Activity, we create an instance of Handler, with our
implementation of handleMessage(). Basically, for any message received, we update the
ProgressBar by 5 points, and then exit the message handler.
We then take advantage of onStart() and onStop(). In onStart(), we set up a
background thread. In a real system, this thread would do something meaningful. Here,
we just sleep 1 second, post a Message to the Handler, and repeat for a total of 20
passes. This, combined with the 5-point increase in the ProgressBar position, will march
the bar clear across the screen, as the default maximum value for ProgressBar is 100.
You can adjust that maximum via setMax(). For example, you might set the maximum to
be the number of database rows you are processing, and update once per row.
Note that we then leave onStart(). This is crucial. The onStart() method is invoked on
the activity UI thread, so it can update widgets and such. However, that means we need
to get out of onStart(), both to let the Handler get its work done and to inform Android
that our activity is not stuck.

Note, though, that while ProgressBar samples like this one show your code arranging to
update the progress on the UI thread, for this specific widget, that is not necessary. At
least as of Android 1.5, ProgressBar is now UI thread safe, in that you can update it from
any thread, and it will handle the details of performing the actual UI update on the UI
thread.

Runnables
If you would rather not fuss with Message objects, you can also pass Runnable objects to
the Handler, which will run those Runnable objects on the activity UI thread. Handler
offers a set of post...() methods for passing Runnable objects in for eventual
processing.
Just as Handler supports post() and postDelayed() to add Runnable objects to the
event queue, you can use those same methods on any View (i.e., any widget or
container). This slightly simplifies your code, in that you can then skip the Handler
object.

Source From “Beginning Android 4”

댓글 없음:

댓글 쓰기

ETL 솔루션 환경

ETL 솔루션 환경 하둡은 대용량 데이터를 값싸고 빠르게 분석할 수 있는 길을 만들어줬다. 통계분석 엔진인 “R”역시 하둡 못지 않게 관심을 받고 있다. 빅데이터 역시 데이터라는 점을 볼때 분산처리와 분석 그 이전에 데이터 품질 등 데이...