Android后台线程和UI线程通讯实例

2014-08-03  来源:本站原创  分类:Android  人气:3 

这篇文章主要介绍了Android后台线程和UI线程通讯实例,每一步的要点和步骤都有提及,并配有代码例子,需要的朋友可以参考下

本节向你展示如何在任务中发送数据给UI线程里的对象,这个特性允许你在后台线程工作,完了在UI线程展示结果。

在UI线程定义一个Handler

Handler是Android系统线程管理框架里的一部分。一个Handler对象接收消息,并且运行代码来处理消息。正常情况下,你为新线程创建Handler,但你也可以为已有的线程创建一个Handler.当你连接Handler到UI线程时,处理消息的代码会在UI线程上运行.

在创建线程池的类的构造器里实例化Handler对象,保存在全局变量里。用Handler(Looper)方法实例化,连接到UI线程,构造方法使用Looper对象,也是Android系统线程管理框架里的一部分.Looper类有一个静态方法getMainLooper()可以获取UI线程的Looper对象。如:

private PhotoManager() {

...

    // Defines a Handler object that's attached to the UI thread

    mHandler = new Handler(Looper.getMainLooper()) {

    ...

在Handler里,覆盖handleMessage()。Android系统会在Handler管理的线程收到新消息时,调用该方法。一个指定线程的所有Handler对象都会收到相同的消息。

复制代码 代码如下:

        /*

         * handleMessage() defines the operations to perform when

         * the Handler receives a new Message to process.

         */

        @Override

        public void handleMessage(Message inputMessage) {

            // Gets the image task from the incoming Message object.

            PhotoTask photoTask = (PhotoTask) inputMessage.obj;

            ...

        }

    ...

    }

}

从任务里移动数据到UI线程

要从后台线程的任务里移动数据到UI线程的对象,先保存引用到数据和任务对象的UI对象里,接下来把任务对象和状态码传给Handler对象。在这个对象里,发送一个包含状态 和任务对象的消息给Handler.因为Handler在UI线程上运行,它可以移动数据给UI对象。

在任务对象里存储数据

如,这是一个Runnable,运行在后台线程,它解析Bitmap,并保存到它的父对象。Runnable同时保存状态码DECODE_STATE_COMPLETED。

复制代码 代码如下:

// A class that decodes photo files into Bitmaps

class PhotoDecodeRunnable implements Runnable {

    ...

    PhotoDecodeRunnable(PhotoTask downloadTask) {

        mPhotoTask = downloadTask;

    }

    ...

    // Gets the downloaded byte array

    byte[] imageBuffer = mPhotoTask.getByteBuffer();

    ...

    // Runs the code for this task

    public void run() {

        ...

        // Tries to decode the image buffer

        returnBitmap = BitmapFactory.decodeByteArray(

                imageBuffer,

                0,

                imageBuffer.length,

                bitmapOptions

        );

        ...

        // Sets the ImageView Bitmap

        mPhotoTask.setImage(returnBitmap);

        // Reports a status of "completed"

        mPhotoTask.handleDecodeState(DECODE_STATE_COMPLETED);

        ...

    }

    ...

}

...

PhotoTask还包含一个ImageView引用,用来显示Bitmap.尽管引用Bitmap和ImageView是在同一个对象里,但因为不是在UI线程,你不能直接让ImageView显示Bitmap.

沿对象层次逐级发送状态

PhotoTask持有解码的数据和显示数据的View对象的引用,它从PhotoDecodeRunnable接收到状态码,并且沿着线程池里引用的对象和Handler实例传送。

复制代码 代码如下:

public class PhotoTask {

    ...

    // Gets a handle to the object that creates the thread pools

    sPhotoManager = PhotoManager.getInstance();

    ...

    public void handleDecodeState(int state) {

        int outState;

        // Converts the decode state to the overall state.

        switch(state) {

            case PhotoDecodeRunnable.DECODE_STATE_COMPLETED:

                outState = PhotoManager.TASK_COMPLETE;

                break;

            ...

        }

        ...

        // Calls the generalized state method

        handleState(outState);

    }

