package mars.handler;import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.widget.Toast;public class HandlerTest2 extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//打印了当前线程的ID
System.out.println("Activity-->" + Thread.currentThread().getId());
//生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能,这个类由Android应用程序框架提供
HandlerThread handlerThread = new HandlerThread("handler_thread");
//在使用HandlerThread的getLooper()方法之前,必须先调用该类的start();
handlerThread.start();
MyHandler myHandler = new MyHandler(handlerThread.getLooper());
Message msg = myHandler.obtainMessage();
//将msg发送到目标对象,所谓的目标对象,就是生成该msg对象的handler对象
Bundle b = new Bundle();
b.putInt("age", 20);
b.putString("name", "Jhon");
msg.setData(b);
msg.sendToTarget();
Toast.makeText(HandlerTest2.this,"在主线程中运行", 1000).show();
}

class MyHandler extends Handler{
public MyHandler(){

}
public MyHandler(Looper looper){
super(looper);
}
@Override
public void handleMessage(Message msg) {
Bundle b = msg.getData();
int age = b.getInt("age");
String name = b.getString("name");
System.out.println("age is " + age + ", name is" + name);
System.out.println("Handler--->" + Thread.currentThread().getId());
System.out.println("handlerMessage");
Toast.makeText(HandlerTest2.this,"在分线程中运行", 3000).show();
}
}
}
不是说Toast中只用在主线程中才能执行么?为啥这里的Toast在分线程中也能执行呢?

