Android--Handler

一:定义
主要接收子线程发送的数据, 并用此数据配合主线程更新UI,用来跟UI主线程交互用。
比如可以用handler发送一个message,然后在handler的线程中来接收、处理该消息,以避免直接在UI主线程中处理事务导致影响UI主线程的其他处理工作,Android提供了Handler作为主线程和子线程的纽带;也可以将handler对象传给其他进程,以便在其他进程中通过handler给你发送事件;还可以通过handler的延时发送message,可以延时处理一些事务的处理。
通常情况下,当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发。如果此时需要一个耗时的操作,例如:联网读取数据,或者读取本地较大的一个文件的时候,不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象,如果5秒钟还没有完成的话,会收到Android系统的一个错误提示”强制关闭”. 而子线程是不能直接操作UI!
此时就需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,当子线程中有涉及到操作UI的操作时,就会对主线程产生危险,也就是说,更新UI只能在主线程中更新,在子线程中操作是危险的. 这个时候,Handler就出现了来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传递)Message对象,(里面包含数据), 把这些消息放入主线程队列中,配合主线程进行更新UI。

二:特点:
handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),它有两个作用:
(1)安排消息或Runnable 在某个主线程中某个地方执行;
(2)安排一个动作在不同的线程中执行。
Handler中分发消息的一些方法

post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)

以上post类方法允许你排列一个Runnable对象到主线程队列中,
sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待接收,然后更新相关数据。

三:使用

—-1:简单例子

public class FristActivity extends AppCompatActivity implements View.OnClickListener {
    TextView textView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_frist);
        textView = (TextView) findViewById(R.id.textMsg);
        findViewById(R.id.sendBtn).setOnClickListener(this);
    }


    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 2:
                    textView.setText("msg.what=2");
                    break;
            }
            super.handleMessage(msg);
        }
    };


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.sendBtn:
                Message message = new Message();
                message.what = 2;
                handler.sendMessage(message);
                break;
        }
    }
}

—-2:发送一个空消息

 //1 注意第一种与第二种参数不一样的问题
 Message message = new Message();
 message.what = 0;
 handler.sendMessage(message);
 //2:比第一种方式更节省运行内存
 Message message1 = handler.obtainMessage();
 message1.arg1 = 0;
 handler.sendMessage(message1);
//3直接调用系统提供的方法
 handler.sendEmptyMessage(0);

—-3:稍微复杂一点的例子:

public class OneActivity extends AppCompatActivity {
TextView textView;

MyHandler myHandler;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_frist);
    textView = (TextView) findViewById(R.id.textMsg);
    myHandler = new MyHandler();
    MyThred m = new MyThred();
    new Thread(m).start();
}


class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        Bundle bundle = msg.getData();
        String msgString = bundle.getString("msg");
        textView.setText(msgString);
    }
}


class MyThred extends Thread {
    @Override
    public void run() {
        super.run();
        try {
            Thread.sleep(2000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Message message = myHandler.obtainMessage();
        Bundle bundle = new Bundle();
        bundle.putString("msg", "msg=====null");
        message.setData(bundle);

        myHandler.sendMessage(message);
    }
}

}
—-4:从消息队列中移除<避免重复发送消息>
myHandler.removeMessages(int what);
myHandler.removeMessages(int what,Object o);
myHandler.removeCallbacksAndMessages(Object o);
myHandler.removeCallbacks(Runnable r,Object o);
myHandler.removeMessages(int what);
myHandler.removeCallbacks(Runnable r);

—-5:<简单操作可以使用本例子>
运行结果是每隔三秒就打印出来数据。
—-是因为实现了Runable接口,runable对象进入了空的消息队列即被立即执行Run方法,而在Run方法内部,在三秒之后将其再次发送到消息队列里面。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
      findViewById(R.id.button).setOnClickListener(this);
        findViewById(R.id.button2).setOnClickListener(this);
    }


    Handler handler = new Handler();

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            Log.i("start", "start");
            handler.postDelayed(runnable, 3000);
        }
    };

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button:
                handler.post(runnable);
                break;
            case R.id.button2:
               handler.removeCallbacks(runnable);
                break;
        }
    }
}

总结:
post方法虽然发送的是一个实现了Runnable接口的类对象,但是它并非创建了一个新线程,而是执行了该对象中的run方法。也就是说,整个run中的操作和主线程处于同一个线程。