    ...

    // Passes the state to PhotoManager

    void handleState(int state) {

        /*

         * Passes a handle to this task and the

         * current state to the class that created

         * the thread pools

         */

        sPhotoManager.handleState(this, state);

    }

    ...

}

移动数据到UI

PhotoManager从PhotoTask对象接收到状态码和PhotoTask对象的句柄。因为状态是TASK_COMPLETE,创建一个包含状态和任务对象的Message,发送给Handler。

复制代码 代码如下:

public class PhotoManager {

    ...

    // Handle status messages from tasks

    public void handleState(PhotoTask photoTask, int state) {

        switch (state) {

            ...

            // The task finished downloading and decoding the image

            case TASK_COMPLETE:

                /*

                 * Creates a message for the Handler

                 * with the state and the task object

                 */

                Message completeMessage =

                        mHandler.obtainMessage(state, photoTask);

                completeMessage.sendToTarget();

                break;

            ...

        }

        ...

    }

最终,Handler.handleMessage()为每个进来的Message检查状态码。如果状态码是TASK_COMPLETE,任务就是完成了,Message里的PhotoTask对象包含Bitmap和ImageView.因为Handler.handleMessage()运行在UI线程,它可以安全地为ImageView设置Bitmap.

相关文章
  • Android后台线程和UI线程通讯实例 2014-08-03

    这篇文章主要介绍了Android后台线程和UI线程通讯实例,每一步的要点和步骤都有提及,并配有代码例子,需要的朋友可以参考下 本节向你展示如何在任务中发送数据给UI线程里的对象,这个特性允许你在后台线程工作,完了在UI线程展示结果. 在UI线程定义一个Handler Handler是Android系统线程管理框架里的一部分.一个Handler对象接收消息,并且运行代码来处理消息.正常情况下,你为新线程创建Handler,但你也可以为已有的线程创建一个Handler.当你连接Handler到UI线

  • 理解UI线程--SWT, Android, 和Swing的UI机理 2013-12-01

    在做GUI的时候, 无论是SWT, AWT, Swing 还是Android, 都需要面对UI线程的问题, UI线程往往会被单独的提出来单独对待, 试着问自己, 当GUI启动的时候, 后台会运行几个线程? 比如 1. SWT 从Main函数启动 2. Swing 从Main函数启动 3. Android 界面启动 常常我们被告知, 主线程, UI线程, 因此这里很多会回答, 有两个线程, 一个线程是Main, 另外一个是UI. 如果答案是这样, 这篇文章就是写给你的. OK, 我们以SWT为例,

  • Android中的UI线程 2012-08-29

    一.原理分析 当应用程序启动时会首先创建一个"主线程",它是应用程序的入口,负责管理UI.分发事件,所以习惯上也被称作UI线程.UI线程也负责处理与用户交互的操作,当用户触摸了手机屏幕时,UI线程会把触摸事件分发到控件,控件收到事件后会改变自己的状态,同时发送一个请求重新绘制的事件插入到事件队列.UI线程从事件队列里取出这个事件然后进行重绘操作. 在Android系统中,控件是根据它的一系列的属性值进行绘制的,那么很有可能在控件绘制的过程中,它属性值会被另外一个线程改变,这样以来,可能

  • android使用handler ui线程和子线程通讯更新ui示例 2015-02-06

    这篇文章主要介绍了android使用handler ui线程和子线程通讯更新ui的方法,大家参考使用吧 package com.act262.sockettx; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickLi

  • Android 在其他线程中更新UI线程的解决方法 2014-03-28