解决方案 »

  1.   

    是分线程的,两个的System.out.println("Handler--->" + Thread.currentThread().getId())输出不一样的。
    HandlerThread handlerThread = new HandlerThread("handler_thread");handlerThread.start();开的分线程。
      

  2.   

    这个是异步线程.这里的handleMessage其实是Ui主线程调用的.
    同步任务   handler  中的复写的方法都是主线程调用的.通过分线程  发送消息  通知主线程收到消息,然后调用handleMessage方法.希望对你有所帮助
      

  3.   

    但是在handlerThread()内部,输出的System.out.println("Handler--->" +Thread.currentThread().getId())不一样,这内部应该是分线程么?
      

  4.   

    貌似我在另外一个帖子里面说过了,UI只能在创建他的UI中执行,我们说的UI只能在主线程中,是activity的UI只能在activity的thread中执行,最好的方法是读一下dialog的代码,看看,里面有mUiThread的变量,取的是current thread.
      

  5.   

    谢谢哈,但是handleMessage()内部说输出的System.out.println("Handler--->" + Thread.currentThread().getId())是不一样的,应该是分线程调用的吧。
      

  6.   

    HandlerThread,是有自己的looper的thread,所以你可以把handler attach到他的thread上去。
      

  7.   

    # 这肯定是出现在两个线程中,因为你申明
    MyHandler myHandler = new MyHandler(handlerThread.getLooper());
    的时候知名了其消息栈。# "不是说Toast中只用在主线程中才能执行么?" 有这样的说法么?
    你可以尝试在onCreate里面写这样的代码:
    for(int i=0;i<1000;i++){
    Toast.makeText(HandlerTest2.this,"在分线程中运行", 3000).show();
    }
    finish();
    return;
    你会发现你的app退出了很久之后,toast还在不断刷, 我觉得toast是系统单独管理的一个东西,和当前线程不一定有啥关系。 (感觉而已,未经测试)
      

  8.   


    对啊,这个意思我明白。这个时候“handler attach到他的thread上去”,所有handler就在分线程中了呢,就应该不能Toast,可在上面的handlemessage()函数中为啥还能实现Toast方法呢?
      

  9.   

    我刚说的:貌似我在另外一个帖子里面说过了,UI只能在创建他的UI中执行,我们说的UI只能在主线程中,是activity的UI只能在activity的thread中执行,最好的方法是读一下dialog的代码,看看,里面有mUiThread的变量,取的是current thread.
      

  10.   

    handleMessages是handler中的方法,也是在Handler的Thread中执行。你说呢?
      

  11.   


    我也是这意思,System.out.println("Activity-->" + Thread.currentThread().getId());System.out.println("Handler--->" + Thread.currentThread().getId())
    这俩的输出就不一样啊???
      

  12.   


    首先楼主的Toast是在handlerThread线程中运行的,这点毫无疑问。现在问题的关键是
    Toast是否能在非UI线程中运行,作了个测试代码如下:
    Thread thread=new Thread(new Runnable() {

    @Override
    public void run() {
    // TODO Auto-generated method stub
    Looper.prepare(); 
    try{
        Toast.makeText(MyAndroidActivity.this, "test!", 3000).show();
    }catch (Exception e) {
    // TODO: handle exception}
    }
    });
    thread.start();如果不加Looper.prepare(); 会抛RuntimeException:Can't create 
    handler inside thread that has not called Looper.prepare(),说明:
    Toast中使用了Handler机制,由于android只能在UI线程中更新UI,所以
    猜想Toast最终是通过Handler在UI线程中更新的,具体原理还不太清楚。
    建议楼主把HandlerThread的代码贴出来,一起分析下
      

  13.   

    Toast中有一个mHandler = new Handler();
    建议去看看Handler中的代码,
    mLooper = Looper.myLooper();
      

  14.   

    说白了,就是在那个线程中创建的thread,就只能在哪里继续搞
      

  15.   


    我说的抽象点吧!  希望你能理解
    系统的更新  在android中分为逻辑更新,和ui更新     
    我们的单机事件  等等监听  都是逻辑更新方法
    android系统调用完逻辑更新方法后,会自动调用ui更新方法
    自己的子线程,更新完逻辑后,并不会通知系统更新ui.
    handler机制可以.
    handler连的handleMessage执行后,会执行ui更新方法.逻辑更新后面紧跟着ui更新方法.我们只能在   android已经写死了的ui更新前面  加上逻辑更新.例如  单击事件   后面   会有ui更新. 我们在单击事件里面作用一切有关ui的操作都会更新.
    handler机制同样如此.如果在你自己的线程中更新了逻辑,    底层在绘制绘制画面的时候,会验证当前的画面和数据是否还是一致.
    不一致会抛出异常.逻辑更新和画面更新  在android系统中是按照顺序成对出现的.  只能在规定的地方执行逻辑更新.
    否则就异常.handler的确不是ui主线程.但是运行完后,会通知ui线程画面更新.  你可以理解为主线程.我只能说到这里.在不懂,就没办法了
      

  16.   

    在举个例子把.在自定义view中  我们需要用view.postInvalidate()来通知onDraw方法来画图.道理是一样的.只是,既然是自定义,自由度高一些.不会有一些验证.
      

  17.   

    可以写一套自己的ACTION动作模式在更新所有有关ui的逻辑.然后在handleMessage中有switch();来判断当前动作.通过改变当前动作来达到效果. 执行完动作后,将当前动作更改为无动作.那么我们就可以在任何地方更新线程了.
      

  18.   

    考虑一下Activity中的runOnUiThread()是否可行
      

  19.   

    谢谢哈,再求助下另外一个问题呢,
    我想实现一个功能:开通socket,接受从某节点连续传入的内容(文字类的)。接收下来后,在函数的内部,对内容的相似度进行比较,当然也要统计该节点的所传输的流量变化。流量的变化的计算方法:d{g(t)}={g(t)-g(t-τ)}/τ,其中g(t)是该节点当前时刻的流量,g(t-τ)前τ时刻的流量。相似度的比较:sim=|e-e'|, 其中e是当前时刻所接收的内容,e'是前一时刻接收的内容。
    这里就有问题:1 我该怎么统计前后流量的变化呢?
                  2 又该怎么实现内容的相互减的操作呢,文字怎么能够相减呢,又不是数字?
    希望大侠帮个忙呢,呵呵!!!!