多线程开发(三)-AnsycTask用法与解惑

第5节 AsyncTask

首先举个例子,获取手机上视频信息所需要的时间是个不能确定的事情。如果视频很少,也许几十毫秒就能完成,如果视频很多(比如几十个),也许就要花二十多秒。

安卓应用只有一个主线程-各个组件都是在这个线程中运行。作为组件的之一的Activity就是在这个线程中更新应用界面的,例如,用户点击界面上的一个按钮,按钮得到响应,整个过程就是在这个主线程里。所以这个主线程绝对不可以做耗时的操作。假如在按钮中做了耗时的操作,那么当它进行耗时操作的时候,你去点击界面上的其它按钮是不会有反应的,就好像程序冻在了那里。

代码的执行一旦连续占用这个线程超过一定的时间,系统就会弹出“程序无响应的”提示。

因此,我们可以考虑把获取视频信息的操作放到一个单独的线程thread中进行。

这就好比你在正在做一件事情A,突然另一件事情B来打扰你,你不得不停下手头的工作来完成,做完了才能继续之前的工作;这时如果有另外一个人(另一个线程)来帮助你,把事情B全部包揽了,那你就不用分心了。当另一个人把事情B做完后,告诉你一声就可以了。

5.1 异步操作

启动一个新的线程,分担耗时工作的方法是一种异步操作:我让你帮我做一件事情,布置任务后,我就去做其他的事情了,等你做完了再告诉我结果;

与它对应的是同步操作:我让你帮我做一件事情,布置任务后,我啥也不做,就等着你做完了告诉我结果;

获取视频信息是个异步操作,启动一个新线程-工作线程thread-查询视频信息,查询完成后,工作线程再将结果通知到主线程,让主线程将查询到结果的结果显示到界面上。界面的更新一定要在主线程中进行,不能在别的线程修改,否则系统后提示运行错误,这一点相当重要。因此我们一定要将查询的结果发送给主线程,让主线程处理界面的更新。

5.2 异步操作的方案

安卓系统提供的异步操作方案有:

  1. 创建工作线程thread和Handler,利用Handler在工作线程和主线程之间传递数据;
  2. 使用AsyncTask帮助类,AsyncTask中封装了工作线程,通过AsyncTask完成工作线程和主线程之间的数据传递;

第1种方案,已经在第3节里面介绍过了。

这里我们介绍第2种方案。

AsyncTask实际上它也是通过方案1实现的,只不过Android SDK对这套机制做了进一步封装,让使用者用起来更加方便。

AsyncTask适用于,

  1. 使用场景简单,只是单个任务的异步操作,没有多个线程之间的数据同步考虑;
  2. 使用方便,不用考虑太多的新线程创建的细节;

5.3 AsyncTask的使用

AsyncTask需要被继承成为一个新的子类来使用,在被继承时,要指定三种参数的类型-Param Progress Result,还需要实现doInBackground(Param...)函数,此外通常还要实现onProgressUpdate(Progress...) onPostExecute(Result) 两个回调函数。

class MyTask  extends AsyncTask<Param, Progress, Result> {

    @Override
    protected Result doInBackground(Param... params) {
        return result;
    }

    @Override
    protected void onProgressUpdate(Progress... progresses) {

    }

    @Override
    protected void onPostExecute(Result result) {

    }

