android非RxJava环境下使用Handler实现预加载

android非RxJava环境下使用Handler实现预加载,第1张

概述在进行Android客户端界面开发时,我们常常会需要将从服务端获取的数据展示到页面布局上,由于数据显示到布局的前置条件是页面布局已初始化完成,否则会出现空指针异常,所以一般我们需要将网络请求放在布局初始化完成

在进行AndroID客户端界面开发时,我们常常会需要将从服务端获取的数据展示到页面布局上,由于数据显示到布局的前置条件是页面布局已初始化完成,否则会出现空指针异常,所以一般我们需要将网络请求放在布局初始化完成之后。
传统的页面加载流程是:

问题:

如果加载的UI布局比较复杂,或者初始化逻辑执行的时间比较多,那么网络请求开始执行的时间就比较晚,最终完成页面加载的时间就比较长。
如果页面初始化和网络加载能同时进行,等两者都执行结束后,再在布局上展示网络数据,这样我们就可以缩短整个页面的加载时间了。
所以,我们期望的页面加载流程是:

这个流程我们称之为:预加载

预加载的目标任务可以是一个网络请求,也可以是其它一些耗时 *** 作,例如:加载一张图片到控件上展示
在实现预加载方案之前,我们需要了解一下Handler工作机制中的SyncbarrIEr概念,对barrIEr概念了解可以看这篇文章中对“同步分割栏”的介绍, 此处我们简单理解为:

在MessageQueue中添加一个特殊的msg,将这个msg作为一个标记,在这个标记被移除之前,当前Messagequeue队列中排在它后面的其它(非async) 的message不会被handler处理。

我们可以先不理会什么是 非async 的message,若需要了解更多,这篇文章中对“同步分割栏”的介绍中也有相关介绍。

利用这个特性,我们可以:

启动一个HandlerThread来异步执行网络请求
设置一个标记SyncbarrIEr,此后在message将一直在messageQueue中不被执行
网络请求成功后,post一个任务来执行展示数据
布局初始化成功后,移除SyncbarrIEr
将展示数据的任务post到ui线程来执行
步骤3和步骤4的先后顺序可以交换

其中,在androID API 22及之前,设置标记SyncbarrIEr可以由

HandlerThread.getLooper().postsyncbarrIEr();

在androID API 23以后,需要调用的方法为:

HandlerThread.getLooper().getQueue().postsyncbarrIEr();

同样的,移除标记的方法分别为:

HandlerThread.getLooper().removeSyncbarrIEr(token);HandlerThread.getLooper().getQueue().removeSyncbarrIEr(token);

不幸的是:这些方法都是@hIDe的,无法直接调用。
幸运的是:我们还有反射

封装工具类如下: PreLoader.java

import androID.os.Handler;import androID.os.HandlerThread;import androID.os.Looper;import androID.os.MessageQueue;import java.lang.reflect.Method;/*** 使用Handler方式实现的预加载* @author billy.qi*/public class PreLoader { private int token; private Handler mainThreadHandler;//用于将结果处理的task放在主线程中执行 private HandlerThread handlerThread;//提供一个异步线程来运行预加载任务 private Handler handler;//预加载使用的handler private PreLoader(final Runnable task) { mainThreadHandler = new Handler(Looper.getMainLooper()); handlerThread = new HandlerThread("pre-loader") {  @OverrIDe  protected voID onLooperPrepared() {  super.onLooperPrepared();  handler = new Handler();  handler.post(task);  //设置同步分割,后面post进来的sync为true的message将暂停执行  Looper looper = handlerThread.getLooper();  if (androID.os.Build.VERSION.SDK_INT >= androID.os.Build.VERSION_CODES.M) {   postsyncbarrIEr(looper.getQueue());  } else {   postsyncbarrIEr(looper);  }  } }; handlerThread.start(); } /** * 开启预加载 * 比如:开始网络请求(在HandlerThread中执行) * @param task 预加载任务 */ public static PreLoader preLoad(Runnable task) { return new PreLoader(task); } /** * 处理加载结果,一般在预加载任务处理完成后调用 * 由于有handler所在的messageQueue设置了同步分割(SyncbarrIEr),该task * @param task 在主线程中执行的任务 */ public voID performResultTask(final Runnable task) { if (handler != null) {  handler.post(new Runnable() {  @OverrIDe  public voID run() {   mainThreadHandler.post(task);  }  }); } } /** * 可以开始执行预加载结果处理 */ public voID readyToGetData() { Looper looper = handlerThread.getLooper(); if (androID.os.Build.VERSION.SDK_INT >= androID.os.Build.VERSION_CODES.M) {  removeSyncbarrIEr(looper.getQueue()); } else {  removeSyncbarrIEr(looper); } } private voID postsyncbarrIEr(Object obj) { try{  Method method = MessageQueue.class.getmethod("postsyncbarrIEr");  token = (int) method.invoke(obj); } catch(Exception e) {  e.printstacktrace(); } } private voID removeSyncbarrIEr(Object obj) { try{  Method method = MessageQueue.class.getmethod("removeSyncbarrIEr",int.class);  method.invoke(obj,token); } catch(Exception e) {  e.printstacktrace(); } } public voID destroy() { handlerThread.quit(); handlerThread = null; handler = null; mainThreadHandler = null; }}

在activity中使用实例:

import androID.os.Bundle;import androID.support.v7.app.AppCompatActivity;import androID.Widget.TextVIEw;public class PreLoaderActivity extends AppCompatActivity { private PreLoader preLoader; private TextVIEw textVIEw; @OverrIDe protected voID onCreate(Bundle savedInstanceState) { preLoad();//启动预加载 //进行页面布局加载及其它初始化工作 super.onCreate(savedInstanceState); setContentVIEw(R.layout.activity_main); textVIEw = (TextVIEw)findVIEwByID(R.ID.textVIEw); //布局初始化完成 preLoader.readyToGetData(); } private voID preLoad() { //预加载的任务 preLoader = PreLoader.preLoad(new Runnable() {  //将得到的请求结果展示到布局控件上  @OverrIDe  public voID run() {  //模拟网络请求耗时  try {   Thread.sleep(500);  } catch (InterruptedException e) {   e.printstacktrace();  }  final String result = "result";  //在UI线程执行的显示任务  preLoader.performResultTask(new Runnable() {   //将得到的请求结果展示到布局控件上   @OverrIDe   public voID run() {   textVIEw.setText(result);   }  });  } }); } @OverrIDe protected voID onDestroy() { super.onDestroy(); //在onDestroy()中进行销毁 preLoader.destroy(); }}


通过预加载,让一部分异步任务提前执行,可以用来提高整体速度。
以上都是以网络请求作为预加载的目的,它同时还可以用来预加载图片、预加载文件、读取数据库等;
除了预加载外,还可以用来作为多个任务并行,并全部执行完之后,再执行另一个任务对之前所有任务执行的结果进行处理。

总结:
在多线程开发时,经常会遇到以下情况:

任务A、任务B(甚至更多任务)是任务C的充要条件,为了提高效率,我们希望AB同时执行,当AB都完成之后,开始执行任务C。
这种情况下我们可以用这种方式来解决。

最后,源码下载地址

总结

以上是内存溢出为你收集整理的android非RxJava环境下使用Handler实现预加载全部内容,希望文章能够帮你解决android非RxJava环境下使用Handler实现预加载所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1147104.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存