    本篇文章是对Android中在其他线程中更新UI线程的方法进行了详细的分析介绍,需要的朋友参考下 方法一:Activity.runOnUiThread(Runnable )(经验之道: 这个最好用, 凡是要刷新页面的地方, Activity.runOnUiThread( new Runnable() { public void run(){更新UI}} ); 方法二:子线程调用Handler的sendMessage(message)发送事件. mHandler = new Handler() {

  • C#子线程更新UI控件的方法实例总结 2014-12-04

    这篇文章主要介绍了C#子线程更新UI控件的方法,在桌面应用程序中控制UI界面有着不错的实用价值,需要的朋友可以参考下 本文实例总结了C#子线程更新UI控件的方法,对于桌面应用程序设计的UI界面控制来说非常有实用价值.分享给大家供大家参考之用.具体分析如下: 一般在winform C/S程序中经常会在子线程中更新控件的情况,桌面程序UI线程是主线程,当试图从子线程直接修改控件属性时会出现"从不是创建控件的线程访问它"的异常提示. 跨线程更新UI控件的常用方法有两种: 1.使用控件自身的i

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

    概述:每个Android应用程序都运行在一个dalvik虚拟机进程中,进程开始的时候会启动一个主线程(MainThread),主线程负责处理和ui相关的事件,因此主线程通常又叫UI线程.而由于Android采用UI单线程模型,所以只能在主线程中对UI元素进行操作.如果在非UI线程直接对UI进行了操作,则会报错: CalledFromWrongThreadException:only the original thread that created a view hierarchy can tou

  • [Google官方教程]第二课:在非UI线程处理Bitmap 2012-11-10

    转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-) http://my.codeweblog.com/ryanhoo/blog/88344 译者:Ryan Hoo 来源:https://developer.android.com/develop/index.html 译者按: 在Google最新的文档中,提供了一系列含金量相当高的教程.因为种种原因而鲜为人知,真是可惜!Ryan将会细心整理,将之翻译成中文,希望对开发者有所帮助. 本系列是Googl

  • android开发教程之子线程中更新界面 2015-03-27

    本文主要介绍Android的Handler的使用方法.Handler可以发送Messsage和Runnable对象到与其相关联的线程的消息队列 每个Handler对象与创建它的线程相关联,并且每个Handler对象只能与一个线程相关联. Handler一般有两种用途:1)执行计划任务,你可以再预定的实现执行某些任务,可以模拟定时器.2)线程间通信.在Android的应用启动时,会创建一个主线程,主线程会创建一个消息队列来处理各种消息.当你创建子线程时,你可以再你的子线程中拿到父线程中创建的Han

  • Android Runnable 运行在那个线程 2012-05-03

    Runnable 并不一定是新开一个线程,比如下面的调用方法就是运行在UI主线程中的: Handler mHandler=new Handler(); mHandler.post(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub } }); 官方对这个方法的解释如下,注意其中的:"The runnable will be run on the user interface thread

  • C++线程优先级SetThreadPriority的使用实例 2014-05-28

    这篇文章主要介绍了C++线程优先级SetThreadPriority的使用实例,较为详细的讲述了C++线程及其优先级的用法,需要的朋友可以参考下 本文实例讲述了C++线程优先级SetThreadPriority的使用方法,分享给大家供大家参考.具体方法如下: // ThreadPriority.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <Windows.h> DWORD WINAPI ThreadProcIdl

  • 守护线程-配置文件实时加载实例 2011-07-06

    在java中有一类线程,专门在后台提供服务,此类线程无需显式关闭,当程序结束了,它也就结束了,这就是守护线程 daemon thread.如果还有非守护线程的线程在执行,它就不会结束. 守护线程有何用处呢?让我们来看个实践中的例子. 在我们的系统中经常应用各种配置文件(黑名单,禁用词汇),当修改配置文件后,一般要重启服务,系统才能够加载:当重启服务的代价比较高的情况下,这种加载方式不能满足我们的要求,这个时候守护线程该发挥它的作用了,它可以实时加载你的配置文件,无需重启.(当然,相当重要的配置文

  • 简短总结一下C#里跨线程更新UI 2012-04-16

    跨线程更新UI是写多线程程序尤其是通信类的程序经常遇到的问题,这里面主要的问题是冲突,比如数据线程想要更新UI的时候,用户同时也在更新UI,就会出现争用.C#里可以用 Control.CheckForIllegalCrossThreadCalls = false; 来关闭跨线程检测.但是这样做有一定的风险,容易让程序崩溃. 最好的办法是通过Invoke,这篇博客只是提供一个示例,至于那些线程同步.Invoke和BeginInvoke,Invoke底层实现神马的,有空再说吧. 一个简单的例子如下:

  • 在UI线程的oncreate方法中,操作软键盘无效 2012-11-26

    案例: 操作软键盘的代码如下: InputMethodManager methodManager = (InputMethodManager) this.getBaseContext().getSystemService(INPUT_METHOD_SERVICE); methodManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); 如果在UI线程中,并在activity的onCreate方法中操作软键盘,则无效. 而以下两

  • 并发编程基础三--join线程,后台线程,线程睡眠,线程让步,改变线程优先级 2013-02-06

    Java的线程支持提供了很多便捷方法,如标题. 1.join线程 join线程的意思就是在当前这个线程A里,加入另一个线程B,此时A阻塞,进入就绪状态,等B完成(结束,线程死亡),A才会继续执行. 这个方法通常由使用线程的程序调用,用以将大问题划分成许多小问题,每个小问题配一个线程,但所有小问题处理后,再调用主线程进一步操作. package org.credo.thread; public class Thread_join extends Thread{ public static void

  • Android中的Handler与多线程应用实例 2013-11-08

    这篇文章主要介绍了Android中的Handler与多线程应用实例,本文首先解释一下handler是用来干嘛的,然后通过例子介绍其在多线程中的应用,需要的朋友可以参考下 本文首先解释一下handler是用来干嘛的,然后通过例子介绍其在多线程中的应用. 什么是Handler handler通俗一点讲就是用来在各个进程之间发送数据的处理对象.在任何进程中,只要获得了另一个进程的handler则可以通过handler.sendMessage(message)方法向那个进程发送数据.基于这个机制,我们在

  • Android最佳实践之UI篇 2014-01-26

    引子 不管进行什么开发,桌面也好.移动端也罢,UI一直都是让人头大的一部分.那对于Android开发来说,在UI这一块,是否有什么最佳实践能让人少走一些弯路吗?这两天就这个问题搜了一圈,收获了不少. UI最佳实践的N条建议 1. 避免嵌套过多层级的布局 即使使用的全都是官方提供的基础布局和控件,也不意味着就能做出高效的UI布局设计.每个布局(layout),控件(Button.TextView等),都需要进行初始化,测量大小.定位以及绘制.布局里嵌套了过多的层级将带来相当大的性能开销.官方提供了

  • Android 模拟器(JAVA)与C++ socket 通讯 分享 2014-02-24

    Android 模拟器(JAVA)与C++ socket 通讯 分享,需要的朋友可以参考一下 C++ 作为Client端 view plaincopy to clipboardprint? // Client.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include #pragma comment(lib,"ws2_32.lib") #defi

  • android使用多线程更新ui示例分享 2014-04-25

    在Android平台中多线程应用很广泛,在UI更新.游戏开发和耗时处理(网络通信等)等方面都需要多线程,下面是一个在线程中更新UI的代码 Android线程涉及的技术有:Handler;Message;MessageQueue;Looper;HandlerThread. 下面看一段在线程中更新UI的代码: public class MainActivity extends Activity { private TextView timeLable; private Button stopBtn;

  • Java中的守护线程 & 非守护线程(简介) 2011-07-06

    Java中的守护线程 & 非守护线程 守护线程 (Daemon Thread) 非守护线程,又称用户线程(User Thread) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守护线程的保姆:只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作:只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作. 守护线程最典型的应用就是 GC (垃圾回收器) 守护线程通常是由虚拟机自行创建使用,不过通过编码同样可以创建守护线程,而且 very easy: Thre