定义
Handler是用来结合线程的消息队列来发送、处理"Message对象"和"Runnable对象"的工具。
每一个Handler实例之后会关联一个线程和该线程的消息队列。也就是说,当你创建一个Handler的时候,从此开始,他就会自动关联到所在的线程/消息队列,然后它就会陆续把Message/Runnable分发到消息队列,并在他们出队的时候处理掉。因为android只允许在主线程中更新UI,Handler的目的就是作为线程通信的桥梁,进而再通过主线程更新UI。使用Handler这种异步回调机制,使我们可以再完成一个很长的任务后再做出相应的通知。
Handler和Message、MessageQueue、Looper之间的关系
Message
Handler接收与处理的消息对象
MessageQueue
消息队列,以先进先出队列形式管理所有的Message,且在初始化Looper对象时会创建一个与之关联的MessageQueue。每个线程最多只有一个MessageQueue。MessageQueue通常都是由Looper来管理,而主线程创建时,会创建一个默认的Looper对象,而Looper对象的创建,将自动创建一个MessageQueue。其他非主线程,不会自动创建Looper。
Looper
每个线程只能够一个Looper,管理MessageQueue,不断从中去除Message分发给对应的Handler处理。
通俗一点讲:当我们的子线程想修改Activity中的UI组件时,我们可以新建一个Handler对象,通过这个对象向主线程发送消息;而我们发送的消息会先到主线程的MessageQueue中进行等待,由Looper按先入先出顺序取出,再根据Message对象的what属性分发给对应的Handler进行处理。
Handler的主要用途
1.推送未来某个时间点将要执行的Message或者Runnable到消息队列
通过Handler+Message的方式更新UI
public class MainActivity extends AppCompatActivity {
private TextView text;
private static final int UPDATE_TEXT = 1; //整型常量用于表示更新TextView这个动作
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.id.activity_main);
text = (TextView) findViewById(R.id.text);
Button chaneText = (Button) findViewById(R.id.change_text);
change_text.setOnClickListener(this);
}
//新增Handler对象,并重写父类的handlerMessage()方法,在这里对具体的Message进行处理
private Handler handler = new Handler(){
public void handleMessage(Message msg){ //收到消息,在HandleMessage()方法中对消息进行处理
switch (msg.what){
case UPDATE_TEXT:
// 在这里进行UI操作,处于主线程中
text.setText("Nice to meet you");
break;
default:
break;
}
}
};
@Override
public void onClick(View v){
switch(v.getId()){
case R.id.change_text:
new Thread(new Runnable(){
@Override
public void run(){
Message message = new Message();
message.what = UPDATE_TEXT; //将waht字段的值指定为UPDATE_TEXT
handler.sendMessage(message); //调用Handler的sendMessage()方法发送消息
}
}).start();
break;
default:
break;
}
}
}
2.在子线程把需要在另一个线程执行的操作加入到消息队列中去
通过Handler + Message来实现子线程加载图片,在UI线程显示图片
public class ThreadActivity extends AppCompatActivity implements View.OnClickListener {
private ActivityThreadBinding mBinding = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_thread);
// 设置点击事件
mBinding.clickBtn.setOnClickListener(this);
mBinding.resetBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
// 响应load按钮
case R.id.clickBtn:
// 开启一个线程
new Thread(new Runnable() {
@Override
public void run() {
// 在Runnable中进行网络读取操作,返回bitmap
final Bitmap bitmap = loadPicFromInternet();
// 在子线程中实例化Handler同样是可以的,只要在构造函数的参数中传入主线程的Looper即可
Handler handler = new Handler(Looper.getMainLooper());
// 通过Handler的post Runnable到UI线程的MessageQueue中去即可
handler.post(new Runnable() {
@Override
public void run() {
// 在MessageQueue出队该Runnable时进行的操作
mBinding.photo.setImageBitmap(bitmap);
}
});
}
}).start();
break;
case R.id.resetBtn:
mBinding.photo.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.default_pic));
break;
}
}
/***
* HttpUrlConnection加载图片,不多说
* @return
*/
public Bitmap loadPicFromInternet() {
Bitmap bitmap = null;
int respondCode = 0;
InputStream is = null;
try {
URL url = new URL("https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=1421494343,3838991329&fm=23&gp=0.jpg");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(10 * 1000);
connection.setReadTimeout(5 * 1000);
connection.connect();
respondCode = connection.getResponseCode();
if (respondCode == 200) {
is = connection.getInputStream();
bitmap = BitmapFactory.decodeStream(is);
}
} catch (MalformedURLException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "访问失败", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return bitmap;
}
}
很想高飞,但我不能;不想天空,剩我一人。