Android应用设计之实现多线程框架

做了Android开发满2年了,感觉在开发中用的很多的就是多线程了;由于在现代的计算机中CPU核数越来越多,因此操作系统底层就向多线程方向发展。因此为了跟上时代,开篇就将平时用的比较多的多线程开发原理吧。
本文需要掌握一定的Android基础;比如Handler,Message,Looper等的关系;还需要掌握一些Java线程池的知识,方能更好的理解本文。
架构是本人根据实际开发经验悟出,因此有不完善的地方,希望大家指正。共同学习进步才是我的目的。
首先提出几个问题:
一:多线程,既然是多线程,就是多个运行的程度,那么是不是需要一个可以管理这些的策略。要不太多了,占用资源太多,系统就会变卡。
二:Activity启动只是在他自己的ActivityThread里面,因此启动其他的线程必须在主线程(ActivityThread)里面启动的。因此还有一个主线程和这个线程的交互问题。
三:手机只有一个,因此必定存在线程之间的竞争关系;比如同时读写一个文件;同时等待一个条件;这里面还牵扯到线程的释放问题;如何安全的结束一个线程。同时竞争CPU资源等。
四:最困难的是多线程之间互相等待的问题,比如这个线程等待一个条件;而另一个线程也等待一个条件;如果这个条件永远无法满足,那么就会出现线程饿死问题。
本文就是为了探索多线程在Android APP中的应用;我尽量为大家展示一种简单易懂的,不容易出现问题的设计多线程程序的思路来发挥多线程的优势,而避免多线程带来的不足。
既然是框架,那么解决的就是通用问题;因此本文主要围绕如何管理线程,如何为使用者提供线程,如何最大量的复用已有的线程池,如何在线程之间交互进行一个框架。
第一个出场的就是线程池对象:
java.util.concurrent.ExecutorService
这个对象就是线程池对象:
我们先将线程池的创建和使用接口分开设计,分别设计两个类;
线程池的创建管理类:
核心思想是利用Map集合来管理已经创建的线程池:

/**
*
* @author 徐晔
* @note 获取指定模式的线程池对象
*/
public final class XYTPoolCreater {

public final static int CachedThreadPool=0;
public final static int FixedThreadPoo=1;
public final static int ScheduledThreadPool=2;
public final static int SingleThreadScheduledExecutor=3;private Map<String, ExecutorService> executorServicemap;
private Map<String, ScheduledExecutorService> scheduledExecutorServicemap;
public static XYTPoolCreater getInstance = new XYTPoolCreater();private XYTPoolCreater() {executorServicemap = new HashMap<String, ExecutorService>();scheduledExecutorServicemap = new HashMap<String, ScheduledExecutorService>();
}/**** 创建新的线程池*  * @param typeid* @param 0:返回一个带缓存的线程池,该池在必要的时候创建线程,在线程空闲60秒后终止线程* @param 1:返回一个线程池,该池中的线程数由参数指定* @param 2:返回一个执行器,它在一个单一的线程中依次执行各个任务**************************** @param corepoolsize*            :线程池中线程的数目* @param key* @param typeid* @param corepoolsize* @param factory*/
public synchronized ExecutorService creatnewExecutorService(String key, int typeid,int corepoolsize, ThreadFactory factory) {ExecutorService service = null;boolean flag = false;if (key == null) {flag = true;return service;}for (String oldkey : executorServicemap.keySet()) {if (key.equals(oldkey)) {service = executorServicemap.get(oldkey);flag = true;break;}}if (!flag) {service = getExecutorService(typeid, corepoolsize, factory);executorServicemap.put(key, service);}return service;}/*** 获取已经存在的ExecutorService* * @param key* @return*/
public ExecutorService getExecutorService(String key) {ExecutorService service = null;if (key != null) {service = executorServicemap.get(key);}return service;
}/*** 创建新的周期性任务池* * @param key* @param typeid* @param corepoolsize* @param factory*/
public synchronized ScheduledExecutorService creatnewScheduledExecutorService(String key, int typeid, int corepoolsize, ThreadFactory factory) {ScheduledExecutorService service = null;boolean flag = false;if (key == null) {flag = true;return service;}for (String oldkey : scheduledExecutorServicemap.keySet()) {if (key.equals(oldkey)) {service = scheduledExecutorServicemap.get(oldkey);flag = true;break;}}if (!flag) {service = getScheduledExecutorService(typeid, corepoolsize, factory);scheduledExecutorServicemap.put(key, service);}return service;
}/*** 获取以及存在的ScheduledExecutorService* * @param key* @return*/
public ScheduledExecutorService getScheduledExecutorService(String key) {ScheduledExecutorService service = null;if (key != null) {service = scheduledExecutorServicemap.get(key);}return service;
}/*** 创建线程池的工厂* * @param typeid* @param XYTPool.CachedThreadPool:返回一个带缓存的线程池,该池在必要的时候创建线程,在线程空闲60秒后终止线程* @param XYTPool.FixedThreadPoo:返回一个线程池,该池中的线程数由参数指定**************************** @param corepoolsize*            :线程池中线程的数目*/
private ExecutorService getExecutorService(int typeid, int corepoolsize,ThreadFactory factory) {ExecutorService mService = null;if (corepoolsize < 1) {corepoolsize = 1;}if (typeid < 0 || typeid > 2) {typeid = 0;}switch (typeid) {case CachedThreadPool:if (factory != null) {mService = Executors.newCachedThreadPool(factory);} else {mService = Executors.newCachedThreadPool();}break;case FixedThreadPoo:if (factory != null) {mService = Executors.newFixedThreadPool(corepoolsize, factory);} else {mService = Executors.newFixedThreadPool(corepoolsize);}break;}return mService;
}/*** 预定执行或者重复执行的线程池接口* * @param typeid* @param XYTPool.ScheduledThreadPool:返回一个线程池,它使用给定的线程数来调度任务* @param XYTPool.SingleThreadScheduledExecutor1:返回一个执行器,它在一个单线程中调度任务*/
private ScheduledExecutorService getScheduledExecutorService(int typeid,int corepoolsize, ThreadFactory factory) {if (corepoolsize < 1) {corepoolsize = 1;}ScheduledExecutorService mService = null;if (typeid > 1 || typeid < 0) {typeid = 0;}switch (typeid) {case ScheduledThreadPool:if (factory != null) {mService = Executors.newScheduledThreadPool(corepoolsize,factory);} else {mService = Executors.newScheduledThreadPool(corepoolsize);}break;case SingleThreadScheduledExecutor:if (factory != null) {mService = Executors.newSingleThreadScheduledExecutor(factory);} else {mService = Executors.newSingleThreadScheduledExecutor();}break;}return mService;
}

}

接下来我们需要设计几个接口以满足线程池中添加任务的需求:

/*** @author 徐晔* 异步线程执行之前需要执行的方法*/
public  interface XYdoBefore {/**在执行之前*/public void before(int taskid);}
/***
 @author 徐晔* @param <V>* @note 执行异步任务得到的回调接口*/
public interface XYgetresult<V> {/*** 执行完成,得到返回结果* @param <V>*/public void onfinish(int id, V v);
}
/***
* @author 徐晔* @note 执行没有返回参数的异步任务方法*/
public interface XYInBack {/**在异步线程中执行的方法体*/public void doinbackground();
}
/**
* * @author 徐晔* @param <V>* @note 执行有返回参数的异步任务方法*/public interface XYInBackwithResult<V> {/**在异步线程中执行的方法体* @param <V>*/public  V doinbackground();
}
以上四个是我简单

设计的执行异步任务的方法接口,里面有简单的标识id,有简单的值字段来代表参数。
下面是我具体的给线程池提交参数的类:

/**
* @author 徐晔
* @note 线程池配置类
*/
public final class XYTPool {

/*** @param <V>* 进行有返回参数异步任务* @throws Exception* @throws*/
public static <V> void dobackWithResult(final ExecutorService pool,final int id, final XYInBackwithResult<V> dInbackground,final XYgetresult<V> getResult){pool.submit(new Runnable() {@Overridepublic void run() {getResult.onfinish(id, dInbackground.doinbackground());}});
}/*** 执行没有返回参数的任务* * @param pool* @param id* @param dInbackground* @throws Exception*/
public static void dobackWithoutResult(final ExecutorService pool,final XYInBack dInbackground){pool.submit(new Runnable() {@Overridepublic void run() {dInbackground.doinbackground();}});
}/*** 执行定期任务* @param <V>* * @param typeid* @param 0:预定在指定时间之后执行任务(1次)* @param 1:预定在初始的指定时间之后周期性的执行任务,周期是delay* @param 2:预定在初始的指定时间之后周期性的执行任务,在一次调用完成和下一次调用开始之间有长度为delay的延迟* */
public static <V> void schedule(final ScheduledExecutorService service,int typeid, final XYInBackwithResult<V> task,long initialdelay, long delay, TimeUnit unit) {if (typeid < 0 || typeid > 2) {typeid = 0;}switch (typeid) {case 0:service.schedule(new Runnable() {@Overridepublic void run() {task.doinbackground();}}, delay, unit);break;case 1:service.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {task.doinbackground();}}, initialdelay, delay, unit);break;case 2:service.scheduleWithFixedDelay(new Runnable() {@Overridepublic void run() {task.doinbackground();}}, initialdelay, delay, unit);break;}}/*** 关闭服务*/
public static void shutdown(ExecutorService service) {if (service != null && !service.isShutdown()) {service.shutdown();}
}

}
好了,有了这么几个,简单的线程池管理类,创建类和实现接口对象都有了;
稍微完善一下就可以直接用以上三个类来实现异步任务管理了;但是在Android中,我们还需要实现线程之间值的传递;如下
我设计一个通用的Task类:
/**
* @param
* @param handler:
* 推荐直接传递 new Handler(Looper);
* @param before
* :执行异步线程之前执行的方法
* @param getResult
* :得到异步任务执行结果得到的线程 可以完成大部分的任务,类似于异步请求网络,异步查询数据库,普通的异步任务都可以继承该类来进行实现
*/
public abstract class XYAsynBaseTask implements XYgetresult,
XYdoBefore,XYInBackwithResult {
private XYgetresult mResult;
private XYdoBefore before;
private Handler handler;

/*** @param mLooper*            :Loop对象必须在调用前初始化好,*            比如Looper.prepareMainLooper()(Activity主线程);或者Looper.prepare();*            调用之后必须执行Looper.loop();方法* @param before*            :执行异步线程之前执行的方法* @param getResult*            :得到异步任务执行结果得到的线程*/
public XYAsynBaseTask(Handler handler, XYdoBefore before,XYgetresult<V> mResult) {this.handler=handler;this.before = before;this.mResult=mResult;
}public void execute(int id) throws Exception {XYAsynBaseTask.this.before.before(id);XYTPool.dobackWithResult(XYTPoolCreater.getInstance.creatnewExecutorService(XYAsynConsts.HTTPTHREAD_KEY, 1, 5,null), id, this, this);
}@Override
public void onfinish(final int id,final V v) {handler.post(new Runnable() {@Overridepublic void run() {mResult.onfinish(id, v);}});
}@Override
public abstract V doinbackground();

}
我们在这个基类里通过Android 自己的Handler机制实现了线程之间的交互;执行了线程运行之前需要执行的方法,线程运行得到结果后,将结果返回给Handler所在的线程;为什么传递参数用Handler,开始用Looper,然后new一个Handler对象,但是后面感觉这样貌似浪费了很多Handler对象,所以本人觉得还是传递Handler的好,在主线程new一次;将线程体中需要执行的方法延迟到子类实现;有一点控制反转的意思;
看到这里,一个多线程的框架就此完成。至于如何使用,我相信看懂的人没有不会使用的。
写到最后,这个只是一个简单的多线程框架,用了Runnable对象,无法跟踪线程的执行。如果想要保持线程的跟踪,可以使用Callable
对象和FutureTask对象来实现;但是要注意阻塞,本人不建议用FutureTask来得到结果,因为那个获取结果的方法是一个阻塞式方法;本文抛砖引玉,希望可以给大家提供一个思路。至于最上面提到的问题,就看大家各自的设计能力了。

