转载网址:http://www.cnblogs.com/crazypebble/archive/2011/03/23/1991829.html
在Android中使用Handler和Thread线程执行后台操作

对于线程的控制,我们将介绍一个 Handler类,使用该类可以对运行在不同线程中的多个任务进行排队,并使用Message和Runnable对象安排这些任务。在javadoc中,对Handler是这样解释的:Handler可以发送和处理消息对象或Runnable对象,这些消息对象和Runnable对象与一个线程相关联。每个Handler的实例都关联了一个线程和线程的消息队列。当创建了一个Handler对象时,一个线程或消息队列同时也被创建,该Handler对象将发送和处理这些消息或Runnable对象。

  下面有几种对Handler对象的构造方法需要了解一下:

a、如果new一个无参构造函数的Handler对象,那么这个Handler将自动与当前运行线程相关联,也就是说这个Handler将与当前运行的线程使用同一个消息队列,并且可以处理该队列中的消息。

private Handler handler = new Handler();

  我们做这样一个实验,在主用户界面中创建一个带有无参构造函数的Handler对象,该Handler对象向消息队列推送一个Runnable对象,在Runnable对象的run函数中打印当前线程Id,我们比较主用户界面线程ID和Runnable线程ID是否相同。具体代码如下:

public class HandlerTest01 extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); System.out.println("Activity ---> " + Thread.currentThread().getId());
handler.post(r);
} private Handler handler = new Handler();
private Runnable r = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Runnalbe ---> " + Thread.currentThread().getId());
}
};
}

  通过这个例子的输出可以发现,Runnable对象和主用户界面线程的ID是相同。在这个例子中,我们直接利用handler对象post了一个runnable对象,相当于直接调用了Runnable对象的run函数,也就说没有经过start函数调用run(),那么就不会创建一个新线程,而是在原有线程内部直接调用 run()方法,因此输出的线程Id是相同的。

b、如果new一个带参构造函数的Handler对象,那么这个Handler对象将与参数所表示的Looper相关联。注意:此时线程类应该是一个特殊类HandlerThread类,一个Looper类的Thread类,它继承自Thread类。

HandlerThread handlerthread = new HandlerThread("MyThread");
handlerthread.start();
private MyHandler handler = new MyHandler(handlerthread.getLooper()); class MyHandler extends Handler {
public MyHandler() { } public MyHandler(Looper looper) {
super(looper);
}
}

  下面这个例子,将介绍如何开启一个新的线程,并通过Handler处理消息。

public class HandlerTest02 extends Activity {

private MyHandler myhandler = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
System.out.println("Activity ---> " + Thread.currentThread().getId()); // 生成一个HandlerThread对象,使用Looper来处理消息队列
HandlerThread thread = new HandlerThread("MyThread");
// 必须启动这个线程
thread.start();
// 将一个线程绑定到Handler对象上,则该Handler对象就可以处理线程的消息队列
myhandler = new MyHandler(thread.getLooper());
// 从Handler中获取消息对象
Message msg = myhandler.obtainMessage();
// 将msg对象发送给目标对象Handler
msg.sendToTarget();
} class MyHandler extends Handler {
public MyHandler() { } // 带有参数的构造函数
public MyHandler(Looper looper) {
super(looper);
} @Override
public void handleMessage(Message msg) {
System.out.println("MyHandler ---> " + Thread.currentThread().getId());
}
}
}

  根据这个例子返回的结果,可以看出,新线程Id与主用户界面的线程Id不同。由于我们调用了thread.start()方法,真正的创建了一个新线程,与原来的线程处于不同的线程上下文中,因此打印输出的线程Id是不同的。
c、如果需要Handler对象去处理消息,那么就要重载Handler类的handleMessage函数。

private Handler handler = new Handler() {

@Override
public void handleMessage(Message msg) {
// TODO : Handle the msg
// Usually we update UI here.
}
}

  注意到注释部分,我们通常在handleMessage中处理更新UI界面的操作。

  前面介绍了Handler类的基本使用,但是还是没有涉及到Thread类。要想实现在后台重新开启一个新的线程,通过该线程执行一些费时的操作,我们也使用Thread类来完成这个功能。下面我们先给出一个使用Thread类的例子程序。

