浅谈Handler,Loop,MessageQueue,Thread的小秘密

多线程,多线程,多线程!重要的事情多说几遍。在Android编程中不可能不遇到多线程的问题,我们都知道UI界面即主线程不能做耗时的操作,必须要利用多线程的特性进行耗时的操作,然后UI界面负责实时更新就哦了。

BUT!Thread,Handler都是什么鬼,我迷糊很久很久啦!这不,课题需要,今天好好整理了一下思路,结合课本和示例,终于弄清楚这都是什么了,于是迫不及待写了这一Blog!

First,Thread这里我们就不多说了,学过JAVA的筒子应该都知道,这就是java中用来另起线程的类,继承Thread,覆盖run()方法即另起一个新线程,在run()方法中进行耗时的操作。那么问题来了,Handler什么?是Android里特有的另起线程的类吗?和Thread一样吗?非也!下面我来详细讲一讲Handler这哥们!

Android的消息传递机制是另一种形式的“事件处理”,这个机制是为了解决Android应用的多线程的问题——Android平台只允许UI线程修改Activity里的UI自检,这样就导致一种矛盾,耗时的操作不能再UI线程中执行,另起的线程又不能修改Activity里的UI组件,这让老夫如何是好呢!憋捉急,Handler的消息传递机制帮你实现!

Handler类的主要作用:

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

2、在主线程中获取、处理消息

即:在主线程中出现如下代码:

	final Handler myHandler = new Handler(){
		public void handleMessage(Message msg){
			if(msg.what == 0x123){
				/**
				 * 修改UI的相关操作
				 */
			}
		}
	};
然后另起一个新线程发送消息:

		new Timer().schedule(new TimerTask(){

			@Override
			public void run() {
				// TODO Auto-generated method stub
				myHandler.sendEmptyMessage(0x123);
			}
			
		}, 0,1200);
上述new TimerTask()本质就是启动一条新线程。

上述就是handler在android的多线程干了什么事情的演示。

貌似说到这里,我可以关闭页面了,不行,我们必须深入了解Handler的工作原理,学习与Handler一起工作的几个组件:

Message:Handler接受和处理的消息对象(上面代码中的0x123);

Looper:每个线程只能拥有一个Looper,它的loop()方法负责读取MessageQueue中的消息,读到消息之后就把消息发送给该消息的Handler进行处理,BUT,我们在上面的代码中好像没有发现这个Looper,还有他的loop()方法,憋捉急,一会儿说;

MessageQueue:消息队列,先进先出的方式来管理Message,程序创建Looper对象时会在它的构造器中创建MessageQueue对象;

我们之前说,Handler有两个作用,发送消息和处理消息,程序用Handler发送的消息送到指定的MessageQueue,也就是说,如果希望Handler正常工作,则在当前线程中必须有一个MessageQueue,否则消息没有地方保存了,不过MessageQueue是Looper管理的,也就是说,如果希望Handler正常工作,在当前线程必须有一个Looper对象!如果希望Handler正常工作,在当前线程必须有一个Looper对象!重要的事情多说几遍,反正复制粘贴。

那么怎么样让当前线程必须有一个Looper对象,而我们前面的代码怎么没有呢!答案来了:

主UI线程中,系统已经初始化了一个Looper对象,系统已经初始化了一个Looper对象,因此程序直接创建Handler即可,然后就可以通过Handler来发送消息、处理消息,这就是为什么我们上面的代码没有看到Looper这个鬼;

程序员自己启动的子线程,程序员必须自己创建一个Looper对象,程序员自己启动的子线程,程序员必须自己创建一个Looper对象,并启动它,创建Looper对象调用它的prepare()方法即可。然后调用Looper的静态loop()方法来启动它。loop()方法使用一个死循环不断取出MessageQueue中的消息,将取出的消息分给该消息对应Handler进行处理。

在线程中使用Handler的步骤如下:

1、调用Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象的时候,它的构造器也创建了与之配套的MessageQueue

2、有了Looper之后,创建Handler子类的实例,重写handleMessage()方法,该方法负责处理来自于其他线程的消息

3、调用Looper的loop()方法启动Looper

下面看一个Demo,帮助大家理解:

用户输入一个数值上限,点击“计算”按钮时,该应用会把该上限数值发送到新启动的线程,在新线程中计算该范围内的所有质数(特别耗时的操作):

package com.example.handlertest;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

	EditText text;
	Button cal;
	TextView show;
	mThread calThread;
	
	class mThread extends Thread{
		public Handler mHandler;
		@Override
		public void run() {
			// TODO Auto-generated method stub
			mHandler = new Handler(){

				@Override
				public void handleMessage(Message msg) {
					// TODO Auto-generated method stub
					if(msg.what == 0x123){
						int upper = msg.getData().getInt("KEY");
						List<Integer> list = new ArrayList<Integer>();
						outer:
						for(int i=2; i<upper ; i++){
							for(int j=2; j<i;j++){
								if(i!=2 && i%j==0){
									continue outer;//想跳出两层循环,则需要这样处理
								}
							}
							list.add(i);
						}
						Toast.makeText(MainActivity.this, list.toString(), Toast.LENGTH_LONG).show();
						show.setText(list.toString());
					}
				}
				
			};
		}
		
	}
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
				
		text = (EditText) findViewById(R.id.editText1);
		cal = (Button) findViewById(R.id.button1);
		
		calThread = new mThread();
		calThread.start();
		
		cal.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				int x = Integer.parseInt(text.getText().toString());
				Message msg = new Message();
				msg.what = 0x123;
				Bundle bundler = new Bundle();
				bundler.putInt("KEY", x);
				msg.setData(bundler);
				calThread.mHandler.sendMessage(msg);
			}
		});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
}

上述代码运行会出现如下问题:


报错信息显示,没有Looper呀亲!

所以代码改为如下:

	class mThread extends Thread{
		public Handler mHandler;
		@Override
		public void run() {
			// TODO Auto-generated method stub
			Looper.prepare();
			mHandler = new Handler(){

				@Override
				public void handleMessage(Message msg) {
					// TODO Auto-generated method stub
					if(msg.what == 0x123){
						int upper = msg.getData().getInt("KEY");
						List<Integer> list = new ArrayList<Integer>();
						outer:
						for(int i=2; i<upper ; i++){
							for(int j=2; j<i;j++){
								if(i!=2 && i%j==0){
									continue outer;//想跳出两层循环,则需要这样处理
								}
							}
							list.add(i);
						}
						Toast.makeText(MainActivity.this, list.toString(), Toast.LENGTH_LONG).show();
						show.setText(list.toString());
					}
				}
				
			};
			Looper.loop();
		}
		
	}

其他部分一样,这样就可以获得正确结果:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值