KJFrameForAndroid框架学习——多线程管理

在Android开发中,由于不能再UI线程中做耗时操作,常常需要开启线程来做一些操作。但是这样一来就产生了一个问题,就是大量的线程并发执行,造成了线程维护的开销进而使得代码质量下降手机发烫又耗电。让我们来看一下KJFrameForAndroid框架是如何解决这个问题的。

KJFrameForAndroid框架项目地址:https://github.com/kymjs/KJFrameForAndroid

其实Android提供了一套专门用于异步处理的类,就是我们熟悉又模式的AsynTask类。

AsynTask类就是对Thread类的一个封装,并且加入了一些新的方法。那么我们先来看一下它对于Thread请求的一系列管理与封装。

在jdk中有这样一个集合类叫:BlockingQueue<>它是一个 Queue<E>的子类,支持两个附加操作的 Queue,这两个操作是:获取元素时等待队列变为非空,以及存储元素时等待空间变得可用。

BlockingQueue 方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同:第一种是抛出一个异常,第二种是返回一个特殊值(null 或 false,具体取决于操作),第三种是在操作可以成功前,无限期地阻塞当前线程,第四种是在放弃前只在给定的最大时间限制内阻塞。

我们来看一下在jdk中关于这个类的介绍:

BlockingQueue 不接受 null 元素。试图 add、put 或 offer 一个 null 元素时,某些实现会抛出 NullPointerException。null 被用作指示 poll 操作失败的警戒值。

好,为什么要讲这个集合类呢?因为这与我们接下来要讲的线程池维护有着莫大的关系。

?


1

2

    // 静态阻塞式队列,用来存放待执行的任务,初始容量:8个

    private static final BlockingQueue<Runnable> mPoolWorkQueue = new LinkedBlockingQueue<Runnable>(8);

这里是KJFrameForAndroid开发框架中对于线程队列的维护对象,通过这个线程队列将所有线程放置在一个静态阻塞式队列中保存起来。

然而,仅仅是保存起来还不够,因为线程需要执行,我们必须要让线程进入到CPU工作间才行,这时KJFrameForAndroid使用了jdk中的另一个类ThreadPoolExecutor来管理并使用并发启动这些线程

来看一下在KJFrameForAndroid中对于这个类对象的创建

?


1

2

3

4

5

6

7

    /**

     * 并发线程池任务执行器,可以用来并行执行任务<br>

     * 与mSerialExecutor(串行)相对应

     */

    public static final Executor mThreadPoolExecutor = new ThreadPoolExecutor(

            CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,

            TimeUnit.SECONDS, mPoolWorkQueue, mThreadFactory);

通过注释,我们还可以看到KJFrameForAndroid框架其实还有一种并行执行线程的方式,这里暂时不讲,我们看看这个类的构造方法在jdk中的解释:

那么至此我们有了并发任务执行器和线程池队列,最后就只需要将线程执行起来就行了。ThreadPoolExecutor类是一个实现了执行器Executor接口的类,那么它也就有一个execute方法去执行线程,我们所要做的就是调用这个类来执行它就可以了。

接下来我们来看一下如何让线程执行完成后又回到UI线程去做界面处理的。

还是看源码,以下是摘自KJFrameForAndroid开源框架中的一段代码:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

