Android学习笔记十:异步处理

摘要:
主线程通常又被称为UI线程,Android只允许UI线程修改Activity里的UI组件。具体方法见:http://blog.csdn.net/logicteamleader/article/details/46591499】三:单个异步任务——AsyncTask消息传递机制看起来比较复杂,涉及到了消息队列的应用,这几乎是大型Web应用的架构层面才会用到的模式了。如果只是单个的异步任务,用消息传递机制就有些过于麻烦了,为此,Android为我们提供了一个辅助类——AsyncTask。

转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/7520700.html

一:基础概念

UI线程:当Android程序第一次启动时,Android会同时启动一条主线程(Main Thread),主线程主要负责处理与UI相关的事件,如用户的按键事件、屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。主线程通常又被称为UI线程,Android只允许UI线程修改Activity里的UI组件。

子线程:在程序的activity中创建、启动的线程为子线程,子线程中不能操作UI组件。

后台任务:后台任务一般用子线程来完成,通常用于执行一些耗时任务如:复杂计算、下载文件等。因为这些操作是与UI线程同时运作的,所以又称为异步操作。

二:异步方式之——消息传递机制

我们知道,只有UI线程才能修改、操作界面组件,那么其他子线程中的信息如何反映到UI中呢?那就需要子线程把信息汇总到UI线程,由UI线程显示到组件上。

这个过程,就是消息传递机制。

1)消息传递机制原理图

Android学习笔记十:异步处理第1张

2)消息传递机制解释

首先,UI线程中维护一个消息队列MessageQueue、一个循环者Looper、一个处理者Handler:消息队列负责接受、存储其他子线程发送过来的消息,等待UI线程处理;循环者不停地轮询消息队列,每次都提取队首一个消息;处理者负责处理Looper提取出来的消息,并负责把结果在UI进行呈现。其中,MessageQueue和Looper随着UI线程启动而自动创建并运行,Handler则需要手动定义

其次,在UI线程中创建并启动子线程,子线程中通过同一个handler(通常这个handler为acticity代码中的全局变量,因此子线程中可见)来发送消息,从而把消息发送到了当前UI线程的handler对应的消息队列中。

3)实现步骤

根据消息传递机制的原理,我们只需针对实现各个环节需要的东西即可。

首先:定义、创建Handler,重写其中的handlerMessage方法,处理消息

private Handler mHandler = newHandler() {  
        @Override  
        public voidhandleMessage(Message msg) {  
            switch(msg.what) {  
                //根据消息内容,作处理
}  
        }  
    };  

然后:定义子线程,在其中定义发送消息语句

 Runnable runnable = newRunnable() {  
        @Override  
        public voidrun() {  
            Message message = newMessage();  
            message.what =消息标签;  
            mHandler.sendMessage(message);  //handler是UI线程中的handler
}  
    };  

最后:根据条件,创建子线程实例并启动

mThread = newThread(runnable);  
mThread.start();  

4)应用场景

Handler机制适合多个子线程存在的情况,这样可以把多个子线程发送过来的信息在UI线程中统一处理、绘制呈现。

【附:如果需要在子线程中使用handler和looper,则需要获取到UI线程中的handler、looper对象。具体方法见:http://blog.csdn.net/logicteamleader/article/details/46591499

三:单个异步任务——AsyncTask

消息传递机制看起来比较复杂,涉及到了消息队列的应用,这几乎是大型Web应用的架构层面才会用到的模式了。

如果只是单个的异步任务,用消息传递机制就有些过于麻烦了,为此,Android为我们提供了一个辅助类——AsyncTask。

AsyncTask类,可以理解为异步任务执行者;这个类的设计目的很明确,就是为了“执行一个较为耗时的异步任务(最多几秒钟),然后更新界面”。

1:使用AsyncTask

1)继承AsyncTask,定义子类,重写其中的几个方法:

AsyncTask需要重写5个方法,分别是:

1、onPreExecute方法:准备运行,该回调函数在任务被执行之后立即由UI线程调用,一般可以显示进度条。

2、doInBackground(Params ...)方法:正在后台运行,通常在这里执行耗时的后台计算,计算结果返回给函数,这里如果AsyncTask的第三个参数是Void的话不需要返回,这里不能更新UI,但是可以调用publishProgress(Progress ...)方法完成。

3、onProgressUpdate(Progress ...)方法:进度更新,UI线程在publishProgress(Progress ...)方法调用完成后被调用,一般动态显示一个进度。

