- 浏览: 316133 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
u011076522:
写的确实不错,总结的很好,内容大都属实
C/C++内存分配方式 -
水晶魔方:
...
联合编译工具推荐IncrediBuild -
caiwb1990:
又看了一遍~ 越看越清晰~
C/C++内存分配方式 -
caiwb1990:
每次准备面试的时候来瞅瞅。timer_yin 写道好文,正好补 ...
TCP/IP、Http、Socket的区别【转】 -
caiwb1990:
互相学习~kongxuan 写道这个不错,用简单的话将事情讲明 ...
TCP/IP、Http、Socket的区别【转】
每个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线程更新界面。
为了不阻塞ui线程,我们使用mThread从网络获取了Iteye的LOGO,并用bitmap对象存储了这个Logo的像素信息。
此时,如果在这个线程的run()方法中调用
会出现:CalledFromWrongThreadException:only the original thread that created a view hierarchy can touch its views。原因是run()方法是在新开的线程中执行的,我们上面提到不能直接在非ui线程中操作ui元素。
非UI线程发送消息到UI线程分为两个步骤
一、发送消息到UI线程的消息队列
通过使用Handler的
构造一个Message对象,这个对象存储了是否成功获取图片的标识what和bitmap对象,然后通过message.sendToTarget()方法把这条message放到消息队列中去。
二、处理发送到UI线程的消息
在ui线程中,我们覆盖了handler的
这个方法是处理分发给ui线程的消息,判断msg.what的值可以知道mThread是否成功获取图片,如果图片成功获取,那么可以通过msg.obj获取到这个对象。
最后,我们通过
[java] view plaincopy
01.mImageView.setImageBitmap((Bitmap) msg.obj);
设置ImageView的bitmap对象,完成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的更新。
评论
1 楼
进退取舍
2012-08-22
这个例子是讲清楚了,但还是存在一些不合理的地方.
比如:这里的线程一直在运行。没有停止.
if(mThread == null) {
mThread = new Thread(runnable);
mThread.start();//线程启动
}
比如:这里的线程一直在运行。没有停止.
if(mThread == null) {
mThread = new Thread(runnable);
mThread.start();//线程启动
}
发表评论
-
Android多线程:预读实现
2012-04-08 00:22 3029上一篇博文我们可以知道,使用AsyncTask有导致应用FC的 ... -
Android多线程:AsyncTask的分析
2012-04-05 13:34 4633开发Android应用的过程中,我们需要时刻注意保障应用的稳定 ... -
Android异步4:深入AsyncTask原理
2012-03-01 09:12 4853AsyncTask的本质是一个线程池,所有提交的异步任务都会在 ... -
Android异步3:AsyncTask更新UI
2012-02-29 10:13 1412前天写了Thread+Handler的 ... -
Android异步2:深入详解 Handler+Looper+MessageQueue
2012-02-28 10:15 1739Android使用消息机制实现 ... -
WebView及js
2012-02-20 09:37 1326在Android中通过WebView控 ... -
Android用线程应注意
2012-02-17 09:36 1415我们都知道Hanlder是线程与Activity通信的桥梁,我 ... -
Android用线程应注意
2012-02-17 09:35 1我们都知道Hanlder是线程 ... -
Android Google Api 获取地址
2012-02-16 09:38 3382我们获取Location的目的之一肯定是有获取这个位置的详细地 ... -
Android获取经纬度
2012-02-16 09:34 4460Location 在Android 开发中还是经常用到的,比如 ... -
Android启动已安装应用
2012-02-15 22:45 1200如何在一个应用中 通过某个事件,而去启动另外一个已安装的应用。 ... -
Android 获取Ip
2012-02-15 22:41 1145我们开发中,有判断手机是否联网,或者想获得当前手机的Ip地址, ... -
布局定义菜单--MenuInflater的使用
2012-02-14 10:42 2235传统意义上的定义菜单感觉比较繁琐,当我们使用MenuInfla ... -
LayoutInflater的使用
2012-02-13 11:58 1377在实际开发种LayoutInflater这个类还是非常有用的, ... -
自定义属性
2012-02-13 11:54 1168在xml 文件里定义控件的属性,我们已经习惯了android: ... -
自定义View
2012-02-13 11:37 1022对于初学着来说,他们习惯了Android 传统的页面布局方式, ... -
Intent传递对象的两种方法(Serializable,Parcelable)
2012-02-13 10:23 30116今天讲一下Android中Intent中如何传递对象,就我目前 ... -
Android Service 服务详细讲解
2012-01-16 09:38 1037Android 的Service 和 Handler一样很重, ... -
自定义窗口标题
2011-11-06 14:10 1726我们看到过很多应用,他们的窗口标题行都不是系统默认的 要么有按 ...
相关推荐
### Android异步处理详解:使用Thread+Handler实现非UI线程更新UI界面 #### 概述 Android系统中,每一个应用程序都运行在一个独立的Dalvik虚拟机进程中。当应用程序启动时,系统会创建一个主线程(MainThread),也...
为了解决这个问题,Android提供了多种异步处理机制,其中一种常见的方式是使用`Thread`配合`Handler`来实现非UI线程执行耗时任务并更新UI。本篇将详细介绍这一方法。 首先,我们需要理解Android的线程模型。Android...
在分析了Handler的工作原理和使用方法后,我们可以看到,异步更新UI的核心是利用了Android的消息传递机制,让主线程与工作线程之间能有效地协同工作。通过Handler,我们可以在不影响UI性能的情况下执行后台任务,...
4. **更新UI**:`AsyncTask`内置了更新UI的支持,`Thread+Handler`则需要手动处理。 在选择使用哪种方式时,开发者需要根据任务的特性和需求来权衡。对于简单的异步操作和短时间运行的任务,`AsyncTask`可能是更好...
在Android开发中,`Handler`是一个至关重要的组件,它用于在主线程中处理来自其他线程的消息,确保UI更新操作的正确执行。本项目“Android源代码:HandlerDemo”将深入探讨`Handler`机制及其在多线程环境中的应用。 ...
本篇将详细介绍Asynctask、Handler+Thread以及TimerTask这三种常见的异步刷新UI方法,并探讨它们各自的特点和适用场景。 首先,我们来看Asynctask。Asynctask是Android为开发者提供的一个轻量级的异步任务框架,...
本文将深入探讨两种主要的异步处理方式:线程(Thread)结合Handler以及AsyncTask,它们都是Android中用于解决此问题的有效工具。 1. **线程(Thread)与Handler**: - **线程**:在多线程环境中,线程是程序执行...
3. **AsyncTask**:Android提供的一种轻量级异步任务框架,适用于短时间、快速的后台操作。它可以自动管理线程和Handler,简化了界面更新。 4. **IntentService**:适用于执行单一任务的后台服务,当任务完成后会...
总结起来,`Handler`和`postInvalidate()`在Android开发中用于异步更新UI,确保UI操作始终在主线程执行,从而保持应用的响应性。开发者可以通过创建`Handler`实例、定义`Runnable`并使用`post()`或`postDelayed()`来...
总的来说,理解和熟练运用Handler、Thread和Looper对于Android开发者至关重要,因为它们是保证应用流畅运行、避免阻塞UI的关键。正确地利用这些工具,开发者可以实现高效的异步处理和UI更新,提升用户体验。
Android UI是单线程模型,即所有的UI更新都必须在主线程(也称为UI线程)中进行。然而,网络请求、数据库操作等耗时任务如果放在主线程,会导致应用无响应,因此需要在后台线程执行。这就是多线程在Android中的重要...
本资源主要探讨了通过Handler配合线程模式来实现Android应用的异步图片加载。下面将详细解析这个主题。 首先,Handler是Android消息机制的核心组件,它负责处理由Looper循环器分发的消息。在主线程中创建一个...
在Xamarin.Android开发中,非UI线程更新UI是一个常见的需求,但同时也涉及到线程安全问题。本篇文章将深入探讨如何在Xamarin.Android环境中正确地从非UI线程(也称为后台线程)更新用户界面。 首先,我们需要理解...
然而,由于Android系统的安全机制,子线程不能直接更新UI,这就引出了Handler的作用。 Handler的运作机制主要涉及到三个组件:Handler、Message和Looper。Handler是用来发送和处理Message的对象,通常在主线程中...
总结来说,`AsyncTask`和`Handler`在Android开发中是处理异步任务和UI更新的重要工具。`AsyncTask`提供了一个简单的后台执行和UI更新的框架,而`Handler`则允许开发者在不同线程间传递消息,确保UI更新的安全性。在...
1. 使用Thread创建主线程Handler: 在这个例子中,我们创建了一个新的Thread,并在其中创建了一个新的Handler实例(handler2)。然后,我们通过handler2的post()方法将Runnable对象放入MessageQueue,这将在主线程中...
在Android应用开发中,`Handler` 和 `Thread` 是两个非常关键的概念,它们主要用于处理线程间的通信和异步操作。下面将详细解释这两个概念,以及如何在实际应用中使用它们来实现简单的网络图片获取和显示。 首先,`...
在Android开发过程中,Handler是进行线程间通信的重要机制之一,尤其在实现异步任务更新UI等场景中扮演着关键角色。本篇文章将围绕Handler的工作原理、核心组件及其实现方式进行深入探讨,帮助读者更好地理解并掌握...
`Handler` 是Android消息处理机制的关键组件,它允许我们在一个线程中发送消息到另一个线程,特别是将后台线程的结果传递给主线程更新UI。`Handler`需要与`Looper`配合工作,`Looper`是一个消息循环,它不断检查消息...
AsyncTask是Android提供的一种轻量级异步任务框架,适用于快速执行短时间的后台任务,然后在UI线程更新结果。AsyncTask包含三个泛型参数,分别是Params、Progress和Result,分别代表任务输入参数类型、后台进度类型...