在异步线程中更新UI的方法与流程

文档序号:12463066阅读:357来源:国知局
在异步线程中更新UI的方法与流程

本发明涉及安卓系统中的UI更新,尤其涉及一种在异步线程中更新UI的方法及系统。



背景技术:

在android系统中,每个app运行时系统都会给app分配一个主线程用来处理app自身的刷新操作,如果在主线程中进行一些复杂的耗时处理,就会造成主线程短暂的停顿卡住,给用户造成应用卡顿的感觉,比如进行一些文件的读写操作,网络的访问,数据库的读取等,并且在android中如果主线程停顿时间过长,系统会直接给出ANR,造成对用户的体验大打折扣,并且在android高版本上,所以一般在android开发时,需要将这些操作放在异步线程中,等操作好了,再将结果反馈给主线程,通知主线程进行更新UI(User Interface用户界面)的操作。不过某些情况下,可能需要自己实现一个UI的界面,让其更新与主线程分离,所以更新就需要在自己的线程中,而在android中如果直接在异步线程中更新UI的话,会发出系统抛出的异常,使应用挂掉。

目前常规的方法:在异步线程更新UI,其实其基本原理是,在异步线程中将数据获取成功后,然后通过持有主线程消息队列的handler将数据获取成功的消息传递到主线程,然后在主线程进行更新UI,其本质UI的更新操作还是在主线程。以图片异步加载举例,当应用异步加载图片时,首先创建一个异步的线程,然后在该线程中进行耗时的操作(图片的下载过程),当图片下载完成后通过将下载好的图片转成Bitmap对象,然后将消息发送到主线程,主线程中的ImageView将bitmap加载显示出来,创建异步线程可以通过创建Thread对象或者AsyncTask对象(这两个都是在android中创建异步线程的工具类),将异步线程的消息发送到主线程可以通过handler的post方法,或者activity的runOnUiThread方法,其参数都是发送一个runable对象,其实runOnUiThread内部也是调用handler的post方法,也有可以通过handler的sendMessage方法来进行操作,但是其内部也是通过post方法执行的,从上面描述的原理可以知道,其实常规中异步线程更新UI的本质就是异步线程向主线程发送消息,主线程收到消息后在主线程中更新UI,其根本没有在异步线程中更新UI,前面提到过android中直接在异步线程中更新UI会抛出异常,导致应用crash,所以常规方法中绕过了这个问题。



技术实现要素:

本发明要解决的技术问题在于针对现有技术中更新UI的方式要么使系统主线程出现短暂的停顿卡住,要么会导致系统抛出异常使应用挂掉的缺陷,提供一种在异步线程更新UI的方法,其能做到与应用主UI进行完全的隔离,更新设置等与主UI互相不干扰,提高用户体验,同时也能有效减轻主线程的压力,分担视图刷新的资源消耗。

本发明解决其技术问题所采用的技术方案是:

提供一种在异步线程中更新UI的方法,包括以下步骤:

创建更新UI的异步线程,包括重写该异步线程的run方法,并通过安卓系统的WindowManager在该异步线程中创建新的根视图rootview;

在异步线程中创建消息循环,包括创建一消息队列,用于阻塞该异步线程的run方法,并防止该异步线程中的根视图rootview被销毁;还包括添加逻辑:如果有UI刷新的操作,则在异步线程中进行刷新;若无,则保持等待状态;

将UI更新操作的消息发送到消息队列,并在异步线程中更新UI。

本发明所述的方法中,在创建异步线程循环中,若无UI刷新操作,则使异步线程让出所占用的系统CPU。

本发明所述的方法中,所述消息队列采用MessageQueue,其为安卓系统提供的基于epoll的阻塞队列。

本发明所述的方法中,步骤“创建异步线程循环”具体通过安卓系统中的Looper工具提供的prepare方法来创建当前线程的Looper对象,当prepare方法调用后,通过调用Looper对象的loop方法创建消息队列并且处于等待状态,则在取消消息队列之前,该异步线程的run方法一直处于运行状态,同时在没有UI刷新操作时,让出所占用的CPU。

本发明所述的方法中,所述消息队列具体通过安卓系统提供的Handler工具来处理,将Handler对象绑定到指定的Loop对象中,当需要发送更新UI操作时,直接调用handler对象的post方法,对异步线程的UI进行各种控制。

本发明所述的方法中,步骤“创建新的根视图rootview”具体包括:

通过安卓系统中的context调用其getSystemService方法,获取系统的窗口服务,并返回一个WindowManger对象;

创建一个布局作为异步UI的根视图rootview,然后调用WindowManger的addview方法,将创建的根视图rootview添加进去。

