androidのHandler


【回る:】http://www.cnblogs.com/keyindex/articles/1822463.html
前言
Androidを勉強しています.Androidの応用はどのように設計されているのかを知るために、いくつかのオープンソースのAndroidアプリケーションを詳しく調べることにしました.いくつかのオープンソースアプリケーションから点を吸収し、量の蓄積を行いながら、Androidの学習研究の方向を探っています.ここでまずjwoodのStandup Timerプロジェクトを選びました.本論文では研究内容をノートに整理し、インデックスリストを作成します.
キーワード
Android.os.Handlerは多くの知識点に関連しています.いくつかのキーワードを下記に挙げて、Handlerを紹介します.
android.os.Handler、android.os.Handler.Clalback
ループ、
Threadle、Runnable
Message、Message queue
android.os.Handler
Handlerはandroidでメッセージの送信と処理を担当しています.その主な用途は:
1)計画通りにメッセージを送信するか、またはRunnableを実行する(POST方法を使用する).
2)他のスレッドから送信されたメッセージは、スレッド衝突を避けるためにメッセージキューに入れられる(UIスレッドを更新するのが一般的である).
デフォルトでは、Handlerは現在のスレッドでのメッセージサイクルの例(Handler(Looper looper)、Handler(Looper looper,Handler.Clalback calback)を使用してスレッドを指定することができます.一方、メッセージ・キューは現在のスレッドの複数のオブジェクトによって配布、処理されます.(UIスレッドでは、システムは既にActivityで処理されています.いくつかのHandlerを起こして処理してもいいです.)を選択します.Handlerを実装する場合、Looperは任意のスレッドであってもいいです.Handlerのポインタがあれば、どのスレッドでもsendMessageができます.HandlerのMessageに対する処理は同時に行われません.一つのLooperは一つのMessageを処理してから次のストリップを読みます.したがって、利息解消の処理はブロッキング形式です.方法には時間のかかる操作があってはならず、時間のかかる操作を他のスレッドに置いて実行し、操作が終わったらMessage(sendMessags方法を通じて)を送信し、その後、handleMessage(UI)によって更新することができる.
カウントダウンプログラム
Timerを用いてカウントダウンプログラムを作成し、TimerとTimerTaskを用いてカウントダウンを行い、sendMessages方法を用いてメッセージを送信し、HanleMessageでUIを更新する.
Activityレイアウト:
Layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    >
<TextView      android:layout_width="fill_parent"     android:layout_height="wrap_content"     android:layout_gravity="center"    android:id="@+id/txt"    />
<Button    
android:id="@+id/btnStartTime"    
android:text="    "    
android:layout_width="80dip"    android:layout_height="wrap_content"     >
</Button> 
<Button     
android:id="@+id/btnStopTime"     
android:text="    "     
android:layout_width="80dip"    android:layout_height="wrap_content"  /> 
 <SeekBar android:id="@+id/SeekBar01" android:layout_width="match_parent" android:layout_height="wrap_content">
</SeekBar>
</LinearLayout> 
ここではTextViewを使ってカウントダウンの時間変化を表示します.2つのボタンは時間の開始と停止を制御します.SeekBarは主にスレッドがブロックされているかどうかを確認します.
onCreate

@Override    
public void onCreate(Bundle savedInstanceState) {      
        super.onCreate(savedInstanceState);        
        setContentView(R.layout.main);        
        txt = (TextView) findViewById(R.id.txt);        
        btnStart = (Button) findViewById(R.id.btnStartTime);      
        btnStop = (Button) findViewById(R.id.btnStopTime);
        Log.d("ThreadId", "onCread:"  
           + String.valueOf(Thread.currentThread().getId())); 

         myHandler = new Handler(this); 
         btnStart.setOnClickListener(this);
         btnStop.setOnClickListener(this); 
   } 
onCreate方法で元素の一つの元素を初期化します.myHandler=new Handler(this)と呼びます.  Handler(Handler.Clalback calback)コンストラクタは、コールバックで送られてきたメッセージを処理します(これでは、内部的な書き方でHandleMessage()を書き換える必要はありません).したがって、Activityは、android.os.Handler.Clalbackインターフェースを実現しなければならない.また、onCreateメソッドのThreadIdをLogに記録し、メッセージ送信、処理時に作成したスレッドと比較している.
メッセージを送信

    @Override    
public void onClick(View v) { 
       switch (v.getId()) { 
       case R.id.btnStartTime:
            startTimer();
            break;
        case R.id.btnStopTime:
            timer.cancel();
            break;
        }
    }
    private synchronized void startTimer() {
        timer = new Timer();
        // TimerTask 
updateTimerValuesTask = new TimerTask() {
        // @Override
        // public void run() {
        // updateTimerValues();
        // }
        //
        // };
        //    CallBack  。Task   TimerTask
        Task updateTimerValuesTask = new Task(this);
        timer.schedule(updateTimerValuesTask, 1000, 1000);
    }
    //          。
    private void updateTimerValues() {
        total--;
        Log.d("ThreadId", "send:"
                + String.valueOf(Thread.currentThread().getId()));
                Message msg=new Message();
        Bundle date = new Bundle();
//     
        date.putInt("time", total);
        msg.setData(date);
        msg.what=0;
        myHandler.sendMessage(msg);
        //     
//        Message msg=myHandler.obtainMessage();
//        Bundle date = new Bundle();
//     
//        date.putInt("time", total);
//        msg.setData(date);
//        msg.what=0;
//        msg.sendToTarget();
            }
    @Override
    public void TaskRun() {
        updateTimerValues();
    }     
Buttonボタンのイベント処理を実現し、カウントダウン動作に入ります.ここで使用するTimerは、タイミング操作を実行します.TaskはTimerTaskクラスを継承しています.タスク処理インターフェースを追加して、リカバリーモードを実現します.このActivityは、このリカバリーインターフェースITaskCallBackを実現する必要があります.(このようにするのは、内部の編纂方法があまり好きではないからです).
ICallBackインターフェースとTaskクラス

public interface ITaskCallBack {
    void TaskRun();
}
public class Task extends TimerTask {
    private ITaskCallBack iTask;
        public Task(ITaskCallBack iTaskCallBack)    {
        super();
        iTask=iTaskCallBack;
    }
        public void setCallBack(ITaskCallBack iTaskCallBack)    {
        iTask=iTaskCallBack;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub 
       iTask.TaskRun();
    }} 

  Java          。
  CallBack 
    /**     *            */
    @Override
    public boolean handleMessage(Message msg) {
            switch(msg.what)
        {
        case 0:
            Bundle date=msg.getData();
            txt.setText(String.valueOf(date.getInt("time")));
                        Log.d("ThreadId", "HandlerMessage:"
                    + String.valueOf(Thread.currentThread().getId()));
            Log.d("ThreadId", "msgDate:" + String.valueOf(date.getInt("time"))); 
           break;
        }
        return false;
    } 
Android.os.Handler.calbackインターフェースの実現が見られますが、実はhandlee Message()メソッドを書き換えています.
実行結果
OneCreate方法では、スレッドのIDは1(UIスレッド)であり、これはHandlerMessageがメッセージ処理を行う際に作成したスレッドIDと同じであり、メッセージ送信のスレッドIDは8非UIスレッドであることがわかる.
Threadleを使って実現します.
Activity類

/*
 *    :	ThreadHandlerrActivity.java
 *     :	2014-1-6
 */
package com.example.jiji;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class ThreadHandlerrActivity extends Activity implements Callback,
		OnClickListener {
	private TextView txt;
	private Button btnStart, btnStop;
	private Handler myHandler;
	private TimerThread timerThread;
	private int Total = 30;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		txt = (TextView) findViewById(R.id.txt);
		btnStart = (Button) findViewById(R.id.btnStartTime);
		btnStop = (Button) findViewById(R.id.btnStopTime);
		Log.d("ThreadId",
				"onCread:" + String.valueOf(Thread.currentThread().getId()));
		myHandler = new Handler(this);
		btnStart.setOnClickListener(this);
		btnStop.setOnClickListener(this);
	}

	/** *        */
	@Override
	public boolean handleMessage(Message msg) {
		switch (msg.what) {
		case 0:
			Bundle date = msg.getData();
			txt.setText(String.valueOf(date.getInt("time")));
			Log.d("ThreadId",
					"HandlerMessage:"
							+ String.valueOf(Thread.currentThread().getId()));
			Log.d("ThreadId", "msgDate:" + String.valueOf(date.getInt("time")));
			break;
		}
		return false;
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.btnStartTime:
			//       
			timerThread = new TimerThread(myHandler, 60);
			timerThread.start();
			break;
		case R.id.btnStopTime:
			timerThread.stopThread();
			// timerThread.destroy();
			break;
		}
	}
}
カスタムスレッドクラス

