Android网络应用的封装与调度

Android网络业务的封装与调度

手机客户端程序由于网络宽带的约束,尤其在GPRS网络环境下,大数据量的网络交互很大程度上降低应用的响应,影响用户体验。比如,如果做一个手机网盘客户端,在后台上传文件时(大数据量的交互),获取文件列表(命令类的交互)这个过程就显得太别慢。而我们的要求是希望这些命令类操作能尽快得到响应。

通常,在手机客户端,我们设计一个网络操作的管理器,来统一管理这些需要联网的操作。

具体做法是把网络操作封装成一个Command(或者说是Task),管理器实现特定的调度规则来调度运行这些Task。

这样做的好处至少有三:

一. 用Command封装了网络操作,使得这些操作与上传的业务分离,解除了强耦合。

二. 可以根据网络情况来确定来采用不同的调度规则,提高用户体验。

三. 重用,这些Task和TaskManager的代码在别的手机应用上基本上能照搬过去。

四. 扩展,当应用需要扩展新的业务时,只有扩展一个新的Command(或者说是Task),接受调度即可,易于扩展。

例子:

还是以上文提到的微盘为例,可以概括我们对管理器的设计要求有:

在Wifi网络环境下:

一:各种网络操作可以并行运行。

在GPRS网络环境下:

二:支持优先级抢占调度,命令类操作的优先级比数据传输类的优先级高,当命令类的Task(获取文件列表)提交后,打断数据传输的Task(如上传,下载),等命令类的任务运行完毕,再接着运行数据类任务(断点上传,下载)。

二:同一个优先级的任务可以并行运行,如多个命令一起在网络上传输。

实现思路:

TaskManager :

1. TaskManager开辟一个后台线程进行调度工作。

2. 由于要支持多个优先级的抢占调度,我们需要两个队列来维护运行中的Task和等待中的Task。

3. 由于Task的调度是基于优先级的,我们可以使用优先级队列,运行队列采用PriorityQueue,等待队列使用PriorityBlockingQueue,当没有网络业务需要运行时,调度线程阻塞挂起,避免空转。

4. TaskManager设计为单一实例(单一模式)。

5. 每个Task被调度运行时,该Task被从等待队列移动运行队列,当Task执行完毕时,从运行队列删除,唤醒调度线程进行新的调度。

下面是简单的设计代码

www.2cto.com

public final class TaskEngine implements Runnable{

private PriorityQueue<Task> runningQueue;//运行的task队列

private PriorityBlockingQueue<Task> readyQueue;//就绪的task队列,准备接受调度的task列表

private final AtomicLong taskIdProducer = new AtomicLong(1);//Task Id生成器

private Object sheduleLock = new Object();//同步锁

private static TaskEngine instance;

public long addTask(BusinessObject bo){

  Task task = new Task(bo);

  long newTaskId = taskIdProducer.incrementAndGet();

  task.setTaskId(newTaskId);

  if(this.isWifiNetWork()){ //WIFI网络

  synchronized(sheduleLock){

  runningQueue.add(task);

  }

  new Thread(task).start();

  }else{ //GPRS网络

  if(readyQueue.offer(task)){ //task入就绪队列

  final ReentrantLock lock = this.lock;

  lock.lock();

  try{

  needSchedule.signal(); //唤醒调度线程重新调度

  }finally{

  lock.unlock();}

  }

}

return newTaskId;

}

public final void run(){//task调度逻辑

....

....

}

//挂起调度线程 当不需要调度时

private void waitUntilNeedSchedule() throws InterruptedException

{

.....

}

}

Task:

1. 对要执行的网络操作的封装。

2. Task执行完毕时,发Task结束信号,唤醒调度线程进行新的调度

3. Task要实现Comparable接口,才能让TaskManager的两个队列自动其包含的Task排序。

下面是简单的设计代码:

