`
caiwb1990
  • 浏览: 315134 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android异步1:Thread+Handler更新UI

阅读更多
每个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显示从网络获取到的logo
				Toast.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() {
			
			@Override
			public 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() {
		
		@Override
		public void run() {//run()在新的线程中运行
			HttpClient hc = new DefaultHttpClient();
			HttpGet hg = new HttpGet("http://www.iteye.com/images/logo.gif");//获取iteye的logo
			final 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的更新。
0
0
分享到:
评论
1 楼 进退取舍 2012-08-22  
这个例子是讲清楚了,但还是存在一些不合理的地方.
比如:这里的线程一直在运行。没有停止.
if(mThread == null) {  
                    mThread = new Thread(runnable);  
                    mThread.start();//线程启动  
                }

相关推荐

    Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面

    ### Android异步处理详解:使用Thread+Handler实现非UI线程更新UI界面 #### 概述 Android系统中,每一个应用程序都运行在一个独立的Dalvik虚拟机进程中。当应用程序启动时,系统会创建一个主线程(MainThread),也...

    ndroid异步处理一:使用Thread+Handler实现非UI线程更新UI界面

    为了解决这个问题,Android提供了多种异步处理机制,其中一种常见的方式是使用`Thread`配合`Handler`来实现非UI线程执行耗时任务并更新UI。本篇将详细介绍这一方法。 首先,我们需要理解Android的线程模型。Android...

    使用Handler实现异步更新UI例子

    在分析了Handler的工作原理和使用方法后,我们可以看到,异步更新UI的核心是利用了Android的消息传递机制,让主线程与工作线程之间能有效地协同工作。通过Handler,我们可以在不影响UI性能的情况下执行后台任务,...

    AsyncTask 与Thread加Handler处理消息比较

    4. **更新UI**:`AsyncTask`内置了更新UI的支持,`Thread+Handler`则需要手动处理。 在选择使用哪种方式时,开发者需要根据任务的特性和需求来权衡。对于简单的异步操作和短时间运行的任务,`AsyncTask`可能是更好...

    Android源代码:HandlerDemo

    在Android开发中,`Handler`是一个至关重要的组件,它用于在主线程中处理来自其他线程的消息,确保UI更新操作的正确执行。本项目“Android源代码:HandlerDemo”将深入探讨`Handler`机制及其在多线程环境中的应用。 ...

    Android异步刷新UI多种实现方案

    本篇将详细介绍Asynctask、Handler+Thread以及TimerTask这三种常见的异步刷新UI方法,并探讨它们各自的特点和适用场景。 首先,我们来看Asynctask。Asynctask是Android为开发者提供的一个轻量级的异步任务框架,...

    android+threadhandler AsyncTask

    本文将深入探讨两种主要的异步处理方式:线程(Thread)结合Handler以及AsyncTask,它们都是Android中用于解决此问题的有效工具。 1. **线程(Thread)与Handler**: - **线程**:在多线程环境中,线程是程序执行...

    Android Thread Handler

    3. **AsyncTask**:Android提供的一种轻量级异步任务框架,适用于短时间、快速的后台操作。它可以自动管理线程和Handler,简化了界面更新。 4. **IntentService**:适用于执行单一任务的后台服务,当任务完成后会...

    android开发教程之handler异步更新ui

    总结起来,`Handler`和`postInvalidate()`在Android开发中用于异步更新UI,确保UI操作始终在主线程执行,从而保持应用的响应性。开发者可以通过创建`Handler`实例、定义`Runnable`并使用`post()`或`postDelayed()`来...

    Handler + Thread + Looper

    总的来说,理解和熟练运用Handler、Thread和Looper对于Android开发者至关重要,因为它们是保证应用流畅运行、避免阻塞UI的关键。正确地利用这些工具,开发者可以实现高效的异步处理和UI更新,提升用户体验。

    Handler结合thread 异步加载网络图片

    Android UI是单线程模型,即所有的UI更新都必须在主线程(也称为UI线程)中进行。然而,网络请求、数据库操作等耗时任务如果放在主线程,会导致应用无响应,因此需要在后台线程执行。这就是多线程在Android中的重要...

    handler加线程模式实现android应用的异步加载

    本资源主要探讨了通过Handler配合线程模式来实现Android应用的异步图片加载。下面将详细解析这个主题。 首先,Handler是Android消息机制的核心组件,它负责处理由Looper循环器分发的消息。在主线程中创建一个...

    Xamarin.Android 非UI线程更新UI

    在Xamarin.Android开发中,非UI线程更新UI是一个常见的需求,但同时也涉及到线程安全问题。本篇文章将深入探讨如何在Xamarin.Android环境中正确地从非UI线程(也称为后台线程)更新用户界面。 首先,我们需要理解...

    handler异步更新

    然而,由于Android系统的安全机制,子线程不能直接更新UI,这就引出了Handler的作用。 Handler的运作机制主要涉及到三个组件:Handler、Message和Looper。Handler是用来发送和处理Message的对象,通常在主线程中...

    Android 异步任务 设置 超时使用handler更新通知功能

    总结来说,`AsyncTask`和`Handler`在Android开发中是处理异步任务和UI更新的重要工具。`AsyncTask`提供了一个简单的后台执行和UI更新的框架,而`Handler`则允许开发者在不同线程间传递消息,确保UI更新的安全性。在...

    了解Android核心:Looper,Handler和HandlerThread

    1. 使用Thread创建主线程Handler: 在这个例子中,我们创建了一个新的Thread,并在其中创建了一个新的Handler实例(handler2)。然后,我们通过handler2的post()方法将Runnable对象放入MessageQueue,这将在主线程中...

    Handler+Thread

    在Android应用开发中,`Handler` 和 `Thread` 是两个非常关键的概念,它们主要用于处理线程间的通信和异步操作。下面将详细解释这两个概念,以及如何在实际应用中使用它们来实现简单的网络图片获取和显示。 首先,`...

    Android开发工程师面试题之handler详解。android程序员,android开发面试资料,详解

    在Android开发过程中,Handler是进行线程间通信的重要机制之一,尤其在实现异步任务更新UI等场景中扮演着关键角色。本篇文章将围绕Handler的工作原理、核心组件及其实现方式进行深入探讨,帮助读者更好地理解并掌握...

    handler结合Thread异步加载网络图片

    `Handler` 是Android消息处理机制的关键组件,它允许我们在一个线程中发送消息到另一个线程,特别是将后台线程的结果传递给主线程更新UI。`Handler`需要与`Looper`配合工作,`Looper`是一个消息循环,它不断检查消息...

    android 异步刷新demo

    AsyncTask是Android提供的一种轻量级异步任务框架,适用于快速执行短时间的后台任务,然后在UI线程更新结果。AsyncTask包含三个泛型参数,分别是Params、Progress和Result,分别代表任务输入参数类型、后台进度类型...

Global site tag (gtag.js) - Google Analytics