/*
 *    : TimerThread.java     : 2014-1-6
 */
package com.example.jiji;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

/**
 * *        ,     Handler, Total         
 * */
public class TimerThread extends Thread {
	public int Total = 60;
	public Handler handler;

	/**
	 * *        
	 * 
	 * @param mhandler
	 *            handler       
	 ** @param total
	 *               
	 */
	public TimerThread(Handler mhandler, int total) {
		super();
		handler = mhandler;
		Total = total;
	}

	public void stopThread() {
		Total = -1;
	}

	@Override
	public void run() {
		while (true) {
			Total--;
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if (Total < 0)
				break;
			Message msg = new Message();
			Bundle date = new Bundle();
			//     
			date.putInt("time", Total);
			msg.setData(date);
			msg.what = 0;
			Log.d("ThreadId",
					"Thread:" + String.valueOf(Thread.currentThread().getId()));
			handler.sendMessage(msg);
		}
		super.run();
	}
}
ここではThread類を継承していますが、Runnableインターフェースも直接実現できます.
POSTについて
Postの様々な方法は、Runnableをメッセージキューに送信し、到着時に処理することである.
POST

/*
 *    :	PostHandler.java
 *     :	2014-1-6
 */
package com.example.jiji;

import java.util.Timer;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class PostHandler extends Activity implements OnClickListener, Runnable {
	private TextView txt;
	private Button btnStart, btnStop;
	private Handler myHandler;
	private Timer timer;
	private int total = 60;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		txt = (TextView) findViewById(R.id.txt);
		btnStart = (Button) findViewById(R.id.btnStartTime);
		btnStop = (Button) findViewById(R.id.btnStopTime);
		Log.d("ThreadId",
				"onCread:" + String.valueOf(Thread.currentThread().getId()));
		myHandler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				switch (msg.what) {
				case 0:
					Bundle date = msg.getData();
					txt.setText(String.valueOf(date.getInt("time")));
					Log.d("ThreadId",
							"HandlerMessage:"
									+ String.valueOf(Thread.currentThread()
											.getId()));
					Log.d("ThreadId",
							"msgDate:" + String.valueOf(date.getInt("time")));
					break;
				}
			}
		};
		btnStart.setOnClickListener(this);
		btnStop.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.btnStartTime:
			// myHandler.post(this);
			myHandler.postDelayed(this, 1000);
			break;
		case R.id.btnStopTime:
			break;
		}
	}

	@Override
	public void run() {
		while (true) {
			total--;
			if (total < 0)
				break;
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Message msg = new Message();
			Bundle date = new Bundle();
			//     
			date.putInt("time", total);
			msg.setData(date);
			msg.what = 0;
			Log.d("ThreadId",
					"POST:" + String.valueOf(Thread.currentThread().getId()));
			myHandler.sendMessage(msg);
			Log.d("ThreadId",
					"Thread:" + String.valueOf(Thread.currentThread().getId()));
		}
	}
}

