每个Android应用程序都运行在一个dalvik虚拟机进程中,进程开始的时候会启动一个主线程(MainThread),主线程负责处理和ui相关的事件,因此主线程通常又叫UI线程。而由于Android采用UI单线程模型,所以只能在主线程中对UI元素进行操作。如果在非UI线程直接对UI进行了操作,则会报错:

CalledFromWrongThreadException:only the original thread that created a view hierarchy can touch its views

Android为我们提供了消息循环的机制,我们可以利用这个机制来实现线程间的通信。那么,我们就可以在非UI线程发送消息到UI线程,最终让Ui线程来进行ui的操作。


对于运算量较大的操作和IO操作,我们需要新开线程来处理这些繁重的工作,以免阻塞ui线程。

例子:下面我们以获取ITEYE logo的例子,演示如何使用Thread+Handler的方式实现在非UI线程发送消息通知UI线程更新界面。

public class ThreadHandlerActivity extends Activity {    /** Called when the activity is first created. */private static final int MSG_SUCCESS = 0;//获取图片成功的标识private static final int MSG_FAILURE = 1;//获取图片失败的标识private ImageView mImageView;private Button mButton;private Thread mThread;private Handler mHandler = new Handler() {public void handleMessage (Message msg) {//此方法在ui线程运行switch(msg.what) {case MSG_SUCCESS:mImageView.setImageBitmap((Bitmap) msg.obj);//imageview显示从网络获取到的logoToast.makeText(getApplication(), getApplication().getString(R.string.get_pic_success), Toast.LENGTH_LONG).show();break;case MSG_FAILURE:Toast.makeText(getApplication(), getApplication().getString(R.string.get_pic_failure), Toast.LENGTH_LONG).show();break;}}};    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        mImageView= (ImageView) findViewById(R.id.imageView);//显示图片的ImageView        mButton = (Button) findViewById(R.id.button);        mButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if(mThread == null) {mThread = new Thread(runnable);mThread.start();//线程启动}else {Toast.makeText(getApplication(), getApplication().getString(R.string.thread_started), Toast.LENGTH_LONG).show();}}});    }        Runnable runnable = new Runnable() {@Overridepublic void run() {//run()在新的线程中运行HttpClient hc = new DefaultHttpClient();HttpGet hg = new HttpGet("http://www.iteye.com/images/logo.gif");//获取iteye的logofinal Bitmap bm;try {HttpResponse hr = hc.execute(hg);bm = BitmapFactory.decodeStream(hr.getEntity().getContent());} catch (Exception e) {mHandler.obtainMessage(MSG_FAILURE).sendToTarget();//获取图片失败return;}mHandler.obtainMessage(MSG_SUCCESS,bm).sendToTarget();//获取图片成功,向ui线程发送MSG_SUCCESS标识和bitmap对象//mImageView.setImageBitmap(bm); //出错!不能在非ui线程操作ui元素//mImageView.post(new Runnable() {//另外一种更简洁的发送消息给ui线程的方法。////@Override//public void run() {//run()方法会在ui线程执行//mImageView.setImageBitmap(bm);//}//});}};}


<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="fill_parent"android:layout_height="fill_parent">    <Button android:id="@+id/button" android:text="@string/button_name" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button><ImageView android:id="@+id/imageView" android:layout_height="wrap_content"android:layout_width="wrap_content" /></LinearLayout>



为了不阻塞ui线程,我们使用mThread从网络获取了Iteye的LOGO,并用bitmap对象存储了这个Logo的像素信息。


此时,如果在这个线程的run()方法中调用

mImageView.setImageBitmap(bm) 


会出现:CalledFromWrongThreadException:only the original thread that created a view hierarchy can touch its views。原因是run()方法是在新开的线程中执行的,我们上面提到不能直接在非ui线程中操作ui元素。


非UI线程发送消息到UI线程分为两个步骤

一、发送消息到UI线程的消息队列


通过使用Handler的
Message obtainMessage(int what,Object object)


构造一个Message对象,这个对象存储了是否成功获取图片的标识what和bitmap对象,然后通过message.sendToTarget()方法把这条message放到消息队列中去。

二、处理发送到UI线程的消息

在ui线程中,我们覆盖了handler的

public void handleMessage (Message msg)


这个方法是处理分发给ui线程的消息,判断msg.what的值可以知道mThread是否成功获取图片,如果图片成功获取,那么可以通过msg.obj获取到这个对象。
最后,我们通过



[java] view plaincopy
01.mImageView.setImageBitmap((Bitmap) msg.obj);

设置ImageView的bitmap对象,完成UI的更新。

更多相关文章

  1. 获取Android(安卓)SDK 源代码并在Eclipse中关联查看的方法(for s
  2. android的消息机制
  3. Android(安卓)ThreadLocal及InheritableThreadLocal分析
  4. Android(安卓)资源简介(四) ClipDrawable
  5. Android获取webView快照与屏幕截屏的方法
  6. Android进程与线程的概念
  7. Android使用Handler实时更新UI
  8. Android(安卓)获取手机(ios,android)的设备唯一码(mac地址, IMEI)
  9. 类和 Json对象

随机推荐

  1. 怎么画漂亮鞋子?二次元人物鞋子绘画技巧!
  2. 如何学习画人物头像?二次元人物头像绘画步
  3. 零基础如何学习原画设计?学CG原画设计技巧
  4. Windows配置DNS服务器
  5. curl扩展服务器通讯与mvc小框架实现
  6. Ubuntu18.04..5 配置国内镜像源:解决E: Fa
  7. Ubuntu Linux 安装配置JDK17开发环境
  8. Anaconda Navigator卡logo打不开闪退问题
  9. 安装配置Puppet
  10. 基于CentOS 7系统安装部署Grafana服务端