public class Task implements Runnable,Comparable<Task>{

private long taskId;

private BusinessObject bo;//封装网络操作的业务对象的抽象父类,

//它封装了具体的Command,保证了业务扩展中Task的接口不变

@Override

public void run() {

  this.onTaskStart();

  this.bo.execute();

  this.onTaskEnd();

}

private voidonTaskStart()

{...}

public int getPriority()

{...}

public void setPriority(intpriority)

{...}

@Override

public int compareTo(Task object1) {

return this.getPriority()>object1.getPriority()?-1:1;

}

} 

小注意事项:

Android对PriorityQueue的实现和Jdk中的实现有点不一样。

(PriorityQueue.java在android中的代码路径是usr\dalvik\libcore\luni\src\main\java\java\util)

PriorityQueue.remove(Object o) ;//从PriorityQueue中删除一个元素。

对于完成这个删除操作android和jdk都是分两个过程实现,一,找出待删除元素的索引index,二,删除index所在元素。

在JDK中,是通过调用元素的equals方法来找到待删除元素的索引,

private int indexOf(Object o) {

if (o != null) {

for (int i = 0; i < size; i++)

if (o.equals(queue[i]))

return i;

}

return -1;

}

在android中,是间接调用元素的compareTo方法判断结果是否为0来找到待删除元素的索引,

int targetIndex;

for (targetIndex = 0; targetIndex < size; targetIndex++) {

if (0 == this.compare((E) o, elements[targetIndex])) {

break;

}

}

private int compare(E o1, E o2) {

if (null != comparator) {

return comparator.compare(o1, o2);

}

return ((Comparable<? super E>) o1).compareTo(o2);

}

所以为了Task能在执行完毕时从PriorityQueue找到这个Task并删除之,需要在compareTo方法里在优先级相等时

返回0。

@Override

public int compareTo(Task object1) {

if(this.getPriority()==object1.getPriority())

return 0;

return this.getPriority()>object1.getPriority()?-1:1;

}

当是这样运行PriorityQueue.remove(Object o) 逻辑上只能删除PriorityQueue里第一个优先级与被删除的元素

优先级相等的元素(可能是待删除的元素也可能不是),有误删的可能,需要做如下修改:

@Override

public int compareTo(Task object1) {

if(this.getPriority()==object1.getPriority() && this.equals(object1))

return 0;

return this.getPriority()>object1.getPriority()?-1:1;

}

这样才能正确执行remove(Object o),删除指定的对象o。

个人觉得android这样设计使得remove(Object o)复杂化了,不然JDK中那么简洁。语义上也不是那么好懂了,

因为按通常理解,equals是判断两个对象是否相等,compareTo可能是对象的某个属性的比较(类别数据库中的order by),

而现在执行PriorityQueue.remove(Object o),这个对象o明明在容器PriorityQueue中,却删除不了,除非去翻看android中PriorityQueue的实现代码,然后重写compareTo这个方法。这样的API使用时比较容易出错,应该不符号良好的API设计规范

吧。

完整的代码实现如下:

View Code

1 * @类名:TaskEngine

2  * @创建:baiyingjun (devXiaobai@gmail.com)

3  * @创建日期:2011-7-7

4  * @说明:task调度引擎

5  ***************************************************/

