做了也快2年的android了,发现android的机制还不是很了解,这几天看了一下这方面的介绍,总结一下handler的用法和机制。

handler就是用来线程之间通信的,主线程与子线程。一般的用法是,子线程通知ui主线程的handler去刷新ui操作。最近遇到一些人,问能不能主线程去通知子线程的handler。

当然是可以的。贴一个例子

 

package cc.c;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.widget.TextView;
/**
 * Demo描述:
 * 
 * 示例步骤如下:
 * 1 子线程给子线程本身发送消息
 * 2 收到1的消息后,子线程给主线程发送消息
 * 3 收到2的消息后,主线程给子线程发送消息
 * 
 * 为实现子线程给自己本身发送消息,关键还是在于构造Handler时传入的Looper.
 * 在此就传入该子线程自己的Looper即调用Looper.myLooper(),代码如下:
 * Looper.prepare();
 * mHandlerTest1=new HandlerTest1(Looper.myLooper());
 * Looper.loop();
 * 
 * 所以当mHandlerTest1.sendMessage(message);发送消息时
 * 当然是发送到了它自己的消息队列.
 * 
 * 当子线程中收到自己发送的消息后,可继续发送消息到主线程.此时只要注意构造
 * Handler时传入的Handler是主线程的Handler即可,即getMainLooper().
 * 其余没啥可说的.
 * 
 * 
 * 在主线程处理消息后再发消息到子线程
 * 
 * 
 * 其实这些线程间发送消息,没有什么;关键还是在于构造Handler时传入谁的Looper.
 *
 */
public class MainActivity extends Activity {
    private TextView mTextView;
    private HandlerTest1 mHandlerTest1;
    private HandlerTest2 mHandlerTest2;
    private int counter=0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        init();
    }

    private void init() {
        mTextView = (TextView) findViewById(R.id.textView);
        
        //1 子线程发送消息给本身
        new Thread() {
            public void run() {
                Looper.prepare();
                mHandlerTest1=new HandlerTest1(Looper.myLooper());
                Message message = new Message();
                message.obj = "子线程发送的消息Hi~Hi";
                mHandlerTest1.sendMessage(message);
                Looper.loop();
            };
        }.start();
        
    }

    private class HandlerTest1 extends Handler {

        private HandlerTest1(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            System.out.println("子线程收到:" + msg.obj);
            
            //2  收到消息后可再发消息到主线程
            mHandlerTest2=new HandlerTest2(getMainLooper());
            Message message = new Message();
            message.obj = "O(∩_∩)O";
            mHandlerTest2.sendMessage(message);
        }
    }
    
    private class HandlerTest2 extends Handler {

        private HandlerTest2(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            mTextView.setText("在主线程中,收到子线程发来消息:" + msg.obj);
            
            //3  收到消息后再发消息到子线程
            if (counter==0) {
                Message message = new Message();
                message.obj = "主线程发送的消息Xi~Xi";
                mHandlerTest1.sendMessage(message);
                counter++;
            }
            
        }
    }

}

 

这个就很好的展示了,子线程主线程都是可以有handler,可以互相传递消息的。必须要明确的是handler必须要绑定一个looper。
但是区别在于,子线程需要做
Looper.prepare();
Looper.loop();
这两个方法,而主线程不需要。因为主线程在启动的时候会初始化looper,如下:

 Android程序的运行入口点可以认为是android.app.ActivityThread类的main()方法(源码2.3.3):

lua可以在子线程上跑吗 子线程looper_主线程

public static final void main(String[] args) {
        // other codes...

        // 创建主线程循环
        Looper.prepareMainLooper();
        if (sMainThreadHandler == null) {
            sMainThreadHandler = new Handler();
        }

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        // other codes...

        // 进入当前线程(此时是主线程)消息循环
        Looper.loop();

        // other codes...

        thread.detach();
        // other codes...
    }

lua可以在子线程上跑吗 子线程looper_主线程

 所以可以看到,如果要有消息循环的话,线程中任何时候都必须要有初始化looper的过程,只不过主线程在启动的时候已经帮我们完成,而子线程需要自己去实现。(需要注意的是,如果我们在ui线程中new handler而不做绑定,那么默认的认为handler是绑定主线程的looper,所以我们就可以想到,ui线程中new handler也可以绑定子线程的looper,即handlerThread的用法)

另外一个是,handlerThread,参考下面的解释:

在上面的总结中指出,Android的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper。事实上Android提供了一个封装好的带有looper的线程类,即为HandlerThread,具体可参见下面的代码:

public class HandlerThreadActivity extends Activity {

    private static final String TAG = "HandlerThreadActivity";

    private HandlerThreadmHandlerThread;

    private MyHandler mMyHandler;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

       // TODO Auto-generatedmethod stub

       super.onCreate(savedInstanceState);

       TextView text = new TextView(this);

       text.setText("HandlerThreadActivity");

       setContentView(text);

      

       Log.d(TAG, "The mainthread id = " +      Thread.currentThread().getId());

      

       //生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能,

       //这个类由Android应用程序框架提供

       mHandlerThread = new HandlerThread("handler_thread");

      

       //在使用HandlerThread的getLooper()方法之前,必须先调用该类的start();

       mHandlerThread.start();

       //即这个Handler是运行在mHandlerThread这个线程中

       mMyHandler = new MyHandler(mHandlerThread.getLooper());

      

       mMyHandler.sendEmptyMessage(1);

    }

   

    private class MyHandler extends Handler {

      

       public MyHandler(Looper looper) {

           super(looper);

       }

 

       @Override

       public void handleMessage(Message msg) {

           Log.d(TAG, "MyHandler-->handleMessage-->threadid = " + Thread.currentThread().getId());

           super.handleMessage(msg);

       }

    }

   

}

 

可以看到在该段代码中,在子线程中有 mHandlerThread = new HandlerThread("handler_thread"),然后在主线程中的hanler是绑定该线程的loooper的,mMyHandler = new MyHandler(mHandlerThread.getLooper());

我的理解的话,HandlerThread与thread的区别不大,因为HandlerThread是继承自thread的,只不过HandlerThread提供了默认的Looper。

 

总结一下:

1、handler是android提供的一种消息循环机制,为多线程提供了很大的帮助,特别是异步获取数据然后刷新ui的操作。

2、handler与looper是共生的,一个线程只有一个looper,只不过有的线程已经做好了初始化looper的操作(ui线程,HandlerThread),而其他子线程需要自己做。

3、handler通过绑定特定线程的looper,可以实现在该线程中向某一个looper发送消息,就可以在这个handler中处理了。如子线程中通过

Looper.prepare();mHandlerTest1=new HandlerTest1(Looper.myLooper());
绑定自己的looper,
也可以mHandlerTest2=new HandlerTest2(getMainLooper());绑定ui的looper都是可以的,
然后主线程中也棒子子线程的looper,就看你如何绑定哪个looper了。