Android--HandlerThread详解

一、使用场景

举个例子,数据实时更新,我们每10秒需要切换一下显示的数据,如果我们将这种长时间的反复调用操作放到UI线程中,虽说可以执行,但是这样的操作多了之后,很容易会让UI线程卡顿甚至崩溃。 于是,就必须在子线程中调用这些了。 HandlerThread继承自Thread,一般适应的场景,便是集Thread和Handler之所长,适用于会长时间在后台运行,并且间隔时间内(或适当情况下)会调用的情况,比如上面所说的实时更新。

二、HandlerThread用法

//步骤1:创建HandlerThread的实例对象=已经创建了一个新线程
//参数=线程名字,作用是标记该线程
HandlerThread mHandlerThread = new HandlerThread("handlerThread");

//步骤2:启动线程
mHandlerThread.start();

//步骤3:创建工作线程Handler,实现消息处理的操作,并与其他线程进行通信
Handler mHandler = new Handler( handlerThread.getLooper() ) {
            @Override
            public boolean handleMessage(Message msg) {
                //消息处理
                return true;
            }
        });

//步骤4:结束线程,即停止线程的消息循环
mHandlerThread.quit();

三、HandlerThread类的源码
public class HandlerThread extends Thread {
    //线程优先级
    int mPriority;
    //当前线程id
    int mTid = -1;
    //当前线程持有的Looper对象
    Looper mLooper;

/*分析1:如何创建新线程*/

   //HandlerThread在进行实例化的同时,已经创建了一个新线程,这说明猫腻是在构造方法
   //HandlerThread类有两个构造方法
   //不同之处就是设置当前线程的优先级参数。你可以根据自己的情况来设置优先级,也可以使用默认优先级。

    //方法1. 默认优先级
    public HandlerThread(String name) {
        //通过调用父类默认的方法创建线程
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

    //方法2. 根据需求设置优先级-构造方法带优先级参数
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

/*分析2:如何创建Handler*/

    //步骤1:通过run()方法作好创建Handler的准备
    @Override
    public void run() {
        //获得当前线程的id
        mTid = Process.myTid();
        //创建了一个Looper对象并初始化了一个MessageQueue
        Looper.prepare();
        //持有锁机制来获得当前线程的Looper对象
        synchronized (this) {
            mLooper = Looper.myLooper();

            //通知getLooper方法中的wait当前线程已经创建mLooper对象成功,让wait结束等待
            notifyAll();
        }
        //设置当前线程的优先级
        Process.setThreadPriority(mPriority);
        //在线程循环之前做一些准备工作
        //该方法实现体是空的,子类可以实现该方法,也可以不实现。
        onLooperPrepared();
        //进行消息循环,即不断从MessageQueue中取消息和派发消息
        Looper.loop();
        mTid = -1;
    }
}

    //线程循环前的准备工作
    protected void onLooperPrepared() {
    }

    //步骤2:在创建Handler时调用了getLooper()
    //Handler mHandler = new Handler( handlerThread.getLooper())
    //getLooper()的作用主要是获得当前HandlerThread线程中的mLooper对象
    public Looper getLooper() {
        //如果线程不是存活的,则直接返回null
        if (!isAlive()) {
            return null;
        } 

        synchronized (this) {
      //首先判断当前线程是否存活
      //如果不是存活的,这直接返回null。
      //其次如果当前线程存活的,在判断线程的成员变量mLooper是否为null,如果为null,说明当前线程已经创建成功,但是还没来得及创建Looper对象
            while (isAlive() && mLooper == null) {
                try {
      //因此,这里会调用wait方法去等待
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        //当run方法中的notifyAll方法调用之后通知当前线程的wait方法结束等待并跳出循环
        //最终getLooper()返回的是我们在run方法中创建的mLooper
        return mLooper;
    }

/*分析3:结束新线程*/

  //Handler有两种让当前线程退出循环的方法:quit() 和 quitSafely()
  //第一种:效率高,但线程不安全
  public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
  //第二种:效率低,但线程安全
  public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }
  • 在获得mLooper对象的时候存在一个同步的问题:只有当线程创建成功并且Looper对象也创建成功之后才能获得mLooper的值,才能将创建的Handler与该Looper绑定
  • 解决方案:在run()中成功创建Looper对象后,立即调用notifyAll()通知 getLooper()中的wait()结束等待,并返回run()中成功创建的Looper对象,使得Handler与该Looper对象绑定


四、实例

import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.text.Html;
import android.widget.TextView;

import com.zhy.blogcodes.R;


public class HandlerThreadActivity extends AppCompatActivity
{

    private TextView mTvServiceInfo;

    private HandlerThread mCheckMsgThread;
    private Handler mCheckMsgHandler;
    private boolean isUpdateInfo;

    private static final int MSG_UPDATE_INFO = 0x110;

    //与UI线程管理的handler
    private Handler mHandler = new Handler();


    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_thread_handler);

        //创建后台线程
        initBackThread();

        mTvServiceInfo = (TextView) findViewById(R.id.id_textview);

    }

    @Override
    protected void onResume()
    {
        super.onResume();
        //开始查询
        isUpdateInfo = true;
        mCheckMsgHandler.sendEmptyMessage(MSG_UPDATE_INFO);
    }

    @Override
    protected void onPause()
    {
        super.onPause();
        //停止查询
        isUpdateInfo = false;
        mCheckMsgHandler.removeMessages(MSG_UPDATE_INFO);

    }

    private void initBackThread()
    {
        mCheckMsgThread = new HandlerThread("check-message-coming");
        mCheckMsgThread.start();
        mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper())
        {
            @Override
            public void handleMessage(Message msg)
            {
                checkForUpdate();
                if (isUpdateInfo)
                {
                    mCheckMsgHandler.sendEmptyMessageDelayed(MSG_UPDATE_INFO, 1000);
                }
            }
        };


    }

    /**
     * 模拟从服务器解析数据
     */
    private void checkForUpdate()
    {
        try
        {
            //模拟耗时
            Thread.sleep(1000);
            mHandler.post(new Runnable()
            {
                @Override
                public void run()
                {
                    String result = "实时更新中,当前大盘指数:<font color='red'>%d</font>";
                    result = String.format(result, (int) (Math.random() * 3000 + 1000));
                    mTvServiceInfo.setText(Html.fromHtml(result));
                }
            });

        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }

    }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        //释放资源
        mCheckMsgThread.quit();
    }


}

在onCreate中,去创建和启动了HandlerThread,并且关联了一个mCheckMsgHandler。然后我们分别在onResume和onPause中去开启和暂停我们的查询,最后在onDestory中去释放资源。

这样就实现了我们每隔5s去服务端查询最新的数据,然后更新我们的UI,当然我们这里通过Thread.sleep()模拟耗时,返回了一个随机数,大家可以很轻易的换成真正的数据接口。




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值