6 public final class TaskEngine implements Runnable{

7

8     private static final String TAG=Log.makeTag(TaskEngine.class);

9

10     private PriorityQueue<Task> runningQueue;//运行的task队列

11

12     private PriorityBlockingQueue<Task> readyQueue;//就绪的task队列,准备接受调度的task列表

13

14     private final AtomicLong taskIdProducer = new AtomicLong(1);

15

16     private Object sheduleLock = new Object();//调度锁

17

18     private static TaskEngine instance;

19

20     private final ReentrantLock lock = new ReentrantLock(true);

21

22     private final Condition needSchedule = lock.newCondition();

23

24     private Task currentTask;//准备接受调度的task

25

26     private Context mAppContext;

27

28     /**

29      * add BusinessObject to taskEngine

30 */

31     public long addTask(BusinessObject bo) throws NetworkNotConnectException{

32         Task task = new Task(bo);

33         long newTaskId = taskIdProducer.incrementAndGet();

34         task.setTaskId(newTaskId);

35         if(Log.DBG){

36             Log.d(TAG, "Add task with task id "+newTaskId+", priority "+task.getPriority());

37         }

38

39         if(this.isWifiNetWork()){ //WIFI网络

40             synchronized(sheduleLock){

41                 runningQueue.add(task);

42             }

43             new Thread(task).start();

44         }else{ //GPRS网络

45             if(readyQueue.offer(task)){ //task入就绪队列

46                 if(Log.DBG)

47                     Log.d(TAG, "add task " +task.bo.methodName+" "+task.taskId+" to ready queue");

48                 final ReentrantLock lock = this.lock;

49                 lock.lock();

50                 try{

51                     needSchedule.signal(); //唤醒调度线程重新调度

52                 }finally{

53                     lock.unlock();

54                 }

55             }

56             //schedule();

57         }

58         return newTaskId;

59     }

60

61     private TaskEngine(Context context){

62         mAppContext = context;

63         runningQueue = new PriorityQueue<Task>();

64         readyQueue = new PriorityBlockingQueue<Task>();

65         new Thread(this).start();

66         Log.i(TAG, "shedule thread working");

67     }

68

69     public synchronized static TaskEngine getInstance(Context context){

70         Context appContext = context.getApplicationContext();

71         if(instance==null || instance.mAppContext!=appContext){

72             instance=new TaskEngine(appContext);

73         }

74         return instance;

75     }

76

77     protected boolean isWifiNetWork() throws NetworkNotConnectException{

78         return NetworkManager.isWIFINetWork(mAppContext);

79     }

80

81     /**

82      * task调度逻辑

83 */

84     public final void run(){

85         Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

86         while(true){

87             try {

88                 if(this.isWifiNetWork()){

89                     Task task = this.readyQueue.take();

90                     if(task !=null){

91                         synchronized(sheduleLock){

92                             runningQueue.add(task);

93                         }

94                         new Thread(task).start();

95                     }

96                 }

97                 else{//非wifi网络

98 //空就绪队列,空运行队列,等待直到有任务到来

99                     if(this.readyQueue.size()==0 && runningQueue.size()==0){

100                         currentTask=readyQueue.take();

101                         synchronized(sheduleLock){

102                             runningQueue.add(currentTask);

103                         }

104                         new Thread(currentTask).start();

105                     }

106                     //抢占式调度(就绪队列非空,运行队列优先级比就绪队列优先级低)

107                     else if(readyQueue.size()>0 &&

108                             this.readyQueue.element().getPriority()>=this.getMaxPriority()){

109                         currentTask = readyQueue.take();

110                         if(currentTask.getPriority()>this.getMaxPriority()){//暂停低优先级的任务运行

111                             synchronized(sheduleLock){

112                                 for(int i=0;i<runningQueue.size();i++){

113                                     Task toStopTask =runningQueue.remove();

114                                     //因为任务调度,将低优先级的任务暂时给冻结起来

115                                     toStopTask.setState(Task.STATE_FROST);

116                                     readyQueue.add(toStopTask);

117                                 }

118                             }

119                         }

120                         //运行被调度的任务

121                         runningQueue.add(currentTask);

122                         new Thread(currentTask).start();

123                     }else {//等高优先级的任务运行完毕

124                         waitUntilNeedSchedule();

125                     }

126                 }

127

128             }catch (InterruptedException e) {

129                 Log.e(TAG, "Schedule error "+e.getMessage());

130             } catch (NetworkNotConnectException e) {

131                 // TODO Auto-generated catch block

132                 e.printStackTrace();

133             }

134         }

135     }

136

137     /*

138      * 等待,直到就绪队列里的最高优先级比当前运行优先级高,或者就绪队列为空时等待运行队列运行完毕

139 */

140     private void waitUntilNeedSchedule() throws InterruptedException{

141          final ReentrantLock lock = this.lock;

142          lock.lockInterruptibly();

143             try {

144                 try{

145                     while ((readyQueue.size()>0

146                             && readyQueue.element().getPriority()<getMaxPriority())//等高优先级的任务运行完毕

147                             || (readyQueue.size()==0 && runningQueue.size()>0) ){//或者等运行队列运行完毕

148                         if(Log.DBG)

149                             Log.d(TAG, "waiting sheduling........");

150                         needSchedule.await();

151                     }

152                 }

153                 catch (InterruptedException ie) {

154                     needSchedule.signal(); // propagate to non-interrupted thread

155                     throw ie;

156                 }

157             } finally {

158                 lock.unlock();

159             }

160     }

161

162     /**

163      * Hand the specified task ,such as pause,delete and so on

164 */

165     public boolean handTask(long taskId,int handType) {

166         Log.i(TAG, "set task`s state with taskId "+taskId);

167         synchronized(this.sheduleLock){

168             //如果在运行队列里,取消该任务

169             Iterator<Task> runningItor= this.runningQueue.iterator();

170             while(runningItor.hasNext()){

171                 Task task = runningItor.next();

172                 boolean b = task.equals(this);

173                 if(task.getTaskId()==taskId){

174                     runningQueue.remove(task);

175                     task.setState(handType);

176                     Log.i(TAG, "set runningQueue taskId = "+taskId + " state " + handType);

177                     return true;

178                 }

179             }

180             //如果在就绪队列里,删除

181             Iterator<Task> readyItor= this.readyQueue.iterator();

182             while(readyItor.hasNext()){

183                 Task task = readyItor.next();

184                 if(task.getTaskId()==taskId){

185 //                    readyQueue.remove(task);

186                     task.setState(handType);

187                     Log.i(TAG, "set readyQueue taskId = "+taskId + " state " + handType);

188                     return true;

189                 }

190             }

191             return false;

192         }

193     }

194     /***

195      * 获取运行队列任务的最高优先级

196 */

197     private int getMaxPriority(){

198         if(this.runningQueue==null || this.runningQueue.size()==0)

199             return -1;

200         else{

201             return this.runningQueue.element().getPriority();

202         }

203     }

204

205     /***************************************************

206      * @类名:Task

207      * @创建:baiyingjun (devXiaobai@gmail.com)

208      * @创建日期:2011-7-7

209      * @说明:业务对象的包装成可运行实体

210      ***************************************************/

211     public class Task implements Runnable,Comparable<Task>{

212

213         //运行

214         public static final int STATE_INIT = -1;

215         //运行

216         public static final int STATE_RUN = 0;

217         //停止

218         public static final int STATE_STOP = 1;

219         //暂停

220         public static final int STATE_PAUSE = 2;

221         //取消

222         public static final int STATE_CANCLE = 3;

223         //冻结,如果在GPRS下,因为线程调度的时候低优先级的被放readyqueue里的时候,要把这个任务暂时给“冻结”起来

224         public static final int STATE_FROST = 4;

225

226         private long taskId;

227

228         private BusinessObject bo;

229

230         public Task(){

231

232         }

233

234         public Task(BusinessObject bo){

235             this.bo=bo;

236         }

237

238         @Override

239         public void run() {

240             this.onTaskStart();

241             this.bo.execute();

242             this.onTaskEnd();

243         }

244

245         private void onTaskStart(){

246             this.bo.setmState(STATE_RUN);

247         }

248

249         public long getTaskId() {

250             return taskId;

251         }

252

253         public void setTaskId(long taskId) {

254             this.taskId = taskId;

255         }

256

257         public int getPriority() {

258             return this.bo.getPriority();

259         }

260

261         public void setPriority(int priority) {

262             this.bo.setPriority(priority);

263         }

264

265         /*

266          * compare task priority

267 */

268         @Override

269         public int compareTo(Task object1) {

270             if(this.getPriority()==object1.getPriority()&& this.equals(object1))

271                 return 0;

272             return this.getPriority()>object1.getPriority()?-1:1;

273         }

274

275         public void setState(int state){//设置当前运行的task的state

276             this.bo.setmState(state);

277             Log.d(TAG, "Set task "+this.bo.methodName+" "+this.taskId + " state " + state);

278         }

279

280         private void onTaskEnd(){//运行完毕后从taskengine运行队列里删除

281             if(Log.DBG){

282                 Log.d(TAG, "task "+this.bo.methodName+" "+taskId+" End");

283             }

284             if(this.bo.getmState() == STATE_FROST)//因为调度停止了该业务

285                 return;

286

287             final ReentrantLock lock = TaskEngine.this.lock;

288             lock.lock();

289             try{

290                 boolean removed = runningQueue.remove(this); //remove from running queue

291                 assert removed;

292                 if(Log.DBG)

293                     Log.d(TAG, this.bo.methodName+" "+this.taskId+" remove from runningQueue");

294                 needSchedule.signal(); //唤醒调度线程重新调度

295             }finally{

296                 lock.unlock();

297             }

298         }

299

300         @Override

301         public boolean equals(Object o) {

302             // TODO Auto-generated method stub

303             if(this==o){

304                 return true;

305             }

306             if(o instanceof Task){

307                 return taskId==((Task)o).taskId;

308             }

309             return false;

310         }

311     }

312

313 }完

