Android 개발 노트: 메시지 순환과 Looper 상세 정보
public class LooperDemoActivity extends Activity {
private WorkerThread mWorkerThread;
private TextView mStatusLine;
private Handler mMainHandler;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.looper_demo_activity);
mMainHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
String text = (String) msg.obj;
if (TextUtils.isEmpty(text)) {
return;
}
mStatusLine.setText(text);
}
};
mWorkerThread = new WorkerThread();
final Button action = (Button) findViewById(R.id.looper_demo_action);
action.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mWorkerThread.executeTask("please do me a favor");
}
});
final Button end = (Button) findViewById(R.id.looper_demo_quit);
end.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mWorkerThread.exit();
}
});
mStatusLine = (TextView) findViewById(R.id.looper_demo_displayer);
mStatusLine.setText("Press 'do me a favor' to execute a task, press 'end of service' to stop looper thread");
}
@Override
public void onDestroy() {
super.onDestroy();
mWorkerThread.exit();
mWorkerThread = null;
}
private class WorkerThread extends Thread {
protected static final String TAG = "WorkerThread";
private Handler mHandler;
private Looper mLooper;
public WorkerThread() {
start();
}
public void run() {
// Attention: if you obtain looper before Looper#prepare(), you can still use the looper
// to process message even after you call Looper#quit(), which means the looper does not
//really quit.
Looper.prepare();
// So we should call Looper#myLooper() after Looper#prepare(). Anyway, we should put all stuff between Looper#prepare()
// and Looper#loop().
// In this case, you will receive "Handler{4051e4a0} sending message to a Handler on a dead thread
// 05-09 08:37:52.118: W/MessageQueue(436): java.lang.RuntimeException: Handler{4051e4a0} sending message
// to a Handler on a dead thread", when try to send a message to a looper which Looper#quit() had called,
// because the thread attaching the Looper and Handler dies once Looper#quit() gets called.
mLooper = Looper.myLooper();
// either new Handler() and new Handler(mLooper) will work
mHandler = new Handler(mLooper) {
@Override
public void handleMessage(Message msg) {
/*
* Attention: object Message is not reusable, you must obtain a new one for each time you want to use it.
* Otherwise you got "android.util.AndroidRuntimeException: { what=1000 when=-15ms obj=it is my please
* to serve you, please be patient to wait!........ } This message is already in use."
*/
// Message newMsg = Message.obtain();
StringBuilder sb = new StringBuilder();
sb.append("it is my please to serve you, please be patient to wait!
");
Log.e(TAG, "workerthread, it is my please to serve you, please be patient to wait!");
for (int i = 1; i < 100; i++) {
sb.append(".");
Message newMsg = Message.obtain();
newMsg.obj = sb.toString();
mMainHandler.sendMessage(newMsg);
Log.e(TAG, "workthread, working" + sb.toString());
SystemClock.sleep(100);
}
Log.e(TAG, "workerthread, your work is done.");
sb.append("
your work is done");
Message newMsg = Message.obtain();
newMsg.obj = sb.toString();
mMainHandler.sendMessage(newMsg);
}
};
Looper.loop();
}
public void exit() {
if (mLooper != null) {
mLooper.quit();
mLooper = null;
}
}
// This method returns immediately, it just push an Message into Thread's MessageQueue.
// You can also call this method continuously, the task will be executed one by one in the
// order of which they are pushed into MessageQueue(they are called).
public void executeTask(String text) {
if (mLooper == null || mHandler == null) {
Message msg = Message.obtain();
msg.obj = "Sorry man, it is out of service";
mMainHandler.sendMessage(msg);
return;
}
Message msg = Message.obtain();
msg.obj = text;
mHandler.sendMessage(msg);
}
}
}
이 실례에서 메인 라인에서 임무를 수행하는 것은 서비스 라인에 메시지를 보내는 동시에 관련 데이터를 전달하는 것이다. 데이터는 메시지 대상(Message)으로 포장된 다음에 서비스 라인의 메시지 대기열에 넣고 메인 라인의 호출이 되돌아온다. 이 과정은 매우 빠르기 때문에 메인 라인을 막지 않는다.서비스 라인은 메시지가 메시지 대기열에 들어갈 때마다 깨워서 대기열에서 메시지를 꺼내고 작업을 수행합니다.서비스 스레드는 임의의 수량의 작업을 수신할 수 있습니다. 즉, 주 스레드는 끊임없이 서비스 스레드에 메시지를 보낼 수 있습니다. 이 메시지는 메시지 대기열에 넣고, 서비스 스레드는 모든 작업이 끝날 때까지 계속 실행됩니다. (메시지 대기열이 비어 다른 메시지가 없습니다.) 서비스 스레드는 다시 휴면 상태로 들어갑니다. 새로운 메시지가 올 때까지.서비스 라인을 종료하려면 mLooper 대상에서quit () 를 호출하면 메시지 순환이 종료됩니다. 라인이 다른 작업이 없기 때문에 전체 라인도 종료됩니다.주의해야 할 것은 한 라인의 메시지 순환이 종료된 후에 메시지를 더 이상 보낼 수 없습니다. 그렇지 않으면 "Runtime Exception: Handler {4051e4a0}sending message to a Handler on a dead thread"를 이상 던질 수 있습니다.그래서 Looper에서 권장합니다.prepare () 후 Looper를 호출합니다.이 Looper에 대한 인용을 가져오기 위해 myLooper () 는 종료(quit () 대상에 호출해야 함) 에 사용됩니다.또한 메시지를 받을 때 메시지 순환이 종료되었는지 확인하는 데 사용됩니다 (예를 들어).
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.