Android应用设计之实现多线程框架相关推荐

  1. Android用户界面设计“.NET研究”:框架布局

    框架布局是将控件组织在Android程序的用户界面中最简单的布局类型之一. 理解布局对于良好的Android程序设计来说是非常重要的.在这个教程里,你将学到所以关于框架布局的知识,它们主要用来在屏幕上 ...

  2. Android用户界面设计:框架布局

    框架布局是将控件组织在Android程序的用户界面中最简单的布局类型之一. 理解布局对于良好的Android程序设计来说是非常重要的.在这个教程里,你将学到所以关于框架布局的知识,它们主要用来在屏幕上 ...

  3. osgi框架 android,基于OSGi的Android应用模块动态加载框架设计与实现

    摘要: 伴随着移动互联网科技水平向4G的飞跃,移动终端的使用日趋常态化,移动智能设备的普及率越来越高,得到了大量使用者的追捧.与此同时,各手机操作系统下应用商店里正充斥着琳琅满目的移动应用产品,用户对 ...

  4. android ui框架详解,多图详解 “Android UI”设计官方教程(二)

    编者注:本文为Android的官方开发者博客发了一份幻灯片的翻译文档的第二部分,专门介绍了一些Android UI设计的小贴士,我们在介绍这个幻灯片的第一部分<多图详解 "Androi ...

  5. android 视频播放器通用的编码框架,Android播放器框架设计系列-1

    视频播放器框架已经非常成熟了,但是由于项目需求各种各样,第三方库使用起来需要大量修改定制,并且还会出现各种问题,因此把之前项目中开发的模块提取出来进行完善扩展,写了一套自研的播放框架,并且引入Jetp ...

  6. 王家林最受欢迎的一站式云计算大数据和移动互联网解决方案课程 V1之Android架构设计和实现完整训练:HALFrameworkNative ServiceAndroid ServiceBes

    如何理解Android架构设计的初心并开发出搭载Android系统并且具备深度定制和软硬整合能力特色产品,是本课程解决的问题. 课程以Android的五大核心:HAL.Binder.NativeSer ...

  7. Android 快速开发框架:推荐10个框架

    一.  Afinal 官方介绍: Afinal是一个Android的ioc,orm框架,内置了四大模块功能:FinalAcitivity,FinalBitmap,FinalDb,FinalHttp.通 ...

  8. android教程 - android ui 介绍,多图详解 “Android UI”设计官方教程

    我们曾经给大家一个<MeeGo移动终端设备开发UI设计基础教程>,同时很多朋友都在寻找Android UI开发的教程,我们从Android的官方开发者博客找了一份幻灯片,介绍了一些Andr ...

  9. android ui秘笈,看图说话 – Android UI 设计秘笈 :Part I

    Android 的官方开发者博客发了一份幻灯片,介绍了一些 Android UI 设计的小贴士,Roger 在这里以看图说话的形式发出来,有兴趣的读者就继续往下翻吧.整个 PPT 共分5个部分,Par ...

最新文章

  1. ASP.NET MVC 3拥抱动态类型,徐汇区网站设计
  2. 2020年华科计算机考研机试题答案(没弄懂题目的意思)
  3. pip安装python模块遇到一直出现retrying的问题
  4. Servlet_概述
  5. scp 上传文件到服务器
  6. 转:CDC,CPaintDC,CClientDC,CWindowDC区别
  7. 如何手动编辑art分区修改qsdk(qca9531、qca9563)无线mac地址
  8. mongodb详细优化策略方案
  9. 显示器接口_显示器接口都有哪些?
  10. 工控机在机器视觉系统中的应用
  11. Intellij IDEA之Mybatis插件:Free Mybatis Plugin
  12. 申论该怎么学?申论作文如何提高
  13. Android NDK开发之旅17 NDK Apk增量更新
  14. Entity FrameWork Core使用 Include查询关联数据以及机理。
  15. JAVA面试题《下》
  16. PHP中date时差问题解决方法
  17. iOS APP启动页更新失败
  18. 心法利器[78] | 端到端任务的拆解设计
  19. python爬取大众点评数据_python爬虫实例详细介绍之爬取大众点评的数据
  20. Github已标星80,java语言自学教程

热门文章

  1. 用友NC软件被locked1勒索病毒攻击加密的方式,服务器oracle数据库中了勒索病毒
  2. 鸡感染呼吸道疾病怎么办 防治鸡流鼻涕的特效药
  3. wow 人物初次创建进入游戏时的世界公告
  4. Python爬虫设计思路
  5. ubuntu pastebin
  6. java运行闪退_java运行闪退,报错如下,是因为ole32.dll的问题吗?
  7. Apache DolphinScheduler 整合 Apache Knox 网关
  8. 【计算几何】快速排斥实验和跨立实验
  9. 调研分析-全球与中国可拔插接线端子市场现状及未来发展趋势
  10. 新建android项目报错,Rejecting re-init on previously-failed...