拾漏补遗:

1.补充最初的设计类图(可能与代码不太一致,但能说明问题)

2. BusinessObject的实现代码:

1 /***************************************************

2  * @类名:BusinessObject

3  * @创建:baiyingjun (devXiaobai@gmail.com)

4  * @创建日期:2011-7-6

5  * @说明:抽象的业务,扩展的网络业务要继承这个类并实现抽象方法execute()

6  ***************************************************/

7 public abstract class BusinessObject {

8

9     public static final int LOWEST_PRIORITY=1;//最低优先级

10

11     public static final int LOW_PRIORITY=2;//低优先级

12

13     public static final int NORMAL_PRIORITY=3;//正常优先级

14

15     public static final int HIGH_PRIORITY=4;//高优先级

16

17     public static final int HIGHEST_PRIORITY=5;//最高优先级

18

19     protected BusinessListener listnener;//运行业务的回调

20

21     protected Context mContext;

22

23     private long taskId;

24

25     protected Map<String,Object> params;//运行业务需要的参数

26

27     private int priority;

28

29     public int getPriority() {

30         return priority;

31     }

32

33     public void setPriority(int priority) {

34         this.priority = priority;

35     }

36

37     //设置回调

38     public void addBusinessListener(BusinessListener listnener){

39         this.listnener=listnener;

40     }

41

42     public long doBusiness() throws NetworkNotConnectException{

43         taskId= TaskEngine.getInstance(mContext).addTask(this);

44         return taskId;

45     }

46

47     public abstract void execute();

48 }