    @Override
    protected void onCancelled() {

    }
}
  1. doInBackground(Param... params)函数:传入参数的Param类型就是AsyncTask<Param, Progress, Result>中指定的Param类型。它运行在新创建的工作线程当中。

    使用MyTask时,要在主线程中使用excute()方法传入不定长参数,让Task运行起来,

    MyTask task = new MyTask();
    task.excute(param0, param1, ..., paramN);

    不定长参数会以数组的形式传递到doInBackground()函数当中,

    @Override
    protected Result doInBackground(Param... params) {
        Param param0 = params[0];
        Param param1 = params[1];
        ......
        Param paramN = params[N];
    
        return result;
    }
  2. onProgressUpdate(Progress... progresses)函数:传入参数的Progress类型就是AsyncTask<Param, Progress, Result>中指定的Progress类型。

    doInBackground()中执行的是一个很耗时的工作,有时需要向主线程报告当前的运行状况,这就要使用到publishProgress()函数,publishProgress()也是使用的不定长参数,

    @Override
    protected Result doInBackground(Param... params) {
        ......
        publishProgress(progress1, progress2, ..., progressN)
    
        return result;
    }

    不定长参数会以数组的形式传递到onProgressUpdate()函数当中,

    @Override
    protected void onProgressUpdate(Progress... progresses) {
        Progress progress0 = progresses[0];
        Progress progress1 = progresses[1];
        ......
        Progress progressN = progresses[N];
    
    }
  3. onPostExecute(Result result)函数:传入参数的Result类型就是AsyncTask<Param, Progress, Result>中指定的Result类型。

    doInBackground()函数返回的类型也是Result

    @Override
    protected Result doInBackground(Param... params) {
        ......
    
        return result;
    }

    返回的结果作为参数传递给onPostExecute()函数,

    @Override
    protected void onPostExecute(Result result) {
    
    }
  4. onCancel()函数会在调用者取消AsyncTask的工作的时候被触发。

    要取消AsyncTask的工作,首先要在主线程中调用cancel()方法,

    task.cancel(true);

    因为在doInBackground()中执行的是一个很耗时的工作,需要时不时的检查自己是否被取消执行了,

    @Override
    protected Result doInBackground(Param... params) {
        ......
        if(isCancelled())
        {
            ......
            return result;
        }
    
        ......
        return result;
    }

    最后,onCancelled()函数会被触发,这个函数会在主线程中被执行,

    @Override
    protected void onCancelled() {
    
    }


综合上面的分析,自定义一个AsyncTask的方法如下,

class MyTask extends AsyncTask<Param, Progress, Result> {

    @Override
    protected Result doInBackground(Param... params) {
        Param param0 = params[0];
        Param param1 = params[1];
        ......
        Param paramN = params[N];

        while(!isCancelled())
        {
            ......
            publishProgress(progress1, progress2, ..., progressN);
        }

        return result;
    }

    @Override
    protected void onProgressUpdate(Progress... progresses) {
        Progress progress0 = progresses[0];
        Progress progress1 = progresses[1];
        ......
        Progress progressN = progresses[N];
        ......
    }

    @Override
    protected void onPostExecute(Result result) {

    }

    @Override
    protected void onCancelled() {

    }
}

使用一个AsyncTask的方法如下,

MyTask task = new MyTask();
task.excute(param0, param1, ..., paramN);
......
task.cancel(true);
时间: 2024-10-24 20:12:23

多线程开发(三)-AnsycTask用法与解惑的相关文章

ios多线程开发 GCD常见用法

1-延迟执行 可以安排其线程(1),主队列 dispatch_queue_t queue= dispatch_get_main_queue(); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), queue, ^{ NSLog(@"主队列--延迟执行------%@",[NSThread currentThread]); }); 可以安排其线程(2),并发队列 1.获取全局并发

Java进阶(三)多线程开发关键技术

原创文章,转载请务必将下面这段话置于文章开头处. 本文转发自Jason's Blog,原文链接 http://www.jasongj.com/java/multi_thread/ sleep和wait到底什么区别 其实这个问题应该这么问--sleep和wait有什么相同点.因为这两个方法除了都能让当前线程暂停执行完,几乎没有其它相同点. wait方法是Object类的方法,这意味着所有的Java类都可以调用该方法.sleep方法是Thread类的静态方法. wait是在当前线程持有wait对象锁

ios 多线程开发(三)Run Loops

Run loops是线程相关的一些基本东西.一个run loop是一个处理消息的循环.用来处理计划任务或者收到的事件.run loop的作用是在有事做的时候保持线程繁忙,没事的时候让线程挂起. Run loop的管理并不是完全自动的.你仍然需要设计代码来在合适的时候启动run loop来相应事件.Cocoa和Core Foundation都提供了run loop对象来配置和管理run loop.程序并不需要创建这些对象,每个线程,包括主线程都有一个对应的run loop对象.只有非主线程需要明确