public class ThreadTest extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
System.out.println("Activity ---> " + Thread.currentThread().getId()); Thread thread = new Thread(r);
thread.start();
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
thread.stop();
} Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Runnable ---> " + Thread.currentThread().getId());
}
};
}

  这个程序执行的结果如下。新线程在创建对象时,传入了Runnable类的一个对象,在Runnable对象中重载了run()方法去执行耗时的操作;新的线程实例执行了start方法,开启了一个新的线程执行Runnable的run方法。

上面这些就是我现在接触到执行线程的方法,在线程中,可以完成我们所需要的操作(比如:下载,处理数据,检测网络状态等),使其与UI界面分离,那么UI界面不会因为耗时操作导致界面被阻塞。

  在《解密Google Android》一书中,发现了这样一个启动线程的模型。利用该模型,我们可以把一些耗时的操作放到doStuff方法中去执行,同时在 updateUIHere方法中进行更新UI界面的操作,就可以完成一个线程所需要的功能。其他的说明写在注释部分了。

Handler myHandler = new Handler() {
public void handleMessage(Message msg) {
updateUIHere();
}
} new Thread() {
public void run() {
doStuff(); // 执行耗时操作
Message msg = myHandler.obtainMessage();
Bundle b = new Bundle();
b.putString("key", "value");
m.setData(b); // 向消息中添加数据
myHandler.sendMessage(m); // 向Handler发送消息,更新UI
}
}.start();

======================================================================================================
通过上面的文章,可以对handler的处理机制有一个比较深刻的认识,而我之前的疑问,为什么在handler中post一个线程,也就有了答案。
handler的应用相当一个对多线程管理的机制,通过一个线程的队列(因为可以post多个)来管理这些线程,
同时通过使用Handler或者HandlerThread来控制,这些线程是要在主线程中执行还是要新开一个线程来执行。

另外一个不错的例子
参考网址:http://rayln.iteye.com/blog/1180652

public class HandlerActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button b1 = (Button)findViewById(R.id.button1);
Button b2 = (Button)findViewById(R.id.button2);
b1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//立即把线程加入消息队列中
handler.post(r);
}
});
b2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//停止线程
handler.removeCallbacks(r);
}
});
}
Handler handler = new Handler();
/**
*该方法的内部类将在handler.sendMessage(msg)后执行
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
System.out.println("msg:"+msg.arg1);
}
};
*/
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("sysout Thread");
//得到一个消息对象,Message类是有Android系统
Message msg = handler.obtainMessage();
//将msg对象arg1参数设置为122,用arg1和arg2传递消息
//优点是系统资源消耗较小
msg.arg1 = 122;
//将消息加入到另外一个消息队列中去
handler.sendMessage(msg);
//3000毫秒后加入线程到消息队列中
handler.postDelayed(r, 3000);
}
};
}
 
from:http://blog.csdn.net/fei0724/article/details/8664462
 