本发明所述的方法中,调用addview方法时需要传入WindowManager.LayoutParams对象,该对象中包括分别用来设置根视图布局layout宽高的成员winth和成员height,该对象中还包括format成员以及表示窗体类型的type。

本发明所述的方法中,所述窗体类型与主线程保持一致。

本发明还提供了一种在异步线程中更新UI的系统,包括:

异步线程创建模块,用于创建更新UI的异步线程,包括重写该异步线程的run方法,并通过安卓系统的WindowManager在该异步线程中创建新的根视图rootview;

消息循环创建模块,用于对异步线程创建消息循环,包括创建一消息队列,用于阻塞该异步线程的run方法,并防止该异步线程中的根视图rootview被销毁;还包括添加逻辑:如果有UI刷新的操作,则在异步线程中进行刷新;若无,则保持等待状态;

更新模块,用于将UI更新操作的消息发送到消息队列,并在异步线程中更新UI。

本发明产生的有益效果是:本发明通过安卓系统的WindowManager在该异步线程中创建新的根视图rootview,从而创建用于更新UI的异步线程,使其与应用主UI进行完全的隔离,更新设置等与主UI互相不干扰,可以运用在某些复杂容错率比较低的视图上,防止这些视图在运行过程中出现问题干扰到应用本身UI的情况;能有效减轻主线程的压力,分担视图刷新的资源消耗。

附图说明

下面将结合附图及实施例对本发明作进一步说明,附图中:

图1是本发明实施例在异步线程中更新UI的方法的流程图;

图2是本发明实施例在异步线程中更新UI系统的结构示意图。

具体实施方式

为了使本发明的目的、技术方案及优点更加清楚明白,以下结合附图及实施例,对本发明进行进一步详细说明。应当理解,此处所描述的具体实施例仅用以解释本发明,并不用于限定本发明。

先对相关专业术语进行解释如下:

ANR:在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择“等待”而让程序继续运行,也可以选择“强制关闭”。所以一个流畅的合理的应用程序中不能出现anr,而让用户每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样系统不会显示ANR给用户。默认情况下,在android中Activity的最长执行时间是5秒,BroadcastReceiver的最长执行时间则是10秒。

epoll:epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。

单例:保证某个类的对象在程序运行中只存在一个,在后文中的线程单例表明,该对象在线程中只存在一个。

本发明可在android中实现异步线程刷新UI,其能满足在异步线程中创建、显示以及更新UI。

本发明实施例的在异步线程中更新UI的方法,如图1所示,包括以下步骤:

S1、创建更新UI的异步线程,包括重写该异步线程的run方法,并通过安卓系统的WindowManager在该异步线程中创建新的根视图rootview;

S2、在异步线程中创建消息循环,包括创建一消息队列,用于阻塞该异步线程的run方法,并防止该异步线程中的根视图rootview被销毁;还包括添加逻辑:如果有UI刷新的操作,则在异步线程中进行刷新;若无,则保持等待状态;

S3、将UI更新操作的消息发送到消息队列,并在异步线程中更新UI。

步骤S1中,创建一个异步线程UI的环境具体为:

在android中,创建一个异步线程直接通过java提供的Thread类(或者通过Android的AysnTask和HandlerThread创建异步线程),然后重写其run方法就行,run方法中做的处理操作就会运行在当前创建的线程当中,前面提到过,如果直接在android中在异步线程中操作UI系统会抛出异常,然而系统的这个异常的判断是通过比较更新的UI线程与创建其视图根元素(rootview)是否是同一个线程来判断的,所以为了规避这个判断,这里异步线程也需要创建自己的rootview,可以模拟系统创建UI视图的方法,通过WindowManger创建。首先通过context调用其getSystemService(“window”)方法获取系统的窗口服务,其返回一个WindowManger对象,然后创建一个布局layout作为异步UI的视图根元素rootview,然后调用WindowManger的addview的方法,将创建的rootview添加进去。

1)在调用addview方法时还需要传入另外一个参数,即WindowManager.LayoutParams对象,该对象中有成员winth,height,分别用来设置根视图布局layout的宽高,还有format成员,这里传入为PixelFormat.RGBA_8888,表示是以RGB8888格式的视图(4个8分别表示A透明度,以及RGB三基色),还有非常重要的成员type表示窗体的类型,虽然这里视图与主线程的视图分开,但是窗体类型还是与主线程保持一致,使用WindowManager.LayoutParams.TYPE_APPLICATION,表示是应用的类型。