Java多线程开发系列之四:玩转多线程(线程的控制2)

在上节的线程控制(详情点击这里)中,我们讲解了线程的等待join().守护线程.本节我们将会把剩下的线程控制内容一并讲完,主要内容有线程的睡眠.让步.优先级.挂起和恢复.停止等. 废话不多说,我们直接进入正题:  3.线程睡眠  sleep() 所有介绍多线程开发的学习案例中,基本都有用到这个方法,这个方法的意思就是睡眠(是真的,请相信我...).好吧,如果你觉得不够具体,可以认为是让当前线程暂停一下,当前线程随之进入阻塞状态,当睡眠时间结束后,当前线程重新进入就绪状态,开始新一轮的抢占计划!

.NET基础拾遗(5)多线程开发基础

Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 一.多线程编程的基本概念 下面的一些基本概念可能和.NET的联系并不大,但对于掌握.NET中的多线程开发来说却十分重要.我们在开始尝试多线程开发前,应该对这些基础知识有所掌握,并且能够在操作系统层面理解多线程的运行方式. 1.1 操作系统层面的进程和线程 (1)进程 进程代表了操作系统上运行着的一个应用程序.进程拥有自己的程序块

Windows多线程开发之并发线程程序研究

做为一名分布式服务器开发人员,在服务器开发领域.多线程开发和并发编程方面有自己的心得和经验,愿意分享给同仁,今讨论下Windows下线程并发程序开发. 下面用用两个线程实现一个简单的数组排序,演示了线程的基本用法. 原理是: 为了节省执行时间而添加并行,把问题划分为几个小问题,并分配给几个线程(分而治之),把问题划分成若干更小的单元,更容易在实现中创建并行逻辑.同时,在并行中使用系统资源能优化应用程序并提高其运行速度. #include "stdafx.h"  #include <

iOS多线程开发--NSThread NSOperation GCD

多线程 当用户播放音频.下载资源.进行图像处理时往往希望做这些事情的时候其他操作不会被中 断或者希望这些操作过程中更加顺畅.在单线程中一个线程只能做一件事情,一件事情处理不完另一件事就不能开始,这样势必影响用户体验.早在单核处理器时期 就有多线程,这个时候多线程更多的用于解决线程阻塞造成的用户等待(通常是操作完UI后用户不再干涉,其他线程在等待队列中,CPU一旦空闲就继续执行, 不影响用户其他UI操作),其处理能力并没有明显的变化.如今无论是移动操作系统还是PC.服务器都是多核处理器,于是“并行

为什么要多线程开发

一.单线程和多线程概述. 单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行. 单线程较多线程来说,系统稳定.扩展性极强.软件丰富.多用于点对点的服务.很多软件都有CPU单核单线程能力测试(single thread).我们都知道,多核多线程能力代表着整机性能的最高表现,而单核单线程能力则是可以体现在某些低功耗运行设定下的实际性能表现.用户需要知道自己的设备性能极限在哪里,也需要知道自己能日常够用到的性能大概有多少. 在固有的观念中,CPU核心数量的增多会被认

Java多线程开发系列之番外篇:事件派发线程---EventDispatchThread

事件派发线程是java Swing开发中重要的知识点,在安卓app开发中,也是非常重要的一点.今天我们在多线程开发中,穿插进来这个线程.分别从线程的来由.原理和使用方法三个方面来学习事件派发线程. 一.事件派发线程的前世今生 事件(Event)派发(Dispatch)线程(Thread)简写为EDT,也就是各个首字母的简写.在一些书或者博客里边也将其译为事件分发线程.事件调度线程.巴拉巴拉,总之,知道这些名字就行.笔者认为这里翻译成派发更准确点. 熟悉Swing和awt编程的小伙伴对事件派发线程