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来包装的。