zoukankan      html  css  js  c++  java
  • Android异步处理系列文章四篇之一使用Thread+Handler实现非UI线程更新UI界面

    目录:

    Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面
    Android异步处理二:使用AsyncTask异步更新UI界面
    Android异步处理三:Handler+Looper+MessageQueue深入详解
    Android异步处理四:AsyncTask的实现原理

    Android异步处理一:使用Thread+Handler实现非UI线程更新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线程。

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

     ThradHandlerActivity.java:

     1 public class ThreadHandlerActivity extends Activity {
     2     /** Called when the activity is first created. */
     3     
     4     private static final int MSG_SUCCESS = 0;//获取图片成功的标识
     5     private static final int MSG_FAILURE = 1;//获取图片失败的标识
     6     
     7     private ImageView mImageView;
     8     private Button mButton;
     9     
    10     private Thread mThread;
    11     
    12     private Handler mHandler = new Handler() {
    13         public void handleMessage (Message msg) {//此方法在ui线程运行
    14             switch(msg.what) {
    15             case MSG_SUCCESS:
    16                 mImageView.setImageBitmap((Bitmap) msg.obj);//imageview显示从网络获取到的logo
    17                 Toast.makeText(getApplication(), getApplication().getString(R.string.get_pic_success), Toast.LENGTH_LONG).show();
    18                 break;
    19 
    20             case MSG_FAILURE:
    21                 Toast.makeText(getApplication(), getApplication().getString(R.string.get_pic_failure), Toast.LENGTH_LONG).show();
    22                 break;
    23             }
    24         }
    25     };
    26     
    27     @Override
    28     public void onCreate(Bundle savedInstanceState) {
    29         super.onCreate(savedInstanceState);
    30         setContentView(R.layout.main);
    31         mImageView= (ImageView) findViewById(R.id.imageView);//显示图片的ImageView
    32         mButton = (Button) findViewById(R.id.button);
    33         mButton.setOnClickListener(new OnClickListener() {
    34             
    35             @Override
    36             public void onClick(View v) {
    37                 if(mThread == null) {
    38                     mThread = new Thread(runnable);
    39                     mThread.start();//线程启动
    40                 }
    41                 else {
    42                     Toast.makeText(getApplication(), getApplication().getString(R.string.thread_started), Toast.LENGTH_LONG).show();
    43                 }
    44             }
    45         });
    46     }
    47     
    48     Runnable runnable = new Runnable() {
    49         
    50         @Override
    51         public void run() {//run()在新的线程中运行
    52             HttpClient hc = new DefaultHttpClient();
    53             HttpGet hg = new HttpGet("http://csdnimg.cn/www/images/csdnindex_logo.gif");//获取csdn的logo
    54             final Bitmap bm;
    55             try {
    56                 HttpResponse hr = hc.execute(hg);
    57                 bm = BitmapFactory.decodeStream(hr.getEntity().getContent());
    58             } catch (Exception e) {
    59                 mHandler.obtainMessage(MSG_FAILURE).sendToTarget();//获取图片失败
    60                 return;
    61             }
    62             mHandler.obtainMessage(MSG_SUCCESS,bm).sendToTarget();//获取图片成功,向ui线程发送MSG_SUCCESS标识和bitmap对象
    63 
    64 //            mImageView.setImageBitmap(bm); //出错!不能在非ui线程操作ui元素
    65 
    66 //            mImageView.post(new Runnable() {//另外一种更简洁的发送消息给ui线程的方法。
    67 //                
    68 //                @Override
    69 //                public void run() {//run()方法会在ui线程执行
    70 //                    mImageView.setImageBitmap(bm);
    71 //                }
    72 //            });
    73         }
    74     };
    75     
    76 }

    main.xml布局文件:

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

    strings.xml

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

    Manifest.xml:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     3       package="com.zhuozhuo"
     4       android:versionCode="1"
     5       android:versionName="1.0">
     6     <uses-sdk android:minSdkVersion="9" />
     7     <uses-permission android:name="android.permission.INTERNET"></uses-permission><!--不要忘记设置网络访问权限-->
     8 
     9     <application android:icon="@drawable/icon" android:label="@string/app_name">
    10         <activity android:name=".ThreadHandlerActivity"
    11                   android:label="@string/app_name">
    12             <intent-filter>
    13                 <action android:name="android.intent.action.MAIN" />
    14                 <category android:name="android.intent.category.LAUNCHER" />
    15             </intent-filter>
    16         </activity>
    17 
    18     </application>
    19 </manifest>
     

    运行结果:

    为了不阻塞ui线程,我们使用mThread从网络获取了CSDN的LOGO

    ,并用bitmap对象存储了这个Logo的像素信息。

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

    1 mImageView.setImageBitmap(bm)

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

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

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

    通过使用Handler的

    1 Message obtainMessage(int what,Object object)

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

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

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

    1 public void handleMessage (Message msg) 

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

    最后,我们通过

    1 mImageView.setImageBitmap((Bitmap) msg.obj);

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

    补充:

    事实上,我们还可以调用

    View的post方法来更新ui

    1 mImageView.post(new Runnable() {//另外一种更简洁的发送消息给ui线程的方法。
    2                 
    3                 @Override
    4                 public void run() {//run()方法会在ui线程执行
    5                     mImageView.setImageBitmap(bm);
    6                 }
    7             });

    这种方法会把Runnable对象发送到消息队列,ui线程接收到消息后会执行这个runnable对象。

     从例子中我们可以看到handler既有发送消息和处理消息的作用,会误以为handler实现了消息循环和消息分发,其实Android为了让我们的代码看起来更加简洁,与UI线程的交互只需要使用在UI线程创建的handler对象就可以了。

    转自:http://blog.csdn.net/mylzc/article/details/6777767

  • 相关阅读:
    (引)spring学习笔记1.什么是控制反转
    Arduino 各种模块篇 步进电机 step motor 舵机 servo 直流电机 总复习
    Raspberry Pi Wireless Adaptor
    Pyramid 使用总结1
    Arduino 各种模块篇 人体红外感应模块 proximity sensor
    Pyramid 使用总结2
    Webcam Streaming Desktop Recording on Linux for ubuntu or its destros
    Arduino 各种模块篇 步进电机 step motor( 不用库,不用shield, 纯)
    Arduino 各种模块篇 motor shield 电机扩展板(舵机、直流电机、步进电机party)
    转载 stepper motors
  • 原文地址:https://www.cnblogs.com/ycxyyzw/p/4469195.html
Copyright © 2011-2022 走看看