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.

(0)

相关推荐

  • Android判断App前台运行还是后台运行(运行状态)

    本文通过图文并茂的方式给大家介绍android判断app状态的相关内容,具体详情如下所示: 要了解这块,首先需要明白一些概念,app,process,task 1.process就是进程,是linux的概念. 2.一般一个app拥有一个uid,运行在一个进程里,如果app中给service等定义不同的uid,那Service就运行在另外一个进程里,也就是说uid就相当于进程的id一样,一个uid就代表一个进程:也可以几个app定义一个uid,那他们就运行在一个进程里了. 3.task是andro

  • Android中使用IntentService创建后台服务实例

    IntentService提供了在单个后台线程运行操作的简单结构.这允许它操作耗时操作,而不影响UI响应.同样,IntentService也不影响UI生命周期事件,所以,它在某些可能关闭AsyncTask的情况下,仍会继续运行(实测在Activity的onDestory里写AsyncTask无法运行). IntentService有如下限制: 1.它不能直接影响UI.要把结果反映给UI,需要发给Activity 2.工作请求会顺序运行.如果一个操作未结束,后面发送的操作必须等它结束(单线程) 3

  • android教程之使用asynctask在后台运行耗时任务

    , Android中实现了默认的进度提示对话框,即ProgressDialog,通过实例化和一些简单设置,就可以使用了. 复制代码 代码如下: private class DownloadDBTask extends AsyncTask<String, Integer, String> {           // 可变长的输入参数,与AsyncTask.exucute()对应           ProgressDialog pdialog;           public Downloa

  • 解析后台进程对Android性能影响的详解

    Android现在这么火,各种的设备也是琳琅满目,高中低等,大小屏幕都有,但是它始终未能达到iOS那样的令人称赞的卓越体验和性能,其操作的流畅度,性能和安全性方面总是略输iOS一筹.据说iPhone4虽然是单核512M内存,但是比Android的双核1G内存的操作起来更流畅,iPad2虽然是也只有512M的内存但是操作起来比Android四核1G内存还要流畅.另外在安全性方面也不如iOS. 造成Android性能,待机时间,操作流畅和安全性不好的原因是Android后台进程的管理. Androi

  • Android后台定时提醒功能实现

    前提:考虑到自己每次在敲代码或者打游戏的时候总是会不注意时间,一不留神就对着电脑连续3个小时以上,对眼睛的伤害还是挺大的,重度近视了可是会遗传给将来的孩子的呀,可能老婆都跟别人跑了. 于是,为了保护眼睛,便做了个如下的应用: 打开后效果: 时间到之后有后台提醒: 好了,接下来说一下做这样一个APP主要涉及到的知识点: Service:使用service,便可以在程序即使后台运行的时候,也能够做出相应的提醒,并且不影响手机进行其他工作. AlarmManager:此知识点主要是用来计时,具体的在代

  • 深入解析Android系统中应用程序前后台切换的实现要点

    在介绍程序实现之前,我们先看下Android中Activities和Task的基础知识. 我们都知道,一个Activity 可以启动另一个Activity,即使这个Activity是定义在别一个应用程序里的,比如说,想要给用户展示一个地图的信息,现在已经有一个Activity可以做这件事情,那么现在你的Activity需要做的就是将请求信息放进一个Intent对象里,并且将这个Intent对象传递给startActivity(),那么地图就可显示出来了,但用户按下Back键之后,你的Activi

  • Android 后台发送邮件示例 (收集应用异常信息+Demo代码)

    上一次说了如何收集我们已经发布的应用程序的错误信息,方便我们调试完善程序.上次说的收集方法主要是把收集的信息通过Http的post请求把相关的异常信息变成请求参数发送到服务器.这个对做过web开发的人来说,服务端处理是很简单.不过对很多没做个web的人来说却是麻烦事.今天介绍个更简单的方法,我们把异常信息收集后,通过后台发送邮件方法,把相关异常信息发送到我们指定的邮箱里面. 这篇文章是实用性文章,不会涉及太多理论分析.主要是让大家看了以后知道怎么在自己的应用里面添加这个功能. 1.第三方库这次发

  • Android编程获取手机后台运行服务的方法

    本文实例讲述了Android编程获取手机后台运行服务的方法.分享给大家供大家参考,具体如下: public static String getRunningServicesInfo(Context context) { StringBuffer serviceInfo = new StringBuffer(); final ActivityManager activityManager = (ActivityManager) context .getSystemService(Context.A

  • Android开发中实现应用的前后台切换效果

    在介绍程序实现之前,我们先看下Android中Activities和Task的基础知识. 我们都知道,一个Activity 可以启动另一个Activity,即使这个Activity是定义在别一个应用程序里的,比如说,想要给用户展示一个地图的信息,现在已经有一个Activity可以做这件事情,那么现在你的Activity需要做的就是将请求信息放进一个Intent对象里,并且将这个Intent对象传递给startActivity(),那么地图就可显示出来了,但用户按下Back键之后,你的Activi

  • Android判断当前应用程序处于前台还是后台的两种方法

    1.通过RunningTaskInfo类判断(需要额外权限): 复制代码 代码如下: /**     *判断当前应用程序处于前台还是后台     */    public static boolean isApplicationBroughtToBackground(final Context context) {        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SER

  • Android 进入设备后台data文件夹的办法

    大家都知道,我们在进行android项目开发时,当涉及到需要存取数据,也就是需要进行数据的互动时,我们就需要把数据存放在虚拟设备的data 文件夹中.之前在相关书籍中了解到如何把文件上传到设备,如前面所说的mp3,mp4播放器中需要上传到设备中的音频及视频文件.方法如下:C:> adb push c:codesamplevideo.mp4 /data/samplevideo.mp4 今天在网上无意中又了解到了如何进入设备的后台的命令,希望对大家有帮助. 可以使用 adb shell 进入设备后台

  • Android中使用Service实现后台发送邮件功能实例

    本文实例讲述了Android中使用Service实现后台发送邮件功能.分享给大家供大家参考,具体如下: 程序如下: import android.app.Activity; import android.content.Intent; import android.content.res.Resources.NotFoundException; import android.os.Bundle; import android.widget.TextView; public class A05Ac

  • Android中Service(后台服务)详解

    1.概念: (1).Service可以说是一个在后台运行的Activity.它不是一个单独的进程,它只需要应用告诉它要在后台做什么就可以了. (2).它要是实现和用户的交互的话需要通过通知栏或者是通过发送广播,UI去接收显示. (3).它的应用十分广泛,尤其是在框架层,应用更多的是对系统服务的调用. 2.作用: (1).它用于处理一些不干扰用户使用的后台操作.如下载,网络获取.播放音乐,他可以通过INTENT来开启,同时也可以绑定到宿主对象(调用者例如ACTIVITY上)来使用. (2).如果说

  • Android App后台服务报告工作状态实例

    本节讲运行在后台服务里的工作请求,如何向发送请求者报告状态.推荐用LocalBroadcastManager发送和接收状态,它限制了只有本app才能接收到广播. 从IntentService汇报状态 从IntentService发送工作请求状态给其他组件,先创建一个包含状态和数据的Intent.也可以添加action和URI到intent里. 下一步,调用 LocalBroadcastManager.sendBroadcast()发送Intent,应用中所有注册了接收该广播的接收器都能收到.Lo

随机推荐