zoukankan      html  css  js  c++  java
  • 解析Android的 消息传递机制Handler

    1. 什么是Handler:

    Handler 网络释义“机械手。经理”意思,在Android它用于管理多个线程UI操作;

    2. 为什么会出现Handler:

    在Android里面的设计机制。只同意主线程(动时所移动的线程,由于此线程主要是完毕对UI相关事件的处理,所以也称UI线程)

    对UI进行改动等操作,这是一种规则的简化,之所以这样简化是由于Android的UI操作时线程不安全的。为了避免多个线程同一时候操作UI造成线程安全

    问题,才出现了这个简化的规则。

    由此以来,问题就出现了,由于仅仅同意主线程改动UI,那么假设新线程的操作须要改动原来的UI该怎样进行的?举个常见的样例就是:假设新线程的操作是更新UI中TextView

    的值。那么该怎样操作?

    这时候就须要Handler在新线程和主线程(UI线程)之间传递歇息;

    3. Handler的功能:

    主要就是两个:

    1)在新启动的线程中发送消息;

    2)在主线程中获取,处理消息;

    看似简单。可是怎样处理同步问题却是一个难题。即怎样把握新线程发送消息的时机和主线程处理消息的时机。这个问题的解决方式是:

    在主线程和新线程之间使用一个叫做MessageQueue的队列,新启动的线程发送消息时将消息先发送到与之关联的MessageQueue,然后主线程的Handler方法会被调用

    从MessageQueue中去取对应的消息进行处理。

    4. Handler的实现机制

    Handler的实现主要是依靠以下的几个方法:

    读取消息使用到的方法是;  

    void handleMessage(Message msg) 。进程通过重写这种方法来处理消息。

    final boolean hasMessage(int what), 检查消息队列中是否包括what属性为指定值的消息。

    final boolean hasMessage(int what,Object object),减产队列中是否有指定值和指定对象的消息。

    Message obtainMessage(): 获取消息,课被多种方式重载。

    发送消息用到的方法有:

    sendEmptyMessage(int what): 发送空消息;

    final boolean sendEmptyMessageDelayed(int what, long delayMillis):指定多少毫秒之后发送空消息

    final boolean sendMessage(Message msg):马上发送消息

    final boolean sendMessageDelayed(Message msg, long delayMillis)指定多少毫秒之后发送空消息

    public class HandlerTest extends Activity
    {
    	ImageView show;
    	// 代表从网络下载得到的图片
    	Bitmap bitmap;
    	Handler handler = new Handler()
    	{
    		@Override
    		<span style="color:#ff0000;">public void handleMessage(Message msg)</span>
    		{
    			if(msg.what == 0x123)  //假设该消息是本程序发的
    			{
    				// 使用ImageView显示该图片
    				show.setImageBitmap(bitmap);
    			}
    		}
    	};
    	@Override
    	public void onCreate(Bundle savedInstanceState)
    	{
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.main);
    		show = (ImageView) findViewById(R.id.show);
    		<span style="color:#ff0000;">new Thread()</span>
    		{
    			public void run()
    			{
    				try
    				{
    					// 定义一个URL对象
    					URL url = new URL("http://img001.21cnimg.com/photos"+
    <span style="white-space:pre">					</span>"/album/20140626/o/C164BDB0B24F59929C2113C0A9910636.jpeg");
    					// 打开该URL相应的资源的输入流
    					InputStream is = url.openStream();
    					// 从InputStream中解析出图片
    					bitmap = BitmapFactory.decodeStream(is);
    					// 发送消息、通知UI组件显示该图片
    					<span style="color:#ff0000;">handler.sendEmptyMessage(0x123);</span>
    					is.close();
    				}
    				catch (Exception e)
    				{
    					e.printStackTrace();
    				}
    			}
    		}.start();
    	}
    }

    新的进程在将图片从网上解析下来之后向主进程发送空消息,之后主线程中handleMessage()的方法会被自己主动调用,更新UI。

    5.  深入理解Handler的工作机制

    上面我们看到了一个简单的Handler的工作过程。当中Handler是在主线程中定义的。假设Handler是在子线程中定义的那么能够更深入的理解他的工作原理。

    由于有的时候我们须要将主线程中的消息传递给子线程。让子线程去处理一些计算量比較大的任务。由于应用程序应尽量避免在UI线程中运行耗时操作,否则会

    导致ANR异常(Application Not Responding)。这种话,我们上面所讲的 主线程和新线程的角色就发生了颠倒,主线程须要向新线程发送消息,然后新线程

    进行消息的处理。在这样的情况下,Handler须要定义在新线程中,在这样的情况下须要做一些额外的工作。

    我们先来解释一下配合Handler的其他组件:

    Looper: 每一个线程相应一个looper,它负责管理MessageQueue。将消息从队列中取出交给Handler进行处理。

    MessageQueue:负责管理Message,接收Handler发送过来的message;

    下图是整个工作的流程:


    以下我们详细阐述一下工作的过程:

    在创建一个Handler之前须要先创建Looper,创建的方式是Looper.prepare();

    在创建Looper的同一时候会自己主动创建MessageQueue;

    以下 创建一个Handler的对象

    然后调用Looper的loop()方法

    以下的这段代码是一个实例,摘自 疯狂android讲义。主进程将上限发送给子线程计算2-上限之间的素数

    public class CalPrime extends Activity
    {
    	static final String UPPER_NUM = "upper";
    	EditText etNum;
    	CalThread calThread;
    	// 定义一个线程类
    	class CalThread extends Thread
    	{
    		<span style="color:#cc0000;">public Handler mHandler;</span>
    
    		public void run()
    		{
    			<span style="color:#ff0000;">Looper.prepare();</span>
    			<span style="color:#ff0000;">mHandler = new Handler()</span>
    			{
    				// 定义处理消息的方法
    				@Override
    				public void handleMessage(Message msg)
    				{
    					if(msg.what == 0x123)
    					{
    						int upper = msg.getData().getInt(UPPER_NUM);
    						List<Integer> nums = new ArrayList<Integer>();
    						// 计算从2開始、到upper的全部质数
    						outer:
    						for (int i = 2 ; i <= upper ; i++)
    						{
    							// 用i处于从2開始、到i的平方根的全部数
    							for (int j = 2 ; j <= Math.sqrt(i) ; j++)
    							{
    								// 假设能够整除,表明这个数不是质数
    								if(i != 2 && i % j == 0)
    								{
    									continue outer;
    								}
    							}
    							nums.add(i);
    						}
    						// 使用Toast显示统计出来的全部质数
    						Toast.makeText(CalPrime.this , nums.toString()
    							, Toast.LENGTH_LONG).show();
    					}
    				}
    			};
    			<span style="color:#ff0000;">Looper.loop();</span>
    		}
    	}
    	@Override
    	public void onCreate(Bundle savedInstanceState)
    	{
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.main);
    		etNum = (EditText)findViewById(R.id.etNum);
    		<span style="color:#ff0000;">calThread = new CalThread();</span>
    		// 启动新线程
    		<span style="color:#ff0000;">calThread.start();</span>
    	}
    	// 为button的点击事件提供事件处理函数
    	public void cal(View source)
    	{
    		// 创建消息
    		<span style="color:#ff0000;">Message msg = new Message();</span>
    		msg.what = 0x123;
    		Bundle bundle = new Bundle();
    		bundle.putInt(UPPER_NUM ,
    			Integer.parseInt(etNum.getText().toString()));
    		<span style="color:#ff0000;">msg.setData(bundle);</span>
    		// 向新线程中的Handler发送消息
    		<span style="color:#ff0000;">calThread.mHandler.sendMessage(msg);</span>
    	}
    }

    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    086 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 03 面向对象基础总结 01 面向对象基础(类和对象)总结
    085 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 04 构造方法调用
    jQuery UI组件库Kendo UI使用技巧小分享
    Kendo UI ListView模板功能,让Web开发更轻松
    UI组件套包DevExpress ASP.NET Core v20.2新版亮点:全新的查询生成器
    Devexpress WinForms最新版开发.NET环境配置Visual Studo和SQL Server对应版本
    全新的桌面应用数据可视化呈现方式,Sankey Diagram控件你了解多少?
    java中的递归方法
    连接数据库查询 将查询结果写入exce文件中
    java连接mysql数据查询数据
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4750886.html
Copyright © 2011-2022 走看看