/*********************** start 一个完整的执行周期 ***************************/

    /**

     * 在doInBackground之前调用,用来做初始化工作 所在线程:UI线程

     */

    protected void onPreExecute() {}

    /**

     * 这个方法是我们必须要重写的,用来做后台计算 所在线程:后台线程

     */

    protected abstract Result doInBackground(Params... params);

    /**

     * 打印后台计算进度,onProgressUpdate会被调用<br>

     * 使用内部handle发送一个进度消息,让onProgressUpdate被调用

     */

    protected final void publishProgress(Progress... values) {

        if (!isCancelled()) {

            mHandler.obtainMessage(MESSAGE_POST_PROGRESS,

                    new KJTaskResult<Progress>(this, values))

                    .sendToTarget();

        }

    }

    /**

     * 在publishProgress之后调用,用来更新计算进度 所在线程:UI线程

     */

    protected void onProgressUpdate(Progress... values) {}

    /**

     * 任务结束的时候会进行判断:如果任务没有被取消,则调用onPostExecute;否则调用onCancelled

     */

    private void finish(Result result) {

        if (isCancelled()) {

            onCancelled(result);

        else {

            onPostExecute(result);

        }

        mStatus = Status.FINISHED;

    }

    /**

     * 在doInBackground之后调用,用来接受后台计算结果更新UI 所在线程:UI线程

     */

    protected void onPostExecute(Result result) {}

    /**

     * 所在线程:UI线程<br>

     * doInBackground执行结束并且{@link #cancel(boolean)} 被调用。<br>

     * 如果本函数被调用则表示任务已被取消,这个时候onPostExecute不会再被调用。

     */

    protected void onCancelled(Result result) {}

    /*********************** end 一个完整的执行周期 ***************************/

在这里我们看到了三个非常熟悉的函数:doInBackground、onPostExecute、onProgressUpdate

没错,这三个函数正式SyncTask中被我们使用的三个方法(如果你还不知道,请搜索Android开发中SyncTask用法)接着我们再看看他们是如何被调用的:

这里声明了一个线程任务被执行的方法,实际上也就是doInBackground、被调用的方法:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

/**

     * 必须在UI线程调用此方法<br>

     * 通过这个方法我们可以自定义KJTaskExecutor的执行方式,串行or并行,甚至可以采用自己的Executor 为了实现并行,

     * asyncTask.executeOnExecutor(KJTaskExecutor.mThreadPoolExecutor, params);

     */

    public final KJTaskExecutor<Params, Progress, Result> executeOnExecutor(

            Executor exec, Params... params) {

        if (mStatus != Status.PENDING) {

            switch (mStatus) {

            case RUNNING:

                throw new IllegalStateException(

                        "Cannot execute task:"

                                " the task is already running.");

            case FINISHED:

                throw new IllegalStateException(

                        "Cannot execute task:"

                                " the task has already been executed "

                                "(a task can be executed only once)");

            default:

                break;

            }

        }

        mStatus = Status.RUNNING;

        onPreExecute();

        mWorker.mParams = params;

        exec.execute(mFuture);// 原理{@link #execute(Runnable runnable)}

        // 接着会有#onProgressUpdate被调用,最后是#onPostExecute

        return this;

    }

而onProgressUpdate实际上是在这个handle中被调用了。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

/**

     * KJTaskExecutor内部Handler,用来发送后台计算进度更新消息和计算完成消息

     */

    private static class InternalHandler extends Handler {

        @Override

        @SuppressWarnings({ "unchecked""rawtypes" })

        public void handleMessage(Message msg) {

            KJTaskResult result = (KJTaskResult) msg.obj;

            switch (msg.what) {

            case MESSAGE_POST_RESULT:

                result.mTask.finish(result.mData[0]);

                break;

            case MESSAGE_POST_PROGRESS:

                result.mTask.onProgressUpdate(result.mData);

                break;

            }

        }

    }

有关本类的完整代码可以查看https://github.com/kymjs/KJFrameForAndroid/blob/master/KJLibrary/src/org/kymjs/aframe/core/KJTaskExecutor.java

时间: 2024-10-07 02:43:38

KJFrameForAndroid框架学习——多线程管理的相关文章

KJFrameForAndroid框架学习----高效加载Bitmap

KJFrameForAndroid框架项目地址:https://github.com/kymjs/KJFrameForAndroid 或备用地址http://git.oschina.net/kymjs/KJFrameForAndroid KJFrameForAndroid开发群:257053751 我们在写Android程序的时候,肯定会用到很多图片.那么对于图片的压缩处理自然是必不可少.为什么要压缩?我想这个问题不必在强调了,每个人在最初学习Android的时候肯定都会知道这么一个原因:我们编

KJFrameForAndroid框架学习----深入理解注解原理

Android开发中,有一个让人又爱又恨的方法叫findViewById(int);我想如果你是一民Android开发者,必然知道这个方法,让我们来看一下KJFrameForAndroid框架是如何解决这个问题的. KJFrameForAndroid框架项目地址:https://github.com/kymjs/KJFrameForAndroid. 为什么说findViewById(int);让人又爱又恨呢?想必大家也是很有感触. 写一个布局,用Java代码写和用xml文件写,完成速度完全是无法

KJFrameForAndroid框架学习----高效设置网络图片

KJFrameForAndroid框架项目地址:https://github.com/kymjs/KJFrameForAndroid 或备用地址http://git.oschina.net/kymjs/KJFrameForAndroid KJFrameForAndroid开发群:257053751 我们都知道,计算机读取数据时:内存的读取速度是最快的,然后是文件的读取速度,最后是网络资源的读取. 假设每次载入同一张图片都要从网络获取,那代价实在太大了.所以同一张图片仅仅要从网络获取一次就够了,然

JavaSE中线程与并行API框架学习笔记——线程为什么会不安全?

前言:休整一个多月之后,终于开始投简历了.这段时间休息了一阵子,又病了几天,真正用来复习准备的时间其实并不多.说实话,心里不是非常有底气. 这可能是学生时代遗留的思维惯性--总想着做好万全准备才去做事.当然,在学校里考试之前当然要把所有内容学一遍和复习一遍.但是,到了社会里做事,很多时候都是边做边学.应聘如此,工作如此,很多的挑战都是如此.没办法,硬着头皮上吧. 3.5 线程的分组管理 在实际的开发过程当中,可能会有多个线程同时存在,这对批量处理有了需求.这就有点像用迅雷下载电视剧,假设你在同时

JavaSE中线程与并行API框架学习笔记1——线程是什么?

前言:虽然工作了三年,但是几乎没有使用到多线程之类的内容.这其实是工作与学习的矛盾.我们在公司上班,很多时候都只是在处理业务代码,很少接触底层技术. 可是你不可能一辈子都写业务代码,而且跳槽之后新单位很可能有更高的技术要求.除了干巴巴地翻书,我们可以通过两个方式来解决这个问题:一是做业余项目,例如在github上传自己的demo,可以实际使用:二是把自己的学习心得写成博客,跟同行们互相交流. 3.1 线程的初窥门径 我们在之前的文章里提到的程序其实都是单线程程序,也就说启动的程序从main()程

某智能家居项目框架学习总结

这个月来第一篇博客,各种其他事情.. 之前负责过一个智能家居项目的二次开发,苏州一家公司做的,项目还是分了好几个系统,对业务流程的不同部分进行了划分,我是此项目的主要负责人,通过老师的指导,对这个项目也有了一些了解.此项目运用了一些框架,有些也是我第一次接触到的,下面将对项目用到的一些框架进行总结. 下面可能会出现几个有关智能家居的名词,介绍一下 1.机顶盒:每一个家庭都应该至少有一个机顶盒,控制电器开关都是由机顶盒向各电器的接收器发送命令 2.客户端:也就是用户的移动设备,手机.平板都可以,我

Spring框架学习之IOC(一)

Spring框架学习之IOC 先前粗浅地学过Spring框架,但当时忙于考试及后期实习未将其记录,于是趁着最近还有几天的空闲时间,将其稍微整理一下,以备后期查看. Spring相关知识 spring是J2EE应用程序框架,是轻量级的IoC和AOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级容器.可单独使用,通常也与其他框架整合使用,例如SSH.SSM. IOC:控制反转 控制权由对象本身转向容器:由容器根据配置文件去创建实例并创建各个实例之间的依赖关系.等同于DI依赖注入 A

spring框架学习(一)

转自:http://blog.csdn.net/lishuangzhe7047/article/details/20740209 —————————————————————————————————————————————————— 1,什么是spring框架 spring是J2EE应用程序框架,是轻量级的IoC和AOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,ibatis框架等组合使用. 2,架构概述 1)IoC(Inversi

C#框架学习资料集锦

1.AllEmpty 的[从零开始编写自己的C#框架]系列 从零开始编写自己的C#框架(1)--前言从零开始编写自己的C#框架(2)--开发前的准备工作从零开始编写自己的C#框架(3)--开发规范从零开始编写自己的C#框架(4)--文档编写说明从零开始编写自己的C#框架(5)--三层架构介绍从零开始编写自己的C#框架(6)--SubSonic3.0插件介绍从零开始编写自己的C#框架(7)--需求分析从零开始编写自己的C#框架(8)--后台管理系统功能设计从零开始编写自己的C#框架(9)--数据库