POSTを使うとRunnableを処理スレッド(ここはUI)に一緒に送信し、Runnableの操作が時間がかかるとスレッドがブロック状態になります.RunnableのRunメソッドを先に実行してからHandleMessage()に入るのが見えます.他の書き込みも試してみました.TimerThreadPOSTを過去に行っても、運転結果は同じです.
コード

/*
 *    :	PostHandler.java
 *     :	2014-1-6
 */
package com.example.jiji;

import java.util.Timer;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class PostHandler extends Activity implements OnClickListener, Runnable {
	private TextView txt;
	private Button btnStart, btnStop;
	private Handler myHandler;
	private Timer timer;
	private int total = 60;
	private TimerThread timerThread;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		txt = (TextView) findViewById(R.id.txt);
		btnStart = (Button) findViewById(R.id.btnStartTime);
		btnStop = (Button) findViewById(R.id.btnStopTime);
		Log.d("ThreadId",
				"onCread:" + String.valueOf(Thread.currentThread().getId()));
		myHandler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				switch (msg.what) {
				case 0:
					Bundle date = msg.getData();
					txt.setText(String.valueOf(date.getInt("time")));
					Log.d("ThreadId",
							"HandlerMessage:"
									+ String.valueOf(Thread.currentThread()
											.getId()));
					Log.d("ThreadId",
							"msgDate:" + String.valueOf(date.getInt("time")));
					break;
				}
			}
		};
		btnStart.setOnClickListener(this);
		btnStop.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.btnStartTime:
			// myHandler.post(this);
			// myHandler.postDelayed(this, 1000);
			timerThread = new TimerThread(myHandler, 60);
			myHandler.post(timerThread);
			break;
		case R.id.btnStopTime:
			break;
		}
	}

	@Override
	public void run() {
		while (true) {
			total--;
			if (total < 0)
				break;
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Message msg = new Message();
			Bundle date = new Bundle();
			//     
			date.putInt("time", total);
			msg.setData(date);
			msg.what = 0;
			Log.d("ThreadId",
					"POST:" + String.valueOf(Thread.currentThread().getId()));
			myHandler.sendMessage(msg);
			Log.d("ThreadId",
					"Thread:" + String.valueOf(Thread.currentThread().getId()));
		}
	}
}
POSTの様々な方法は主に「計画通りにメッセージを送信するか、またはあるRunnableを実行する(POST方法を使用する)」ために使用されると言える.
参考文献
Androidはノートのメッセージの仕組み、非同期とマルチスレッドを勉強します.
android handler概念解釈
SDK