Looper如何和一个线程进行绑定,以及Android中的Can't create handler inside thread that has not called Looper.prepare()

Android客户端和服务器端数据交互的第三种方法》中Android手机客户端代码1曾经提到“第41行和第61行不可缺少,否则会出现java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()异常”,呵呵呵,难道将”第41行和第61行”代码注销掉以后真的会出现这个异常疑问?嗯嗯嗯,这是一个事实,可是如果把”第41行和第61行”代码注销掉并且把“第50行”代码改为“System.out.println(EntityUtils.toString(httpResponse.getEntity()));”,这时再次运行Android客户端就会发现程序没有任何问题,为什么会这样?很简单,一句话Android中不能在子线程中刷新UI线程。那么问题来了,如果需要在子线程中刷新UI线程怎么办?有如下两种方法:

        第一种方法:像博客《Android客户端和服务器端数据交互的第三种方法》中说的那样添加”第41行和第61行”代码;

        第二种方法提到了Looper类,那么怎么理解这个类呢?

        Looper类用来为一个子线程开启一个消息循环。默认情况下Android中新诞生的非主线程没有开启消息循环(主线程诞生时系统会自动为其创建开启消息循环的Looper对象),所以在非主线程中直接new Handler()会报“java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()”异常,需要先调用Looper.prepare()启用Looper,然后通过调用Looper.loop()让Looper开始工作,如下代码:

        代码1:名为“AndroidActivity.java”的文件

  1. package com.example.androidclient;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.os.Handler;  
  6. import android.os.Looper;  
  7. import android.os.Message;  
  8. import android.view.View;  
  9. import android.view.View.OnClickListener;  
  10. import android.widget.Button;  
  11. import android.widget.Toast;  
  12.   
  13. public class AndroidActivity extends Activity {  
  14.       
  15.     @Override  
  16.     protected void onCreate(Bundle savedInstanceState) {  
  17.         super.onCreate(savedInstanceState);  
  18.         setContentView(R.layout.android);  
  19.   
  20.         Button sendButton = (Button) findViewById(R.id.button);  
  21.         sendButton.setOnClickListener(new OnClickListener(){  
  22.             @Override  
  23.             public void onClick(View v) {  
  24.                 new Thread(new Runnable(){  
  25.                     @Override  
  26.                     public void run() {  
  27.                         Looper.prepare();  
  28.                         Message message = new Message();    
  29.                         Bundle bundle = new Bundle();  
  30.                         Handler handler = new Handler(){    
  31.                             @Override    
  32.                             public void handleMessage(Message message) {    
  33.                                 super.handleMessage(message);    
  34.                                 Bundle bundle = message.getData();    
  35.                                 String msg = bundle.getString(”msg”);    
  36.                                 Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();    
  37.                             }    
  38.                         };  
  39.                         bundle.putString(”msg”“你好!!!”);  
  40.                         message.setData(bundle);    
  41.                         handler.sendMessage(message);  
  42.                         Looper.loop();  
  43.                     }  
  44.                 }).start();  
  45.             }  
  46.         });  
  47.     }  
  48. }  
package com.example.androidclient;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class AndroidActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.android);

    Button sendButton = (Button) findViewById(R.id.button);
    sendButton.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v) {
            new Thread(new Runnable(){
                @Override
                public void run() {
                    Looper.prepare();
                    Message message = new Message();  
                    Bundle bundle = new Bundle();
                    Handler handler = new Handler(){  
                        @Override  
                        public void handleMessage(Message message) {  
                            super.handleMessage(message);  
                            Bundle bundle = message.getData();  
                            String msg = bundle.getString("msg");  
                            Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();  
                        }  
                    };
                    bundle.putString("msg", "你好!!!");
                    message.setData(bundle);  
                    handler.sendMessage(message);
                    Looper.loop();
                }
            }).start();
        }
    });
}

}

        代码2:名为“android.xml”的文件
  1. <RelativeLayout xmlns:android=http://schemas.android.com/apk/res/android  
  2.     xmlns:tools=http://schemas.android.com/tools  
  3.     android:layout_width=“match_parent”  
  4.     android:layout_height=“match_parent”  
  5.     android:paddingBottom=“@dimen/activity_vertical_margin”  
  6.     android:paddingLeft=“@dimen/activity_horizontal_margin”  
  7.     android:paddingRight=“@dimen/activity_horizontal_margin”  
  8.     android:paddingTop=“@dimen/activity_vertical_margin”  
  9.     tools:context=“.MainActivity” >  
  10.   
  11.    <Button  
  12.        android:id=“@+id/button”  
  13.        android:layout_width=“wrap_content”  
  14.        android:layout_height=“wrap_content”  
  15.        android:layout_centerHorizontal=“true”  
  16.        android:layout_centerVertical=“true”  
  17.        android:text=“@string/hello” />  
  18.   
  19. </RelativeLayout>  
<RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android” 
xmlns:tools=”http://schemas.android.com/tools”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:paddingBottom=”@dimen/activity_vertical_margin”
android:paddingLeft=”@dimen/activity_horizontal_margin”
android:paddingRight=”@dimen/activity_horizontal_margin”
android:paddingTop=”@dimen/activity_vertical_margin”
tools:context=”.MainActivity” >

<Button
android:id=”@+id/button”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_centerHorizontal=”true”
android:layout_centerVertical=”true”
android:text=”@string/hello” />

</RelativeLayout>

        第二种方法:像博客《Android客户端和服务器端数据交互的第二种方法》中做的那样在子线程中添加Handler来发送消息更新UI线程。

        第二种方法提到了HandlerHandler,可是怎样理解它呢?

        Handler主要用于接收子线程发送的数据并用此数据配合主线程更新UI线程. 
        解释: 当Android应用程序启动时,它首先会开启一个主线程 (也就是UI线程), 主线程为管理界面中的UI控件,进行事件分发, 比如说, 点击一个Button, Android会将事件分发到该Button上来响应操作。如果点击按钮后需要一个耗时的操作(比如联网读取数据或者读取本地较大的一个文件),你不能把这些操作放在主线程中,放在主线程界面会出现假死现象, 如果5秒钟还没有完成,则会收到Android系统的一个错误提示”强制关闭”,这个时候我们需要把这些耗时的操作放在一个子线程中,又因为子线程涉及到UI更新,而Android主线程不安全的,所以只能在主线程中更新UI线程,子线程中操作是危险的。这种情况下,Handler的出现解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接收子线程传过来的(子线程用sedMessage()方法传弟)Message对象(该对象携带者子线程传入的数据)并把这些数据放入主线程队列中以配合主线程更新UI线程。






版权声明:本文为博主原创文章,未经博主允许不得转载。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值