4、onPostExecute(Result)方法:完成后台任务,会返回,这里可以进行些UI的操作,比如提醒任务执行的结果,以及关闭掉进度条对话框等。

5、onCancelled方法:取消任务,在调用AsyncTask的cancel()方法的时候调用。

class ViewContentTask extends AsyncTask<Void, Integer, Boolean>{//三个范型分别对应下面doInBackground、onProgressUpdate、onPostExecute三个方法的参数类型
        @Override  
        protectedBoolean doInBackground(Void... voids) {  
            return null;  
        }  
        @Override  
        protected voidonProgressUpdate(Integer... values) {  
        }  
        @Override  
        protected voidonPostExecute(Boolean b) {  
            //操作UI组件
        }  
        @Override  
        protected voidonPreExecute() {  
        }  
        @Override  
        protected voidonCancelled() {  
        }  
    }  
  

2)创建异步任务实例,启动异步任务

ViewContentTask  task = newViewContentTask();  
task.execute();  

2:AsyncTask工作原理

当一个异步任务被执行时,要经历四步:
onPreExecute(),在UI线程中执行,它会在异步任务开始前执行,一般用来设置任务参数;
doInBackground, 最重要的方法,在子线程中执行(事实上,只有它在子线程中执行,其他方法都在UI线程中执行)。当onPreExecute结束后,本方法立刻执行,它用 来进行后台的耗时计算,异步任务的参数会被传给它,执行完成的结果会被送给第四步;执行途中,它还可以调用publishProgress 方法来通知UI线程当前执行的进度;
onProgressUpdate, 当publishProgress 被调用后,它在UI线程中执行,刷新任务进度,一般用来刷新进度条等UI部件;
onPostExecute, 当后台的异步任务完成后,它会在UI线程中被调用,并获取异步任务执行完成的结果。

免责声明:文章转载自《Android学习笔记十:异步处理》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Nginx与安全有关的几个配置关于 Cannot forward after response has been committed的错误下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Golang Web入门(1):自顶向下理解Http服务器

摘要 由于Golang优秀的并发处理,很多公司使用Golang编写微服务。对于Golang来说,只需要短短几行代码就可以实现一个简单的Http服务器。加上Golang的协程,这个服务器可以拥有极高的性能。然而,正是因为代码过于简单,我们才应该去研究他的底层实现,做到会用,也知道为什么这么用。 在本文中,会以自顶向下的方式,从如何使用,到如何实现,一点点的分...

JAVA多线程提高十三:同步集合类的应用

 1.引言   在多线程的环境中,如果想要使用容器类,就需要注意所使用的容器类是否是线程安全的。在最早开始,人们一般都在使用同步容器(Vector,HashTable),其基本的原理,就是针对容器的每一个操作,都添加synchronized来进行同步,此种方式尽管简单,但是其性能是非常地下的,所以现在已经不怎么使用了。人们普遍会使用并发的容器,在JDK1....

C/S系统实现两数求和(非阻塞+epoll+心跳包检测用户在线状况+滚动日志+配置文件.)

C/S系统实现两数求和 任务要求: 实现配置文件 实现日志滚动 设置非阻塞套接字,EPOLL实现 检测客户端的连接,设置心跳检测 主线程 + 心跳检测线程 + EPOLL的ET模式处理事务线程 注意事项:设置volatile类型跳出死循环 作品简介: 本次实验分为bin,config,include,log,src五个文件夹以及一个makefile...

python并发编程:阻塞IO

阻塞IO(blocking  IO) 在Linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样:   当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据。对于network io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的udp包),这个时候kernel...

ThreadPool.QueueUserWorkItem的性能问题

在WEB开发中,为了减少页面等待时间提高用户体验,我们往往会把一些浪费时间的操作放到新线程中在后台运行。 简单的实现代码就是: //代码一 new Thread(()=>{ //do something }).Start();   但是对于一个请求量大的网址这样做是很不现实的——每一个操作都要开启一个新线程,最终会因CPU不堪重负而...

synchronized同步代码块锁释放

今天发现自己写的线上程序出现数据库不能同步的问题,查看日志已经停止记录,随后使用jstack查看线程的运行状况,发现有个同步线程锁住了。 以下是jstack -l 637  问题线程的内容。 "schedulerJob-t-291" #314 daemon prio=5 os_prio=0 tid=0x00007f7d64844800 nid=0x3d5...