Android编程中的消息机制实例详解_Android

本文实例讲述了Android编程中的消息机制。分享给大家供大家参考,具体如下:

在分析Android消息机制之前,我们先来看一段代码:

public class MainActivity extends Activity implements View.OnClickListener {
  private TextView stateText;
  private Button btn;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    stateText = (TextView) findViewById(R.id.tv);
    btn = (Button) findViewById(R.id.btn);
    btn.setOnClickListener(this);
  }
  @Override
  public void onClick(View v) {
    new WorkThread().start();
  }
  //工作线程
  private class WorkThread extends Thread {
    @Override
    public void run() {
      //......处理比较耗时的操作
      //处理完成后改变状态
      stateText.setText("completed");
    }
  }
}

这段代码似乎看上去很正常,但是当你运行时就会发现,它会报一个致命性的异常:

ERROR/AndroidRuntime(421): FATAL EXCEPTION: Thread-8
ERROR/AndroidRuntime(421): android.view.ViewRoot$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.

到底是怎么回事呢?原因在于,Android系统中的视图组件并不是线程安全的,如果要更新视图,必须在主线程中更新,不可以在子线程中执行更新的操作。
既然这样,我们就在子线程中通知主线程,让主线程做更新操作吧。那么,我们如何通知主线程呢?我们需要使用到Handler对象。
我们稍微修改一下上面的代码:

public class MainActivity extends Activity implements View.OnClickListener {
  private static final int COMPLETED = 0;
  private TextView stateText;
  private Button btn;
  private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      if (msg.what == COMPLETED) {
        stateText.setText("completed");
      }
    }
  };
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    stateText = (TextView) findViewById(R.id.tv);
    btn = (Button) findViewById(R.id.btn);
    btn.setOnClickListener(this);
  }
  @Override
  public void onClick(View v) {
    new WorkThread().start();
  }
  //工作线程
  private class WorkThread extends Thread {
    @Override
    public void run() {
      //......处理比较耗时的操作
      //处理完成后给handler发送消息
      Message msg = new Message();
      msg.what = COMPLETED;
      handler.sendMessage(msg);
    }
  }
}

通过上面这种方式,我们就可以解决线程安全的问题,把复杂的任务处理工作交给子线程去完成,然后子线程通过handler对象告知主线程,由主线程更新视图,这个过程中消息机制起着重要的作用。

下面,我们就来分析一下Android中的消息机制。

熟悉Windows编程的朋友知道Windows程序是消息驱动的,并且有全局的消息循环系统。Google参考了Windows的消息循环机制,也在Android系统中实现了消息循环机制。Android通过Looper、Handler来实现消息循环机制。Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。

Android系统中的Looper负责管理线程的消息队列和消息循环。通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。

前面提到,Android的消息队列和消息循环都是针对具体线程的,一个线程可以存在一个消息队列和消息循环,特定线程的消息只能分发给本线程,不能跨线程和跨进程通讯。但是创建的工作线程默认是没有消息队列和消息循环的,如果想让工作线程具有消息队列和消息循环,就需要在线程中先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环。下面是我们创建的工作线程:

class WorkThread extends Thread {
   public Handler mHandler;
   public void run() {
     Looper.prepare();
     mHandler = new Handler() {
       public void handleMessage(Message msg) {
         // 处理收到的消息
       }
     };
     Looper.loop();
   }
}

这样一来,我们创建的工作线程就具有了消息处理机制了。
那么,为什么前边的示例中,我们怎么没有看到Looper.prepare()和Looper.loop()的调用呢?原因在于,我们的Activity是一个UI线程,运行在主线程中,Android系统会在Activity启动时为其创建一个消息队列和消息循环。
前面提到最多的是消息队列(MessageQueue)和消息循环(Looper),但是我们看到每个消息处理的地方都有Handler的存在,它是做什么的呢?Handler的作用是把消息加入特定的Looper所管理的消息队列中,并分发和处理该消息队列中的消息。构造Handler的时候可以指定一个Looper对象,如果不指定则利用当前线程的Looper对象创建。下面是Handler的两个构造方法:

/**
* Default constructor associates this handler with the queue for the
* current thread.
*
* If there isn't one, this handler won't be able to receive messages.
*/
public Handler() {
    if (FIND_POTENTIAL_LEAKS) {
      final Class<? extends Handler> klass = getClass();
      if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
          (klass.getModifiers() & Modifier.STATIC) == 0) {
        Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
          klass.getCanonicalName());
      }
    }
    mLooper = Looper.myLooper();
    if (mLooper == null) {
      throw new RuntimeException(
        "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = null;
}
/**
* Use the provided queue instead of the default one.
*/
public Handler(Looper looper) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = null;
}

下面是消息机制中几个重要成员的关系图:

一个Activity中可以创建出多个工作线程,如果这些线程把他们消息放入Activity主线程的消息队列中,那么消息就会在主线程中处理了。因为主线程一般负责视图组件的更新操作,对于不是线程安全的视图组件来说,这种方式能够很好的实现视图的更新。

那么,子线程如何把消息放入主线程的消息队列中呢?只要Handler对象以主线程的Looper创建,那么当调用Handler的sendMessage方法,系统就会把消息主线程的消息队列,并且将会在调用handleMessage方法时处理主线程消息队列中的消息。