posted on 2013-02-22 17:57 蓝少泽 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/Jack-Lu/archive/2013/02/22/2922697.html

Android网络应用的封装与调度相关推荐

  1. Android 二次封装网络加载框架

    Android 二次封装网络加载框架 写在最前面 开发当中,在请求网络的时候,大家或多或少都会使用一些第三方框架,Android-Async-Http. Volley.XUtils.Okhttp.Re ...

  2. Android AudioTrack 播放封装及测试

    Android 音频录音/播放系列: <Android AudioRecord 录音封装及测试> <Android AudioTrack 播放封装及测试> 对 Android ...

  3. android中mvp封装,android-简单快速封装MVP+Retrofit2.0+Rxjava框架

    1.概述 对于MVP(Model View Presenter)大多数做开发的人都能说出一二,或者看到网上的对mvp的解释,对其意都有大概的了解,但让你真正写一套mvp框架,是不是发现无从下手? 曾几 ...

  4. android dialog 控件,android控件封装 自己封装的dialog控件

    自定义dialog肯定是用的很多了但是感觉每次做都是很乱 单纯完成任务而已,现在封装了一下 以后用到直接copy 先上图: 主activity package com.su.testcustomdia ...

  5. Android线程池封装库

    目录介绍 1.遇到的问题和需求 1.1 遇到的问题有哪些 1.2 遇到的需求 1.3 多线程通过实现Runnable弊端 1.4 为什么要用线程池 2.封装库具有的功能 2.1 常用的功能 3.封装库 ...

  6. android动画封装,Android属性动画封装,快速构建动画

    Android实现动画效果的方式主要有帧动画.补间动画.属性动画.关于安桌动画的基础知识可以查看这篇文章Android属性动画完全解析 这里我要讲的是如何快速构建出一个动画效果,如下图: 如果我们用属 ...

  7. mqtt android封装,Android之MQTT封装使用

    一.MQTT协议介绍 客户机较小并且 MQTT 协议高效地使用网络带宽,在这个意义上,其为轻量级.MQTT 协议支持可靠的传送和即发即弃的传输. 在此协议中,消息传送与应用程序脱离. 脱离应用程序的程 ...

  8. android硬编码封装mp4,【Android 音视频开发打怪升级:音视频硬解码篇】四、音视频解封和封装:生成一个MP4...

    [声 明] 首先,这一系列文章均基于自己的理解和实践,可能有不对的地方,欢迎大家指正. 其次,这是一个入门系列,涉及的知识也仅限于够用,深入的知识网上也有许许多多的博文供大家学习了. 最后,写文章过程 ...

  9. android 加载条封装,Android基于JsBridge封装的高效带加载进度的WebView

    图片发自简书App 概述 从去年4月项目就一直用起了JsBridge,前面也针对jsBridge使用姿势介绍过一篇入门篇,<Android JsBridge实战 打造专属你的Hybrid APP ...