handler.post 为什么要将thread对象post到handler中执行呢?的更多相关文章

  1. 转:handler.post 为什么要将thread对象post到handler中执行呢?

    转载网址:http://blog.csdn.net/fei0724/article/details/8664462在Android中使用Handler和Thread线程执行后台操作 对于线程的控制,我 ...

  2. 4.构造Thread对象你也许不知道的几件事

    1.Thread类对象只有在调用了start()方法之后,JVM虚拟机才会给我们创建一个真正的线程!否则就不能说是创建了线程!也就是说new Thread()之后,此时实际上在计算机底层,操作系统实际 ...

  3. 8 并发编程-(线程)-多线程与多进程的区别&Thread对象的其他属性或方法

    1.开启速度  在主进程下开启线程比 开启子进程快 # 1 在 主进程下开启线程 from threading import Thread def work(): print('hello') if ...

  4. 并发编程 - 线程 - 1.开启线程的两种方式/2.进程与线程的区别/3.Thread对象的其他属性或方法/4.守护线程

    1.开启线程的两种方式: 进程,线程: 进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合)而线程才是cpu上的执行单位) 1.同一个进程内的多个线程共享该进程内的地址资源 2.创建线 ...

  5. 使用Executor管理Thread对象详解

    java SE5的java.util.concurrent包中的执行器(Executor)是管理Thread对象的优选方法.使用Executor管理Thread对象可以简化并发编程. Executor ...

  6. 多线程《四》Thread对象的其他属性和方法

    Thread对象的其他属性或方法 介绍 Thread实例对象的方法 # isAlive(): 返回线程是否活动的. # getName(): 返回线程名. # setName(): 设置线程名. th ...

  7. 第25课 std::thread对象的析构

    一. 线程的等待与分离 (一)join和detach函数 1. 线程等待:join() (1)等待子线程结束,调用线程处于阻塞模式. (2)join()执行完成之后,底层线程id被设置为0,即join ...

  8. 《JAVA高并发编程详解》-Thread对象的启动

    当我们用关键字new创建一个Thread对象时,此时它并不处于执行状态,因为没有调用start方法启动该线程,那么线程的状态为NEW状态,NEW状态通过start方法进入RUNNABLE状态. 线程一 ...

  9. Android Handler的使用示例:结合源码理解Android Handler机制(一)

    什么是Handler? Android 的官方解释: 文档分节1:A Handler allows you to send and process Message and Runnable objec ...

随机推荐

  1. UNIX command Questions Answers asked in Interview

    UNIX or Linux operating system has become default Server operating system and for whichever programm ...

  2. POJ 2499 Binary Tree(二叉树,找规律)

    题意:给一个这样的二叉树,每个节点用一对数(a,b)表示,根节点为(1,1).设父亲为(a,b),左儿子(a+b,b),右儿子(a,a+b). 给几组数据,(i,j),求从根节点到(i,j)节点需要向 ...

  3. hdu2717 Catch That Cow

    http://acm.hdu.edu.cn/showproblem.php?pid=2717 //水搜... #include<stdio.h> #include<math.h> ...

  4. Matlab中编译C++文件

    今天在跑<Robust Object Tracking via Sparsity-based Collaborative Model>这篇文章的代码时候,发现出现如下错误: 发现错误时由于 ...

  5. 【PHPsocket编程专题(实战篇③)】构建基于socket的HTTP请求类

    该代码是两年前写的,现在看起来有点渣了,仅仅是提供一个思路,现在做一些Api开发的时候官方会有一些SDK,这些SDK其实原理都是通过socket来通讯的,其实我个人主张用curl更方便,当然前提是你的 ...

  6. iOS开发--_weak typeof(self) weakSelf = self

    _weak typeof(self) weakSelf = self;  (一)内存管理原则  1.默认strong,可选weak.strong下不管成员变量还是property,每次使用指针指向一个 ...

  7. photoshop:调整图层之色相/饱和度

    色相/饱和度:快速调色及调整图片色彩浓淡明暗 面板主要参数:色相.饱和度.明度 色相用来改变颜色:顺序按红-黄-绿-青-蓝-洋红 饱和度用来控制色彩浓淡 明度控制色彩明暗 勾选“着色”,图片会变成单色 ...

  8. 项目SVN的IP地址发生变化时修改SVN为新的IP地址

    在eclipse或者Myeclipse自带的svn:subclipse中修改ip地址 项目开发中有可能要修改SVN的IP地址,entries文件里面包含svn服务器的地址信息.每个文件夹都会产生一个e ...

  9. 利用PhantomJS搭建Highcharts export服务

    利用PhantomJS搭建Highcharts export服务 一直在使用Highcharts做web图表的展示, 但是当发送定时的报表邮件的遇到了这个问题. 为了保证邮件图表和web页图表样式一致 ...

  10. Intellij IDEA 构建Spring Web项目 — 用户登录功能

    相关软件: 1.Intellij IDEA14:http://pan.baidu.com/s/1nu16VyD 2.JDK7:http://pan.baidu.com/s/1dEstJ5f 3.Tom ...