TA的每日心情 | 郁闷 2022-8-29 14:43 |
---|
签到天数: 1 天 连续签到: 1 天 [LV.1]测试小兵
|
Android的消息传递机制是另外一种形式的“事件处理”,这种机制主要是为了解决Android应用中多线程的问题,
在Android中不 允许Activity新启动的线程访问该Activity里的UI组件,这样会导致新启动的线程无法改变UI组
件的属性值。但实际开发中,很多地方需要在 工作线程中改变UI组件的属性值,比如下载网络图片、动画等
等。本篇博客主要介绍Handler是如何发送与处理线程上传递来的消息,并讲解 Message的几种传递数据的方
式,最后均会以小Demo来演示。
Handler
Handler, 它直接继承自Object,一个Handler允许发送和处理Message或者Runnable对象,并且会关联
到主线程的MessageQueue 中。每个Handler具有一个单独的线程,并且关联到一个消息队列的线程,就是
说一个Handler有一个固有的消息队列。当实例化一个Handler 的时候,它就承载在一个线程和消息队列的
线程,这个Handler可以把Message或Runnable压入到消息队列,并且从消息队列中取出 Message或Runna
ble,进而操作它们。
Handler主要有两个作用:
在工作线程中发送消息。
在UI线程中获取、处理消息。
上面介绍到Handler可以把一个Message对象或者Runnable对象压入到消息队列中,进而在UI线程中获取
Message或者执行Runnable对象,所以Handler把压入消息队列有两大体系,Post和sendMessage:
Post:Post允许把一个Runnable对象入队到消息队列中。它的方法有:post(Runnable)、postAtTime(Runn
able,long)、postDelayed(Runnable,long)。
sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。它的方法 有:s
endEmptyMessage(int)、sendMessage(Message)、 sendMessageAtTime(Message,long)、sendMessageDela
yed(Message,long)。
从上面的各种方法可以看出,不管是post还是sendMessage都具有多种方法,它们可以设定Runnable对
象和Message对象被入队到消息队列中,是立即执行还是延迟执行。
Post
对于Handler的Post方式来说,它会传递一个Runnable对象到消息队列中,在这个Runnable对象中,重写
run()方法。一般在这个run()方法中写入需要在UI线程上的操作。
在Handler中,关于Post方式的方法有:
boolean post(Runnable r):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,
立即执行。
boolean postAtTime(Runnable r,long uptimeMillis):把一个Runnable入队到消息队列中,UI线程从消息队
列中取出这个对象后,在特定的时间执行。
boolean postDelayed(Runnable r,long delayMillis):把一个Runnable入队到消息队列中,UI线程从消息队
列中取出这个对象后,延迟delayMills秒执行
void removeCallbacks(Runnable r):从消息队列中移除一个Runnable对象。
下面通过一个Demo,讲解如何通过Handler的post方式在新启动的线程中修改UI组件的属性:
复制代码
复制代码
- 1 package com.bgxt.datatimepickerdemo;
- 2
- 3 import android.app.Activity;
- 4 import android.os.Bundle;
- 5 import android.os.Handler;
- 6 import android.view.View;
- 7 import android.widget.Button;
- 8 import android.widget.TextView;
- 9
- 10 public class HandlerPostActivity1 extends Activity {
- 11 private Button btnMes1,btnMes2;
- 12 private TextView tvMessage;
- 13 // 声明一个Handler对象
- 14 private static Handler handler=new Handler();
- 15
- 16 @Override
- 17 protected void onCreate(Bundle savedInstanceState) {
- 18 super.onCreate(savedInstanceState);
- 19 setContentView(R.layout.message_activity);
- 20
- 21 btnMes1=(Button)findViewById(R.id.btnMes1);
- 22 btnMes2=(Button)findViewById(R.id.btnMes2);
- 23 tvMessage=(TextView)findViewById(R.id.tvMessage);
- 24 btnMes1.setOnClickListener(new View.OnClickListener() {
- 25
- 26 @Override
- 27 public void onClick(View v) {
- 28 // 新启动一个子线程
- 29 new Thread(new Runnable() {
- 30 @Override
- 31 public void run() {
- 32 // tvMessage.setText("...");
- 33 // 以上操作会报错,无法再子线程中访问UI组件,UI组件的属性必须在UI线程中访问
- 34 // 使用post方式修改UI组件tvMessage的Text属性
- 35 handler.post(new Runnable() {
- 36 @Override
- 37 public void run() {
- 38 tvMessage.setText("使用Handler.post在工作线程中发送一段执行到消息队列中,在主线程中执行。");
- 39 }
- 40 });
- 41 }
- 42 }).start();
- 43 }
- 44 });
- 45
- 46 btnMes2.setOnClickListener(new View.OnClickListener() {
- 47
- 48 @Override
- 49 public void onClick(View v) {
- 50 new Thread(new Runnable() {
- 51 @Override
- 52 public void run() {
- 53 // 使用postDelayed方式修改UI组件tvMessage的Text属性值
- 54 // 并且延迟3S执行
- 55 handler.postDelayed(new Runnable() {
- 56
- 57 @Override
- 58 public void run() {
- 59 tvMessage.setText("使用Handler.postDelayed在工作线程中发送一段执行到消息队列中,在主线程中延迟3S执行。");
- 60
- 61 }
- 62 }, 3000);
- 63 }
- 64 }).start();
- 65
- 66 }
- 67 });
- 68 }
- 69 }
复制代码
复制代码
复制代码
效果展示:
有一点值得注意的是,对于Post方式而言,它其中Runnable对象的run()方法的代码,均执行在UI线程上,
所以对于这段代码而言, 不能执行在UI线程上的操作,一样无法使用post方式执行,比如说访问网络,下面
提供一个例子,使用post方式从互联网上获取一张图片,并且显示在 ImageView中。
复制代码
复制代码
- 1 package com.bgxt.datatimepickerdemo;
- 2
- 3 import org.apache.http.HttpResponse;
- 4 import org.apache.http.client.HttpClient;
- 5 import org.apache.http.client.methods.HttpGet;
- 6 import org.apache.http.impl.client.DefaultHttpClient;
- 7 import org.apache.http.util.EntityUtils;
- 8
- 9 import android.app.Activity;
- 10 import android.app.ProgressDialog;
- 11 import android.graphics.Bitmap;
- 12 import android.graphics.BitmapFactory;
- 13 import android.os.Bundle;
- 14 import android.os.Handler;
- 15 import android.view.View;
- 16 import android.widget.Button;
- 17 import android.widget.ImageView;
- 18
- 19 public class HandlerPostActivity2 extends Activity {
- 20 private Button btnDown;
- 21 private ImageView ivImage;
- 22 private static String image_path = "http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg";
- 23 private ProgressDialog dialog;
- 24 // 一个静态的Handler,Handler建议声明为静态的
- 25 private static Handler handler=new Handler();
- 26 @Override
- 27 protected void onCreate(Bundle savedInstanceState) {
- 28 super.onCreate(savedInstanceState);
- 29 setContentView(R.layout.asynctask_activity);
- 30
- 31 btnDown = (Button) findViewById(R.id.btnDown);
- 32 ivImage = (ImageView) findViewById(R.id.ivSinaImage);
- 33
- 34 dialog = new ProgressDialog(this);
- 35 dialog.setTitle("提示");
- 36 dialog.setMessage("正在下载,请稍后...");
- 37 dialog.setCancelable(false);
- 38
- 39 btnDown.setOnClickListener(new View.OnClickListener() {
- 40 @Override
- 41 public void onClick(View v) {
- 42 // 开启一个子线程,用于下载图片
- 43 new Thread(new MyThread()).start();
- 44 // 显示对话框
- 45 dialog.show();
- 46 }
- 47 });
- 48 }
- 49
- 50 public class MyThread implements Runnable {
- 51
- 52 @Override
- 53 public void run() {
- 54 // 下载一个图片
- 55 HttpClient httpClient = new DefaultHttpClient();
- 56 HttpGet httpGet = new HttpGet(image_path);
- 57 HttpResponse httpResponse = null;
- 58 try {
- 59 httpResponse = httpClient.execute(httpGet);
- 60 if (httpResponse.getStatusLine().getStatusCode() == 200) {
- 61 byte[] data = EntityUtils.toByteArray(httpResponse
- 62 .getEntity());
- 63 // 得到一个Bitmap对象,并且为了使其在post内部可以访问,必须声明为final
- 64 final Bitmap bmp=BitmapFactory.decodeByteArray(data, 0, data.length);
- 65 handler.post(new Runnable() {
- 66 @Override
- 67 public void run() {
- 68 // 在Post中操作UI组件ImageView
- 69 ivImage.setImageBitmap(bmp);
- 70 }
- 71 });
- 72 // 隐藏对话框
- 73 dialog.dismiss();
- 74 }
- 75 } catch (Exception e) {
- 76 e.printStackTrace();
- 77 }
- 78 }
- 79
- 80 }
- 81 }
复制代码
|
|