Android异步处理机制

来源:互联网 发布:laravel获取表单数据 编辑:程序博客网 时间:2024/05/20 20:04

一个安卓应用程序启动的时候会单独创建一个进程。默认情况下,该应用程序内的四大组件:Activity、Service、ContentProvider以及Broadcast Receiver都在该进程空间内运行。各应用程序的进程空间相互独立,不允许相互访问资源。每个进程空间中会有很多线程运行,其中有一个主线程(也成为UI线程),根据Android单线程模型,所有更新UI的操作必须在主线程中进行,不允许其他子线程更新UI界面,否则会造成线程安全问题。

Android应用程序中往往会有一些耗时的操作,如从网上下载图片。如果让此操作在主线程中完成,在下载期间不会处理用户的任何输入,会给用户一种卡屏的假象,而且如果下载操作超过5S,系统会自动给出ANR(程序没有回应)的提示对话框。所以,应该再开一个子线程,把这种耗时操作放在子线程中进行处理。执行完成后,如果需要更新用户界面,再通知主线程去更新界面。由上述表述,要解决的问题是:1.如何创建子线程?2.如何在主线程和子线程间传递数据?3.Android是否提供了简单的接口来处理进程间的通信问题?

一、             如何创建子线程?

在java中使用线程的方式有两种:

1.      定义一个线程类

1)  定义一个类继承MyThread自Thread类,并实现其中的run()方法

2)  在主线程中新建MyThread类的对象,用父类Thread来引用该对象

3)  调用上述对象的start()方法开始运行线程

2.      定义一个实现Runnable的类

1)  定义个一类MyRunnable实现Runnable接口,并实现其中的run()方法

2)  在主线程中新建MyRunnable的对象,新建一个Thread类对象,将MyRunnable传递给新建的Thread类。

3)  调用Thread类对象的start()方法

主线程一般通过一个布尔类型的标志来决定是否停止线程的运行。

Thread.sleep(); 用来休眠当前线程

Thread.currentThread().getName();  用来获取当前运行线程的名称

二、            如何在主线程和子线程之间传递消息

对于应用程序中比较耗时的操作,需要放在子线程中执行,而子线程执行完后通常需要更新UI界面。又由于更新UI的操作必须放在主线程中进行,所以主线程和子线程之间需要进行数据传递。解决这个问题的方法就是Android消息传递机制,其中最主要的类,也是需要程序员干涉的类就是Handler类。

Android消息传递机制设计到的类主要有四个:

Handler,处理者,用于发送和处理消息

Message,消息,一个数据结构包含了消息的ID、消息的处理对象(某个Handler)以及处理的数据,一般需了解三项:what(消息类型的整型值)、arg1(额外消息参数)、arg2(额外消息的参数)

MessageQueue:消息队列,一个存放消息的数据结构

Looper:抽取者,一个线程可以产生一个Looper,用来管理一个MessageQueue,将其中的Message从队列中取出并根据target交给相应的Handler来处理。

 

Android Runtime在应用启动的时候,都会为应用程序的UI线程分配一个MessageQueue和一个Looper。但是不会为其他的子线程分配这些。如果在主线程定义一个Handler,那么这个Handler就会和该主线程的MessageQueue和Looper绑定。Handler通过sendMessage(msg)方法发送的消息会被放到MessageQueue中,当MessageQueue中一有消息,Looper就会从中取出消息,根据消息的target将消息交给相应的Handler来处理(此处因为绑定所以直接交予绑定的Handler处理),会调用Handler的handleMessage()方法。Handler在发送消息的时候通常会将消息的target设成自己。使用方法如下:

1)        在主线程中定义MyHandler类(继承Handler)的对象,这样就会与主线程的消息队列和Looper绑定。

2)        在子线程中MyHandler类对象获得消息对象(obtainMessage()),添加数据信息(setData(bundle)),发送消息到绑定的消息队列(sendMessage(msg))

3)        一旦消息队列中有消息,就会回调handleMessage(msg)方法,可以在这个方法中对消息进行处理,比如更新UI,因为该方法位于主线程中,所以不会报错。

Handler发送Runnable对象:

1)  Handler通过调用post(myRunnable)方法,将一个Runnable对象发送到消息队列

2)  Looper处理到Runnable对象时,会调用它的run()方法(运行在主线程中,直接调用run()方法,而不是去调用Thread.start())。

3)  在run()方法中利用handler发送一个消息到消息队列

4)  调用handleMessage()方法,在方法中完成一些更新UI操作,最后又将该Runnable对象发送到消息队列中。

通过上述过程,可以达到循环执行run()方法并更新UI的效果。这里run()方法是在主线程中运行,可以通过使用HandlerThread来达到在子线程中运行run()方法。

三、            Android异步处理机制的一些简单方法

1.      runOnUiThread(Runnalbe)方法的使用:

由于只有在UI线程中才能更新UI界面,使用该方法可以保证传入Runnable对象的run方法在UI线程中执行。所以,可以将需要更新UI的代码写到一个Runnable对象的run方法中传给runOnUiThread()方法来执行。

2.      AsyncTask的使用

AsyncTask类对线程间的通信进行了很好的封装,提供了简单的编程方式来使后台线程与UI线程进行通信,后台线程执行异步任务,并把操作结果通知给UI线程。

1)  新建一个类继承自AsyncTask类,该类是泛型类型,需要给定参数类型化,一共有三个参数,第一个参数是doInBackground()回调方法的接受参数,第二个参数是onProgressUpdate()回调方法的接受参数,第三个参数是onPostExcute()方法的接受参数,doInBackground()方法的返回类型。

该类一共有5个回调方法:

任务执行前onPreExcute(): 该回调方法在任务被执行后由UI线程立即调用,一般完成一些UI界面的初始化工作。

n  任务执行doInBackground():该方法在后台运行,运行在后台线程中,完成一些耗时操作,完成后返回的结果传给onPostExcute()方法。在该方法中也可以使用publishProgress()来调用onProgressUpdate()方法。

n  任务执行中onProgressUpdate():该方法在UI线程中运行,完成任务进度的更新。

n  任务执行完onPostExcute():在UI线程中运行,会在doInBackground方法执行完后执行。

n  任务执行中onCancelled():该方法在调用AsyncTask对象的cancel()方法时调用。

2)  在主线程中通过调用AsyncTask对象的excute()方法执行。

0 0
原创粉丝点击