现在的位置: 首页 > 综合 > 正文

android中的线程与消息处理

2014年01月04日 ⁄ 综合 ⁄ 共 6394字 ⁄ 字号 评论关闭

一、线程理解

在主线程(UI线程)中创建线程有两种方法,一是通过Thread类的构造方法来创建(查看API我们可以知道,Thread类实现了Runnable接口,其中提供了很多种构造方法,可以用来构造不同的线程,下面只是其中的一种)

Thread thread  = new Thread(new Runnable(){

			@Override
			public void run() {
				// TODO Auto-generated method stub
				//线程中要执行的操作
			}
		});

二是实现Runnable接口,当让实现Runnable接口必须要实现其中的run方法

public class Thread1 implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		//线程中要执行的操作
	}
}


在非主线程中创建线程有两种方法

一是继承Thread或者HandlerThread类(后者是前者的子类),二是实现Runnable接口

Thread和HandlerThread的区别有两点,

1、构造函数不同(Thread有很多种构造函数,我就不一一列出来了)
HandlerThread在Thread的基础上增加了两个构造函数:HandlerThread(String name)和HandlerThread(String name, int priority)

2、HandlerThread在继承Thread的同时,重写了其中的run方法

@Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

我们发现,在run方法中,系统已经为我们封装好了一个Looper对象,并开启了这个Looper对象(Looper对象我会在后面继续说的)

不论以哪种方式创建线程,我们必须调用Thread类中的start方法来开启这个线程,也可以调用sleep(long time)方法来让线程休眠指定的时间,调用interrupt()方法来中断线程

当调用stat方法时线程开始工作,当线程中的run方法执行完毕时,线程正常结束,要让线程结束还有几种方法,就是调用interrupt()或者stop()(这个种方法已经不推荐使用了),线程结束后,就无法重新启用了。

(Thread类中还有很多方法,可以实现很多功能)


二、线程间的消息的传递

先看几个概念


1、Looper

        一个线程对应着一个Looper对象,一个Looper对象对应着一个MessageQueue(消息队列)对象,MessageQueue用于存放Message(消息)在消息队列中存放的消息按照先进先出(FIFO)的原则执行,打个比方,Looper就是一个放水的管道,而MessageQueue就是这个管道中的水。Looper对象用来为线程开启一个消息循环,从而操作MessageQueue对象,默认情况下,android中新创建的线程除了主线程(UI线程)之外,是没有开启消息循环的(前面说的Thread和HandlerThread的区别就在此)。所以在主线程中调用new
Handler()方法创建一个Handler对象是不会出错的,但是在非主线程中就不能这么干了。

        如果想要在非主线程中创建一个Handler对象,首先要使用Looper中的prepare()方法来初始化一个Looper对象,然后创建Handler对象,最后调用Looper类中的loop()方法来启动这个Looper对象

public class Thread1 extends Thread{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		//线程中要执行的操作
		Handler handler = new Handler(){
			public void handleMessage(Message msg){
				/****/
			}
		};
		Looper.loop();
	}
}

Looper类中还提供了几种方法,对应的作用如下:

myLooper() 用来获取当前线程的Looper对象

getThread() 用来获取Looper对象所属的线程

quit() 用于结束Looper循环

2、Handler(消息处理类)

消息处理类允许发送和处理Message或Runnable对象到其所在线程的MessageQueue中,在发送的时候可以指定不同的延迟时间、发送时间和要携带的数据当MessageQueue循环到改Message时调用相应的Handler对象的handleMessage()方法对其进行处理。前面说到, 一个线程对应着一个Looper对象,一个Looper对象对应着一个MessageQueue(消息队列)对象,但是一个线程可以有多个Handler对象,这些Handler对象可以共享同一个Looper和MessageQueue。Handler中有很多方法,挑几个常用的

handleMessage(Message msg) 处理消息的方法,在发送消息之后,该方法会自动调用

post(Runnable r) 立即发送Runnable对象,该Runnable对象最后被封装成Message对象

postAtTime(Runnable r, long uptimeMills) 定时发送Runnable对象

postDelayed(Runnable r, long delayMills) 延迟发送Runnable对象

sendEmptyMessage(int what) 发送空消息

sendMessage(Message msg) 立即发送消息

sendMessageAtTime(Message msg, long uptimeMills) 定时发送消息

sendMessageDelayed(Message msg, long delayMills) 延迟发送消息


3、Message(消息)

Message存在于MessageQueue中,一个MessageQueue可以包含多个Message对象,Message有以下几种属性

arg1、arg2 用来存放整型数据

Object 用来存放对象

replyTo (Message类型) 同来指定此Message发送到何处的可选Message对象