对于子线程访问主线程的Handler对象,你可能会问,多个子线程都访问主线程的Handler对象,发送消息和处理消息的过程中会不会出现数据的不一致呢?答案是Handler对象不会出现问题,因为Handler对象管理的Looper对象是线程安全的,不管是添加消息到消息队列还是从消息队列中读取消息都是同步保护的,所以不会出现数据不一致现象。

深入理解Android消息处理机制对于应用程序开发非常重要,也可以让我们对线程同步有更加深刻的认识,希望这篇文章可以对朋友们有所帮助。

希望本文所述对大家Android程序设计有所帮助。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索android
, 消息机制
android消息机制
c 编程实例详解、数控编程实例详解、vb教程 编程实例详解、matlab编程实例详解、数控车床编程实例详解,以便于您获取更多的相关知识。

时间: 2024-10-10 03:40:15

Android编程中的消息机制实例详解_Android的相关文章

Android编程中的消息机制实例详解

本文实例讲述了Android编程中的消息机制.分享给大家供大家参考,具体如下: 在分析Android消息机制之前,我们先来看一段代码: public class MainActivity extends Activity implements View.OnClickListener { private TextView stateText; private Button btn; @Override public void onCreate(Bundle savedInstanceState)

Android编程中context及全局变量实例详解_Android

本文实例讲述了Android编程中context及全局变量的用法.分享给大家供大家参考,具体如下: 今天在研究context的时候,对application和activity context有了一定的了解,下面是从网上复制过来的资料 Application context和Activity context的区别: 这是两种不同的context,也是最常见的两种.第一种中context的生命周期与Application的生命周期相关的,context随着Application的销毁而销毁,伴随ap

Android编程之文件的读写实例详解_Android

本文实例分析了Android编程之文件的读写方法.分享给大家供大家参考,具体如下: Android的文件读写与JavaSE的文件读写相同,都是使用IO流.而且Android使用的正是JavaSE的IO流,下面我们通过一个练习来学习Android的文件读写. 1.创建一个Android工程 Project name:File     BuildTarget:Android2.2     Application name:文件读写     Package name:test.file     Cre

Android 开发中使用Linux Shell实例详解

Android 开发中使用Linux Shell实例详解 引言 Android系统是基于Linux内核运行的,而做为一名Linux粉,不在Android上面运行一下Linux Shell怎么行呢? 最近发现了一个很好的Android Shell工具代码,在这里分享一下. Shell核心代码 import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.

Android开发之Animations动画用法实例详解_Android

本文实例讲述了Android开发之Animations动画用法.分享给大家供大家参考,具体如下: 一.动画类型 Android的animation由四种类型组成:alpha.scale.translate.rotate XML配置文件中 alpha 渐变透明度动画效果 scale 渐变尺寸伸缩动画效果 translate 画面转换位置移动动画效果 rotate 画面转移旋转动画效果 Java Code代码中 AlphaAnimation 渐变透明度动画效果 ScaleAnimation 渐变尺寸

Android中标签容器控件的实例详解_Android

前言 在一些APP中我们可以看到一些存放标签的容器控件,和我们平时使用的一些布局方式有些不同,它们一般都可以自动适应屏幕的宽度进行布局,根据对自定义控件的一些理解,今天写一个简单的标签容器控件,给大家参考学习. 下面这个是我在手机上截取的一个实例,是在MIUI8系统上截取的 这个是我实现的效果图 原理介绍 根据对整个控件的效果分析,大致可以将控件分别从以下这几个角度进行分析: 1.首先涉及到自定义的ViewGroup,因为现有的控件没法满足我们的布局效果,就涉及到要重写onMeasure和onL

Android编程实现泡泡聊天界面实例详解(附源码)_Android

本文实例讲述了Android编程实现泡泡聊天界面的方法.分享给大家供大家参考,具体如下: 昨天写了个界面,实现了Android泡泡聊天界面.运行结果如下,点击发送按钮,屏幕就显示Text的内容. 我也是在网上的一份源码的基础上更改的,整个泡泡界面的实现要点: (1)主界面其实就是一个List View (2)文字显示界面其实就使用了android:background="@drawable/incoming"这个东西.背景图片的格式是xxx.9.png,专门用来缩放的,不然显示效果非常

Android编程中光线传感器的调用方法详解

本文实例讲述了Android编程中光线传感器的调用方法.分享给大家供大家参考,具体如下: 1.activity如果要使用传感器,就必须实现SensorEventListener接口 2.得到传感器管理对象(sensormanager) 3.使用sensormanager.registerlistener 方法注册指定的传感器 4.在sensoreventlistener 接口中的onsensorchanged和onaccuracychanged方法中完成其他具体工作 public class T

Android编程实现自定义手势的方法详解_Android

本文实例讲述了Android编程实现自定义手势的方法.分享给大家供大家参考,具体如下: 之前介绍过如何在Android程序中使用手势,主要是系统默认提供的几个手势,这次介绍一下如何自定义手势,以及如何对其进行管理. 先介绍一下Android系统对手势的管理,Android系统允许应用程序把用户的手势以文件的形式保存以前,以后要使用这些手势只需要加载这个手势库文件即可,同时Android系统还提供了诸如手势识别.查找及删除等的函数接口,具体如下: 一.加载手势库文件: staticGestureL