码迷,mamicode.com
首页 > 其他好文 > 详细

Handler机制详述1---Handler的简介和用法

时间:2016-05-13 04:00:36      阅读:192      评论:0      收藏:0      [点我收藏+]

标签:

1.Handler简介

    handler是Android系统封装的用于线程更新UI,消息处理的机制。

[说明]

查看Android Framework源码可以看到,常见的Activity的生命周期onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy()都是通过handler发送不同Message,AMS(Activity Manager Service)通过Handler向ActivityThread发送消息,在ActivityThread中执行不同的Activity的周期。


2.Handler的用法

// Google文档的地址
http://developer.android.com/reference/android/os/Handler.html
// Google对Handler的介绍
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. 
Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, 
it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver 
messages and runnables to that message queue and execute them as they come out of the message queue.

[说明]

查看Google文档可以看出,Handler允许我们绑定(associate with)一个线程的MessageQueue,并通过该handler向该线程发送Message或者Runnable对象,一个Handler绑定了一个线程以及这个线程的MessageQueue,当你创建一个Handler的时候,该Handler就会和Thread以及该Thread的MessageQueue绑定。

首先,下面的程序,在子线程中更新UI:

public class MainActivity extends Activity
{

	TextView tv;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		tv = (TextView) findViewById(R.id.tv);

		new Thread()
		{
			public void run()
			{
				try
				{
					Thread.sleep(1000);
				} catch (InterruptedException e)
				{
					e.printStackTrace();
				}
				tv.setText("update UI");
			};
		}.start();
	}

}

运行之后,程序奔溃,logcat中打印信息:

技术分享

[说明]

上面信息的主要内容是,不允许在子线程中更新UI线程,Android自身设定的机制则是只能在子线程中处理耗时的操作,处理完毕之后,在UIThread中更新UI,而子线程是不能更新UI的。


Handler主要提供了下面API来实现子线程与UIThread之间的通信问题:

  • sendMessage
  • sendMessageDelayed
  • post(Runnable)
  • postDelayed(Runnable, long)
(1). 使用sendMessage进行线程通信:

public class MainActivity extends Activity
{

	@SuppressLint("HandlerLeak")
	Handler handler = new Handler()
	{
		public void handleMessage(android.os.Message msg)
		{
			if (msg.what == 0x1)
			{
				tv.setText("update UI");
			}
		};
	};

	TextView tv;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		tv = (TextView) findViewById(R.id.tv);

		new Thread()
		{
			public void run()
			{
				try
				{
					Thread.sleep(1000);
				} catch (InterruptedException e)
				{
					e.printStackTrace();
				}
				handler.sendEmptyMessage(0x1);
			};
		}.start();
	}

}

sendMessageDelayed(Message, long)是延迟long毫秒之后,再发送Message。

(2).post(Runnable)
public class MainActivity extends Activity
{

	@SuppressLint("HandlerLeak")
	Handler handler = new Handler()
	{
		public void handleMessage(android.os.Message msg)
		{
		};
	};

	TextView tv;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		tv = (TextView) findViewById(R.id.tv);

		new Thread()
		{
			public void run()
			{
				try
				{
					Thread.sleep(1000);
				} catch (InterruptedException e)
				{
					e.printStackTrace();
				}

				handler.post(new Runnable()
				{

					@Override
					public void run()
					{
						tv.setText("update UI");
					}
				});
			};
		}.start();
	}

}


 下面利用Handler实现一个简单的图片轮换的功能,每隔1s循环替换ImageView显示的图片:
public class MainActivity extends Activity
{

	Handler handler = new Handler();

	ImageView img;
	int[] images = // 存放循环播放的图片
	{ R.drawable.weather_0, R.drawable.weather_1, R.drawable.weather_2, R.drawable.weather_3, R.drawable.weather_4 };
	private int imgCount = images.length;
	private int index = 0;
	private long delayMillis = 1000L; // 每隔1s循环一次

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		img = (ImageView) findViewById(R.id.img);
		handler.post(imgRunnable);
	}

	private Runnable imgRunnable = new Runnable()
	{
		public void run()
		{
			img.setBackgroundResource(images[index % imgCount]);
			index++;
			handler.postDelayed(imgRunnable, delayMillis);
		}
	};

}

对应的xml文件中只有一个<ImageView />:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:id="@+id/img"
        android:layout_width="200.0dip"
        android:layout_height="200.0dip"
        android:layout_centerInParent="true"
        android:contentDescription="@string/app_name" />

</RelativeLayout>

技术分享


[注意]若要终止上面的循环,可以使用下面的方法:

handler.removeCallbacks(imgRunnable);


下面使用Handler演示消息截获的用法:
[说明]
Handler的创建有一个接受一个Handler.Callback参数的构造方法,此方法内部的handlerMessage(Message msg)方法有boolean类型的返回值,return true可以实现类似消息截获的效果:
public class SecondActivity extends Activity
{

	@SuppressLint("HandlerLeak")
	Handler handler = new Handler(new Handler.Callback()
	{
		@Override
		public boolean handleMessage(Message msg)
		{
			if (msg.what == 0x1)
			{
				Log.v(LOG, "返回true,消息被截获");
				return true;
			} else if (msg.what == 0x2)
			{
				Log.v(LOG, "返回false,不截获");
				return false;
			}
			return false;
		}
	})
	{
		@Override
		public void handleMessage(Message msg)
		{
			Log.v(LOG, "收到消息....");
		}
	};

	Button btn1, btn2;
	private final String LOG = "SecondActivity";

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_second);

		btn1 = (Button) findViewById(R.id.btn1);
		btn1.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View v)
			{
				handler.sendEmptyMessage(0x1);
			}
		});

		btn2 = (Button) findViewById(R.id.btn2);
		btn2.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View v)
			{
				handler.sendEmptyMessage(0x2);
			}
		});
	}
}

界面效果如下:
技术分享

点击“消息截获”按键,会向handler对象传递0x1的Message,在Handler.Callback的boolean handlerMessage()方法中返回true,此时该Message不会再被void handlerMessage()方法接收到:
技术分享

相反,当点击“消息不截获”按键,会发送0x2消息,Handler.Callback的boolean handlerMessage()返回false,此时消息仍然会被void handlerMessage()方法所获的:
技术分享

查看Handler的源码可以看到,消息的传递是通过dispatchMessage(Message msg)来发送的,而dispatchMessage函数如下:
技术分享

当使用了Handler包含Handler.Callback参数的构造函数时,mCallback != null,此时会执行mCallback.handlerMessage(msg)方法,若此方法返回true,则直接执行return返回,不再执行下面的handlerMessage(msg),若mCallback.handlerMessage(msg)返回false,mCallback.handlerMessage(msg)方法被调用之后,还会继续调用handlerMessage(msg)方法。

Handler机制详述1---Handler的简介和用法

标签:

原文地址:http://blog.csdn.net/tianmaxingkong_/article/details/51338418

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!