2)布局设置,在根视图rootview设置好了之后,可以把需要放入异步线程的视图传入之中,比如自己定义的布局是layout,直接调用rootview的addview方法就行,之后想要更新layout,就直接在线程中更新就行。步骤S2中在异步线程中创建循环具体为:

如果直接在异步线程中创建根视图的话,当异步线程的run方法结束时,根视图就会被系统回收销毁,所以这里需要通过创建一个消息队列,让其将run方法阻塞住,防止其立刻执行完成造成创建好的根视图立即被销毁,然后添加逻辑,如果有UI刷新的操作就在异步线程中进行刷新,如果没有就什么也不做,但是为了性能考率,防止直接通过循环造成系统CPU大量被消耗,这里最好做到当没有消息时,异步线程能让出系统CPU供其他资源使用,所以这里可以使用消息队列MessageQueue,可以理解的是,还可以通过BlockingQueue来实现。消息队列是android提供的一种基于epoll的阻塞队列,epoll是一种在linxu上的io复用模型,其主要特点就是,在有事件的时候会通知监听者,当没有的话会让出CPU,所以这里通过消息队列MessageQueue能够很好的利用cpu,在android中对线程创建消息循环可以通过系统提供Looper工具,Looper工具类中有一个静态的Threadlocal对象,当各个线程其操作时,Threadlocal保证每个线程都有自己的一份该变量,而在Looper中的Threadlocal对象正好存储的是一个Looper对象,所以凡是使用了Looper工具的线程,都持有一个自己的Looper对象,从而保证所谓的线程单例。Looper类提供prepare方法来创建当前线程的Looper对象,当prepare方法调用后通过调用Looper对象的loop方法创建消息队列并且处于等待状态,这样在取消消息队列之前,线程run方法一直处于运行状态,同时在没有事件时,会让出CPU控制权,节省系统资源。

步骤S3中发送并处理UI更新操作的消息具体为:

在消息循环建立之后,其会一直阻塞,并处于等待状态,所以我们需要将一些更新的消息发送到消息队列,在android中提供了Handler工具来处理消息队列,Handler对象可以绑定到指定的Loop对象中,然后其发送消息就能发到其绑定Loop对象持有的消息队列中,在Handler对象创建时,将2中创建好的Loop对象作为传入进行传入,然后当需要发送更新UI操作时,可以直接调用handler对象的post方法,post方法接收一个实现了runnable接口的对象,runnable接口中有run方法,每个实现了runnable接口的对象都必须实现其run方法,而handler就是将run方法中执行的操作发送到了其Loop的线程中,所以这里可以将需要更新UI的操作放入到run方法中,通过post方法发送到消息队列中,然后Loop持有的消息队列从队列中读取一个消息,进行处理就能对异步线程的UI进行各种控制(这里虽然可以通过Handler进行更新消息,但是这个Handler对与常规方法的对象的区别是,它持有的是异步线程的消息队列,所以所有的UI的更新还是处于异步线程当中,而常规方法中的Handler对象持有的是主线程的消息队列,UI的更新处于主线程中)。

此方法可以运用在动态锁屏的应用当中,动态锁屏应用一般对资源的要求比较大,如果将UI的视图放在主线程中,然后更新的话,可能造成主线程的压力,但是通过本方法的话,可以将锁屏的所有UI元素放入自己创建的异步线程的rootview当中,这样锁屏的所有动态效果都将在异步中进行更新,完全与主线程脱离,从而将达到更加流畅的体验。

本发明实施例在异步线程中更新UI的系统主要为实现上述实施例的方法,如图2所示,包括:

异步线程创建模块10,用于创建更新UI的异步线程,包括重写该异步线程的run方法,并通过安卓系统的WindowManager在该异步线程中创建新的根视图rootview;

消息循环创建模块20,用于对异步线程创建消息循环,包括创建一消息队列,用于阻塞该异步线程的run方法,并防止该异步线程中的根视图rootview被销毁;还包括添加逻辑:如果有UI刷新的操作,则在异步线程中进行刷新;若无,则保持等待状态;

更新模块30,用于将UI更新操作的消息发送到消息队列,并在异步线程中更新UI。

综上,本发明在异步线程中更新UI的方法,其能做到与应用主UI进行完全的隔离,更新设置等与主UI互相不干扰,可以运用在某些复杂容错率比较低的视图上,防止这些视图在运行过程中出现问题干扰到应用本身UI的情况,同时也能有效减轻主线程的压力,分担视图刷新的资源消耗。

应当理解的是,对本领域普通技术人员来说,可以根据上述说明加以改进或变换,而所有这些改进和变换都应属于本发明所附权利要求的保护范围。

当前第1页1 2 3 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1