Handler简介以及一个使用简例

Handler的作用:

当我们需要在处理耗时的操作时,必定要在子线程中处理不然便会把主线程卡死。而当耗时的操作完成后,需要更新UI而子线程不能更新UI,因为UI访问是没有加锁的,在多个线程中访问UI是不安全的,如果有多个子线程都去更新UI,会导致界面不断改变而混乱不堪。

这时就需要使用Handler来处理,Handler能帮我们很容易的把任务(在子线程处理)切换回它所在的线程。简单理解,Handler就是解决线程和线程之间的通信的。


话不多说,让我们直接从API文档来看看Handler类中的几个核心方法的用法。

博主的英语水平实在不咋地,所以如果翻译有误,还请见谅,


一:SendMessageXXX方法:

这一类方法在Handler源码中可以看出这些方法都最终调用了

SendMessageAtTime(Message msg,long uptimeMills)方法:

这个方法使一个Message在经过uptimeMills时间后进入Message队列,会为程序的执行造成额外的时间开销。你将会在创造对应Handler的线程中获得这个Message,在HandleMessage(Message msg)中获得msg对象从而实现线程与线程的信息交互。


二:obtainMessage(XXX)

从消息池中获取一个Message对象,如果有输入参数对应输入msg中的what,arg1,arg2和obj。

相比new Message,方法不需要重新开辟一空间。并且obtainMessage可以循环利用


三:removeMessgae(XXX)

在消息池中删除具有对应标签what或者对象obj的Message对象。


四:HandleMessage(Message msg)

这是一个空方法,在子类中重写这个方法可以确定在接受到Message之后做的操作。


接下来是一个运用Handler的简单例子的源代码以及最终效果:

http://v.youku.com/v_show/id_XMzA4NzQ1MjUzNg==.html

package com.imooc.myapplication;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.lang.ref.WeakReference;
import java.util.Random;


public class DiglettActivity extends AppCompatActivity implements View.OnClickListener,View.OnTouchListener{

    public  static final int CODE = 123;
    private TextView mResultTextView;
    private ImageView mDiglettImageView;
    private  Button mStarrButton;
    private int Xposition,Yposition;

    private  int mTotalCount=0;
    private  int mSuccessCount=0;

    public static final int MAX_COUNT = 10;
    public final DiglettHandler mHandler = new DiglettHandler(this);
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_diglett);
        initView();
        setTitle("打地鼠");

    }

    private void initView(){
        mResultTextView = (TextView)findViewById(R.id.text_view);
        mDiglettImageView = (ImageView)findViewById(R.id.image_view);
        mStarrButton = (Button)findViewById(R.id.start_button);

        mStarrButton.setOnClickListener(this);
        mDiglettImageView.setOnTouchListener(this);
    }

    @Override
    public void onClick(View v){
        switch (v.getId()){
            case  R.id.start_button:
                start();
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 0; i <=MAX_COUNT; i++) {
                            next(0);
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }).start();
                break;
        }

    }
    private  void  start(){
        mResultTextView.setText("开始啦");
        mStarrButton.setText("游戏中.....");
        mStarrButton.setEnabled(false);
    }
    private  void  next(int delayTime){

        Xposition = new Random().nextInt(600);
        Yposition = new Random().nextInt(1000);
        Message message = Message.obtain();
        message.what =CODE;
        message.arg1 = Xposition;
        message.arg2 = Yposition;
        mHandler.sendMessageDelayed(message,delayTime);
        mTotalCount ++;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(v.getId() == R.id.image_view) {
            mDiglettImageView.setSelected(true);
            mSuccessCount++;
            mResultTextView.setText("捉到了" + mSuccessCount + "只,共" + MAX_COUNT + "只.");
            mDiglettImageView.setEnabled(false);
        }
        return false;
    }

    public class DiglettHandler extends Handler{
      public  final WeakReference mWeakReference;

        public  DiglettHandler(DiglettActivity activity){
            mWeakReference = new WeakReference (activity);

        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            DiglettActivity activity = (DiglettActivity) mWeakReference.get();
            switch (msg.what){
                case CODE:
                    mDiglettImageView.setSelected(false);
                    if (activity.mTotalCount >MAX_COUNT){
                        //Update UI
                        activity.clear();
                        Toast.makeText(activity,"地鼠打完了!",Toast.LENGTH_LONG).show();
                        return;
                    }
                    int xposition = msg.arg1;
                    int yposition = msg.arg2;
                    activity.mDiglettImageView.setX(xposition);
                    activity.mDiglettImageView.setY(yposition);
                    activity.mDiglettImageView.setVisibility(View.VISIBLE);
                    mDiglettImageView.setEnabled(true);
                    break;
            }
        }
    }
    private  void clear(){
        mTotalCount = 0;
        mSuccessCount = 0;
        mDiglettImageView.setVisibility(View.GONE);
        mStarrButton.setText("点击开始");
        mStarrButton.setEnabled(true);

    }
}

程序的主要逻辑其实很简单。在点击开始游戏之后,开启子线程生成地鼠(调用next方法)并进行休眠(调用sleep)模拟耗时操作,此时子线程处于休眠状态。

而next中调用了mDiglettHandler对象的SendMessageDelayed(msg,time)方法,把地鼠信息(msg)传出去,与此同时将启动在子类DiglettHandler类中的HandlerMessage方法更新UI,从而实现子线程与主线程的通信。

在DiglettHandler子类中大家会发现这么几行看似奇怪的代码这是怎么回事呢?

      public  final WeakReference mWeakReference;

        public  DiglettHandler(DiglettActivity activity){
            mWeakReference = new WeakReference (activity);

        }

这涉及到Java中的弱引用WeakReference

       如果一个对象只涉及弱引用,那就类似可有可无的生活用品,在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现只具有若引用的对象,不管当前内存空间是否足够,都会回收它的内存,不过由于垃圾回收器是一个优先级很低的线程,因此不一定能够马上发现那些只具有弱引用的对象。

       我们常用内部类的Handler中使用Activity弱引用,可以起到防止内存泄漏的作用。


       与Handler异步操作类似的还有AsyncTask类,而这个类也是通过Handler来包装的。


总结:在处理耗时操作时,一般都是在子线程处理。但是只有在主线程中才能更新UI,在子线程中并不能更新UI。
此时就需要Handler进行处理,Handler主要进行线程之间的通信。Handler中有几个核心方法就是:HandlerMessage SendMessage obtainMessage removeMessage 。用这些方法就能很好处理message.
其中最重要的就是重写的HandlerMessage:这个方法是在接受到信息之后做出的相应操作一般涉及更新UI或者数据存储。




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值