Android中异步消息处理机制

和其他的UI库一样,Android的UI线程也是不安全的。即如果想要更新应用程序里面的UI元素,则必须在主线程中进行。如果不在主线程中进行,就会出现异常。废话不多说,直接上例子。

<span style="font-size:18px;">public class MainActivity extends Activity
{
	private TextView tvText;
	private Button changeText;
	
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		tvText = (TextView) findViewById(R.id.tv_text);
		changeText = (Button) findViewById(R.id.change_text);
		
		changeText.setOnClickListener(new OnClickListener()
		{
			
			@Override
			public void onClick(View v)
			{
				switch (v.getId())
				{
				case R.id.change_text:
					new Thread(new Runnable()
					{
						@Override
						public void run()
						{
							tvText.setText("Hi,world");
							
						}
					}).start();
					break;

				default:
					break;
				}
				
			}
		});
	}
}</span>


<span style="font-size:18px;"><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"
    tools:context="com.example.hanlertest.MainActivity" >

    <TextView
        android:id="@+id/tv_text"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="22sp"
        android:textColor="#f00"
        android:text="@string/hello_world" />

    <Button
        android:id="@+id/change_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:text="Button" />

</RelativeLayout></span>



上面是MainActivity和xml布局文件中的代码,可以看到,我们的逻辑非常简单,布局文件中添加了一个TextView和一个Button,我们给按钮设置了一个点击监听,当点击按钮的时候,更改TextView的文字为“Hi,world”,我也是在onclick方法中new 了一个子线程去处理的,那么是不是不会出错呢?

我只能说,想想很美好,现实很残酷。当然,由此也可以证明了子线程中是不可以进行更新UI操作的。但是在某些情况下,我们需要在子线程中进行UI操作。怎么办呢?虽然我们第一次程序错误了,但是我们也不能就此认输,现在我们将代码进行一点改进:

public class MainActivity extends Activity
{
	private TextView tvText;
	private Button changeText;
	private static final int MESSAGE_TYPE = 1;
	<strong><span style="color:#ff0000;">private Handler handler = new Handler()
	{
		public void handleMessage(Message msg) 
		{
			//在这里我们可以进行相应的UI操作
			switch (msg.what)
			{
			case MESSAGE_TYPE:
				tvText.setText("Hi, world");
				break;

			default:
				break;
			}
		};
	};</span></strong>
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		tvText = (TextView) findViewById(R.id.tv_text);
		changeText = (Button) findViewById(R.id.change_text);
		changeText.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View v)
			{
				switch (v.getId())
				{
				case R.id.change_text:
					new Thread(new Runnable()
					{
						@Override
						public void run()
						{
							<strong><span style="color:#ff0000;">Message message = new Message();
							message.what = MESSAGE_TYPE;
							handler.sendMessage(message);//将消息发送出去</span></strong>
						}
					}).start();
					break;
				default:
					break;
				}	
			}
		});
	}
}


当我们添加了红色部分的代码后,子线程中就可以更新UI了。这不是与我们之前说的子线程中不能更新UI相违背?要解释清楚这个原理,必须要深入了解一下Android的消息机制了。

Android中的主线程是不允许进行延时操作的, Android中的异步处理消息主要由四个部分组成,Message, Handler , MessageQueue , Looper。下面简要介绍下这四个组成部分。

1、Message:Message是在线程之间传递的消息,它可以在内部携带少量的消息。主要用于在不同的线程中传递消息。

2、Handler: Handler是处理者的意思,主要用于发送消息和处理消息的。发送消息使用的是Handler.sendMessage(),发出的消息经过一系列的操作后,又会调用Handler.handlerMessage()方法对消息进行处理。

3、MessageQueue: 消息队列。Handler通过sendMessage方法发送消息后,该消息会保存在MessageQueue中,Handler发送的消息会一直存在于消息队列中,等待被处理。每一个线程中只有一个MessageQueue。

4、Looper:MessageQueue是一个消息队列,Looper就是维护这个消息队列的“保安”,它内部有一个维护着一个Loop方法,当调用了Looper的Loop方法后,会进入到一个无线循环中,然后每当在MessageQueue中发现一条消息,就取出,交给Handler去处理。每个线程只有一个Looper对象。


了解了MessageQueue,Message, Handler, Looper对象后,我们在对整个流程进行梳理一遍,首先在主线程中创建一个Message对象,重写父类的handlerMessage方法,然后当子线程中需要进行UI操作时,就创建一个Message对象,并通过Handler将这条消息发送出去。发出去的这条消息会被添加到MessageQueue中,也就是在消息队列中队尾等待被处理,而Looper则会一直尝试从MessageQueue中取出等待被处理的消息,最后分发回Handler的handleMessage方法中进行处理。由于Handler是在主线程中创建的,所以此时handleMessage方法中的代码也是在主线程中运行,所以我们在这里可以进行UI操作。

整个异步消息处理机制如下图所示:图是百度找的,将就着看。整个消息处理机制就是这样。






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值