最新文章

  1. 学术论文常用英文句型
  2. [深度学习TF2][RNN-LSTM]文本情感分析包含(数据预处理-训练-预测)
  3. null或空值的判断处理-java
  4. 自动给神经网络找bug,Google发布TensorFuzz
  5. 算法复杂度O(1),O(n),O(logn),O(nlogn)的区别
  6. redis强一致性_Redis的8连击,验证你是否熟练掌握Redis核心知识点。
  7. JAVA CLASS混淆工具:JShrink简单试用
  8. TeXworks 设置成默认用XeLaTeX排版
  9. chrome浏览器安装包点击无反应
  10. 《圈子圈套1》—— 读后总结
  11. 按键精灵找图找色找字比色等图色命令失败的通用解决思路
  12. 利用Mac给台式机装Windows系统
  13. Jetty启动项目失败?两个命令解决address already in use问题
  14. 还你清爽桌面!运行精灵软件(快速启动工具)试用测评
  15. B/S系统界面设计与开发详解
  16. C.Lorenzo Von Matterhorn(思维+朴素lca思想)
  17. Swift 复数变量定义
  18. 【移动应用开发】实验2Android UI
  19. 什么是互动触摸屏?它有用途是什么?
  20. 【Mac】动图截图工具Kap

热门文章

  1. Echarts鼠标悬浮样式
  2. vue使用iframe 子页面调用父页面的方法
  3. Mybatis Mapper自动注入警告的解决方案
  4. 2021年度训练联盟热身训练赛第二场(ICPC North Central NA Contest 2019,南阳师范学院),签到题ABCDEFGIJ
  5. 如何进行文件管理、备份
  6. 【vijos1790】拓扑编号
  7. oracle把列数据串成一个字符串,一组数据,如何根据一个字段值分组后,把另一字段的字符串累加连接起来?...
  8. OpenGL基础45:光照矫正(下)之Gamma校正
  9. Unity3D实践1:摄像机跟随
  10. Unity3D基础10:利用Transform组件移动物体