what (int 型) 用来指定用户自定义的消息代码,帮助接受者了解这个消息的信息

需要注意的是:

Message的属性可以用来保存int和Object类型的数据,如果要保存其他类型的数据,可以先将要保存的对象放到Bundle对象中,然后调用Message中的setData()方法将Bundle对象保存到Message对象中

Message虽然有自己的构造方法,可以通过new Message()的方法来创建Message对象,但是这种创建对象的方式很浪费内存,一般采用Message.obtain()或者Handler.obtainMessage()方法来从消息池中获取一个空的Message对象

下面看几个例子

代码1

public class MainActivity extends Activity {
	private String text;
	private Handler handler;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		final TextView textView = (TextView) findViewById(R.id.textView1);

		handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				if (msg.what == 00) {
					textView.setText("计算的结果为:" + msg.arg1);
				}
			}
		};

		thread.start();
	}

	Thread thread = new Thread(new Runnable() {

		@Override
		public void run() {
			// TODO Auto-generated method stub
			Message msg = handler.obtainMessage();
			msg.what = 00;// 只是起到一个标记的作用
			msg.arg1 = fun(1, 1);
			handler.sendMessage(msg);// 发送消息
		}
	});

	private int fun(int i, int j) {
		// TODO Auto-generated method stub
		return i + j;
	}
}

为了进一步说明Message中的what中的作用,我把上面的代码改了一下

代码2

public class MainActivity extends Activity {
	private String text;
	private Handler handler;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		final TextView textView = (TextView) findViewById(R.id.textView1);

		handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				if (msg.what == 00) {
					// textView.setText("计算的结果为:" + msg.arg1);
					System.out.println("计算结果为:" + msg.arg1);
				} else if (msg.what == 11) {
					// textView.setText("计算的结果为:" + msg.arg1);
					System.out.println("计算结果为:" + msg.arg1);
				}
			}
		};

		thread1.start();
		thread2.start();
	}

	Thread thread1 = new Thread(new Runnable() {

		@Override
		public void run() {
			// TODO Auto-generated method stub
			Message msg = handler.obtainMessage();
			msg.what = 00;// 只是起到一个标记的作用
			msg.arg1 = fun(1, 1);
			handler.sendMessage(msg);// 发送消息
		}
	});

	Thread thread2 = new Thread(new Runnable() {

		@Override
		public void run() {
			// TODO Auto-generated method stub
			Message msg = handler.obtainMessage();
			msg.what = 11;// 只是起到一个标记的作用
			msg.arg1 = fun(1, 2);
			handler.sendMessage(msg);// 发送消息
		}
	});

	private int fun(int i, int j) {
		// TODO Auto-generated method stub
		return i + j;
	}
}



我们发现一个Handler对象可以处理几个发送过来的消息,就是靠的Message中的what来区分是哪个线程发送过来的消息。

代码1的另一种写法

主类:(注意:我的Handler对象是在主线程中创建的,然后通过构造函数传递给线程类)

代码3

public class MainActivity extends Activity {
	private String text;
	private Handler handler;

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		Thread1 thread = new Thread1(handler);

		handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				if (msg.what == 00) {
					System.out.println("计算结果为:" + msg.arg1);
				}
			}
		};
	}
}

线程类:

public class Thread1 extends Thread {

	private Handler myhandler;

	public Thread1(Handler handler) {
		// TODO Auto-generated constructor stub
		myhandler = handler;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		Message msg = myhandler.obtainMessage(); 
		msg.what = 00;
		msg.arg1 = fun(1,1);
		myhandler.sendMessage(msg);
	}
	
	private int fun(int i, int j){
		return i+j;
	}
}

上面的代码都是在主线程中传创建的Handler对象,再来看一下不在主线程中创建Handler对象,看下面的代码

代码4

public class MainActivity extends Activity {
	private Handler handler1;

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

		Thread1 thread1 = new Thread1();
		thread1.start();
		
		thread2.start();
	}
	
	Thread thread2 = new Thread(new Runnable(){

		@Override
		public void run() {
			// TODO Auto-generated method stub
			Message msg = handler1.obtainMessage();
			msg.what = 11;
			msg.arg1 = fun(1,3);
			handler1.sendMessage(msg);
		}
	});
	
	public static int fun(int i, int j){
		return i+j;
	}
}
public class Thread1 extends Thread {

	private Handler handler1;
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		handler1 = new Handler(){
			public void handleMessage(Message msg){
				if(msg.what == 11){
					System.out.println("计算的结果为:"+msg.arg1);
				}
			}
		};
	}
}


在上面的代码中,我是在字线程中创建的Handler对象,结果就出现了异常

抱歉!评论已关闭.