—-6:

<
 HandlerThread就是可以处理消息循环的线程,它是一个拥有Looper的线程,可以处理消息循环;说Handler和一个线程绑定,倒不如说HandlerLooper是一一对应的
>

–1:获取当前线程的ID

Thread.currentThread().getId()

–2:HandlerThread
–3:创建一个HandlerThread,即创建了一个包含Looper的线程<在使用HandlerThread的getLooper()方法之前,必须先调用该类的start(),同时开启一个新线程>

HandlerThread       handlerThread = new HandlerThread("leochin.com");
handlerThread.start();       //创建HandlerThread后一定要记得start()

–4:获取HandlerThread的Looper

Looper looper =  handlerThread.getLooper();

–5:创建Handler,通过Looper初始化

Handler handler = new Handler(looper);

通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。
如果想让HandlerThread退出,则需要调用handlerThread.quit();

在使用sendMessage方法传递消息或者使用post方法传递Runnable对象时,就会把它们传递到与handler对象绑定的处于另外一个线程的消息队列中,它们将在另外的消息队列中被处理。而主线程还会在发送操作完成时候继续进行,不会影响当前的操作。<参考前面例子>

–7:重点:
在主线程通过Handler handler = new Handler();即使用默认构造函数构造Handler时,是默认使用主线程的Looper对象,通过这种方式构造的Handler是属于主线程的,也就是Handler和Looper是绑定在一起的,如果构造Handler时指定一个新线程的Looper对象,则该Handler对象是属于该子线程的。

  mHandler=new Handler();
    mHandler.post(new Runnable(){
    void run(){

     }
    });

这个线程其实是在UI线程之内运行的,并没有新建线程!
常见的新建线程的方法是:

    Thread thread = new Thread();
    thread.start();

    HandlerThread thread = new HandlerThread("string");
    thread.start();

—-8:
UI线程它已经建立了Looper,因为主线程默认有一个自己的Looper对象和Message对象,非主线程默认是没有自己的Looper,需要自己去创建:通过Looper.prepare创建一个Looper对象,以及 Looper.loop()创建消息循环队列;在新线程(非主线程)中创建Handler对象,有两种方法实现:
1–创建Handler之前通过 Looper.prepare()方法创建Looper对象;<非主线程>

Looper.prepare();// 创建该线程的Looper对象,用于接收消息,在非主线程中是没有looper的所以在创建handler前一定要使用prepare()创建一个Looper  
Handler myThreadHandler = new Handler(){};

2–使用主线程的Looper对象,因为每个主线程默认已经创建了自己的Looper对象;

<Looper.getMainLooper()><主线程>
Handler threadMainLoopHandler = new Handler(Looper.getMainLooper()){};

—-9:
在一个新线程中要创建一个Handler就需要这样写:

 class MyThread extends Thread {
                public void run() {
                        myThreadHandler = new Handler() {
                                public void handleMessage(Message msg{

                                }
                        };
                        Looper.myLooper().loop();//建立一个消息循环,该线程不会退出
                }
        }

四:源码分析:
—-MessageQueue队列
—–队列属于某一个Looper
—–每个Looper对象通过ThreadLocal.set(new Looper())跟一个Thread绑定
—-Looper对象所属的线程在Looper.Loop方法中循环执行从MessageQueue队列读取Message对象,并把Message对象交由Handler处理,调用Handler的dispatchMessage方法

参考:http://blog.csdn.net/stonecao/article/details/6417364

五:源码:

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

dispatchMessage定义看出,如果Message对象自带callback对象,handler不会执行handleMessage方法而是执行message.callback中定义的run方法,当然callback还是在handler关联的looper所绑定的线程中执行的。实际上Handler.post(Runnable r)方法就是把r添加到一个msg.callback中。

—-1:

Handler handler = new Handler();

Message message = Message.obtain(handler, new Runnable() {
    @Override
    public void run() {

    }
});
handler.sendMessage(message);

—-2:

Handler handler = new Handler();

handler.post(new Runnable() {
    @Override
    public void run() {

    }
});

以上两种方式来说,代码功能没有区别!
注意:本文里面一些创建Handler的方式并不是都说最好的,有些只是为了演示简化步骤,故在使用过程中,请注意按照最优的创建方式创建对象并使用!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值