java 线程间通信 handler_Handler线程间通信

Handler相关说明:

解释:安卓的UI线程(即OnCreate函数创建的线程)是线程非安全的。也就是说,在UI线程中,使用sleep这样的函数会导致整个线程延迟,但是我们在安卓开发中,往往会经常遇到一些延迟比较厉害的操作,(例如通过HTTP获取数据信息)如果放在主线程中,则会影响UI界面的渲染。但是如果另外新开一个线程,则由于UI线程只能在主线程中修改,而导致无法修改主线程的UI界面。这个时候Handler就出来解决这个问题。

handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程), 也就是说Handler对象初始化后,就默认与对它初始化的进程的消息队列绑定,因此可以利用Handler所包含的消息队列,制定一些操作的顺序。

Handler主要两大作用:

1. 提供post操作。post操作主要将Runnable对象放进主线程(UI)线程中的队列中操作。post还支持延迟操作。使用post后,Runnable是按照队列的形式逐个执行的。

2. handlerMessage操作。主要用于新开一个线程与主线程中的通信。新开的线程执行完毕后,可以通过sendMessage给主线程发送消息,并且传递一些参数,然后主线程就可以修改UI界面了。

Handler提供的函数:

post类方法允许你排列一个Runnable对象到主线程队列中:

post(Runnable)

postAtTime(Runnable,long)

postDelayed(Runnable long)

sendMessage类方法, 允许你安排一个带数据的Message对象到队列中:

sendEmptyMessage(int)

sendMessage(Message)

sendMessageAtTime(Message,long)

sendMessageDelayed(Message,long)

应用实例:

1,传递Message。用于接受子线程发送的数据, 并用此数据配合主线程更新UI。

在Android中,对于UI的操作通常需要放在主线程中进行操作。如果在子线程中有关于UI的操作,那么就需要把数据消息作为一个Message对象发送到消息队列中,然后,用Handler中的handlerMessge方法处理传过来的数据信息,并操作UI。类sendMessage(Message msg)方法实现发送消息的操作。 在初始化Handler对象时重写的handleMessage方法来接收Messgae并进行相关操作。

2,传递Runnable对象。用于通过Handler绑定的消息队列,安排不同操作的执行顺序。

Handler对象在进行初始化的时候,会默认的自动绑定消息队列。利用类post方法,可以将Runnable对象发送到消息队列中,按照队列的机制按顺序执行不同的Runnable对象中的run方法。

另外,Android的CPU分配的最小单元是线程,Handler一般是在某个线程里创建的,因而Handler和Thread就是相互绑定的,一一对应。而Runnable是一个接口,Thread是Runnable的子类。所以说,他俩都算一个进程。xml文件:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

/>

/>

View Code

packagecom.example.androidexpriment;importandroid.app.Activity;importandroid.os.Bundle;importandroid.os.Handler;importandroid.util.Log;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.Button;public class MainActivity extendsActivity {private String TAG = "MainActivity";//声明两个按钮控件

private Button startButton = null;private Button endButton = null;

@Overridepublic voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);//根据控件的ID得到代表控件的对象,并为这两个按钮设置相应的监听器

startButton =(Button)findViewById(R.id.startButton);

startButton.setOnClickListener(newStartButtonListener());

endButton=(Button)findViewById(R.id.endButton);

endButton.setOnClickListener(newEndButtonListener());

Log.i(TAG,"Activity-->" +Thread.currentThread().getId());

}class StartButtonListener implementsOnClickListener{

@Overridepublic voidonClick(View v) {//调用Handler的post方法,将要执行的线程对象添加到队列当中

handler.post(updateThread);

}

}class EndButtonListener implementsOnClickListener{

@Overridepublic voidonClick(View v) {

handler.removeCallbacks(updateThread);

}

}//创建一个Handler对象

Handler handler = newHandler();//将要执行的操作写在线程对象的run方法当中

Runnable updateThread = newRunnable(){

@Overridepublic voidrun() {

Log.i(TAG,"UpdateThread");

Log.i(TAG,"Activity-->" +Thread.currentThread().getId());//在run方法内部,执行postDelayed或者是post方法

handler.postDelayed(updateThread, 3000);

}

};

}

点击start后,程序的运行结果就是每隔3秒钟,就会在控制台打印一行UpdateTread。这是因为实现了Runnable接口的updateThread对象进入了空的消息队列即被立即执行run方法,而在run方法的内部,又在3000ms之后将其再次发送进入消息队列中。

注意这种方法创建Handler对象并不需要重写handlerMessage方法。

7e0f5a19d3570446187ec7cb2fa1b7d9.png

从输出结果能看出来:

post方法虽然发送的是一个实现了Runnable接口的类对象,但是它并非创建了一个新线程,而是执行了该对象中的run方法。也就是说,整个run中的操作和主线程处于同一个线程。这样对于那些简单的操作,似乎并不会影响。但是对于耗时较长的操作,就会出现“假死”。为了解决这个问题,就需要使得handler绑定到一个新开启线程的消息队列上,在这个处于另外线程的上的消息队列中处理传过来的Runnable对象和消息。Runnable对象只是作为一个封装了操作的对象被传递,并未产生新线程。

下面这种写法也是可以的:

packagecom.example.androidexpriment;importandroid.app.Activity;importandroid.os.Bundle;importandroid.os.Handler;importandroid.util.Log;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.Button;public class MainActivity extendsActivity {

TestThread t= null;private String TAG = "MainActivity";//声明两个按钮控件

private Button startButton = null;private Button endButton = null;

@Overridepublic voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);//根据控件的ID得到代表控件的对象,并为这两个按钮设置相应的监听器

startButton =(Button)findViewById(R.id.startButton);

startButton.setOnClickListener(newStartButtonListener());

endButton=(Button)findViewById(R.id.endButton);

endButton.setOnClickListener(newEndButtonListener());

Log.i(TAG,"onCreate-->" +Thread.currentThread().getId());

t= new TestThread(1);

}class StartButtonListener implementsOnClickListener{

@Overridepublic voidonClick(View v) {//调用Handler的post方法,将要执行的线程对象添加到队列当中

handler.post(t);

}

}class EndButtonListener implementsOnClickListener{

@Overridepublic voidonClick(View v) {

handler.removeCallbacks(t);

}

}//创建一个Handler对象

Handler handler = newHandler();class TestThread extendsThread{intprime;

TestThread(intprime) {this.prime =prime;

}

@Overridepublic voidrun() {//在run方法内部,执行postDelayed或者是post方法

handler.postDelayed(t, 3000);

Log.i(TAG,"TestThread-->" +Thread.currentThread().getId());

}

}

}

c62c459245eec91ad632416c0135c956.png

虽然创建了一个Thread,但是并没有执行Thread的start()方法。考虑到Thread和Runnable之间的关系,上面的两种代码并无实质差别,所以logcat中甚至都没出现启动新线程的日志。

然而,如果稍加修改:加上启动方法

class StartButtonListener implementsOnClickListener{

@Overridepublic voidonClick(View v) {//调用Handler的post方法,将要执行的线程对象添加到队列当中

handler.post(t);

t.start();

}

}

775b86ba11f02ad208dc208c2092ceea.png

可以明显看到,虽然启动了新线程,但post仍然可以把这个线程推到主线程里面去,线程由虚拟机自动结束。

所以,在UI线程(主线程)中:

mHandler=new Handler();

mHandler.post(new Runnable(){

void run(){

//执行代码..

}

});

这个线程其实是在UI线程之内运行的,并没有新建线程。

常见的新建线程的方法是:参考J2SE文档的

1、

class PrimeThread extends Thread {

long minPrime;

PrimeThread(long minPrime) {

this.minPrime = minPrime;

}

public void run() {

// compute primes larger than minPrime

. . .

}

}

The following code would then create a thread and start it running:

PrimeThread p = new PrimeThread(143);

p.start();

2、

class PrimeRun implements Runnable {

long minPrime;

PrimeRun(long minPrime) {

this.minPrime = minPrime;

}

public void run() {

// compute primes larger than minPrime

. . .

}

}

The following code would then create a thread and start it running:

PrimeRun p = new PrimeRun(143);

new Thread(p).start();

尽量按照上面给出的两种方式做,不要受网上影响简单的从Threa创建,那样不能做到传递参数。

static void

Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers.

代码验证:

packagecom.example.androidexpriment;importandroid.app.Activity;importandroid.os.Bundle;importandroid.os.Handler;importandroid.os.Message;importandroid.util.Log;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.Button;public class MainActivity extendsActivity {private String TAG = "MainActivity";//声明两个按钮控件

private Button startButton = null;private Button endButton = null;

TestThread t= null;int flag = 0;

@Overridepublic voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);//根据控件的ID得到代表控件的对象,并为这两个按钮设置相应的监听器

startButton =(Button)findViewById(R.id.startButton);

startButton.setOnClickListener(newStartButtonListener());

endButton=(Button)findViewById(R.id.endButton);

endButton.setOnClickListener(newEndButtonListener());

Log.i(TAG,"onCreate-->" +Thread.currentThread().getId());

t= new TestThread(1);

}class StartButtonListener implementsOnClickListener{

@Overridepublic voidonClick(View v) {//调用Handler的post方法,将要执行的线程对象添加到队列当中

t.start();

}

}class EndButtonListener implementsOnClickListener{

@Overridepublic voidonClick(View v) {

handler.sendEmptyMessage(33);

flag= 5;

}

}class TestThread extendsThread{intprime;

TestThread(intprime) {this.prime =prime;

}

@Overridepublic voidrun() {//在run方法内部,执行postDelayed或者是post方法

try{while(true) {

Log.i(TAG,"TestThread-->" +Thread.currentThread().getId());//handler.sendEmptyMessageDelayed(22,3000);

Thread.sleep(3000);

handler.sendEmptyMessage(22);if(flag == 5) //线程最佳的退出方法,就是自杀,也就是在线程的函数里面自然的return 出来

return;

}

}catch(InterruptedException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}

}//创建一个Handler对象

Handler handler = newHandler(){

@Overridepublic voidhandleMessage(Message msg) {//TODO Auto-generated method stub

super.handleMessage(msg);switch(msg.what) {case 22:

Log.i(TAG,"StartButton");

Log.i(TAG,"Handler-->" +Thread.currentThread().getId());break;case 33:

Log.i(TAG,"EndButton");

Log.i(TAG,"Handler-->" +Thread.currentThread().getId());break;

}

}

};

}

38b9397fc555e7e9bba65e3a918b3075.png

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值