中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

android開發中使用Handler怎么實現預加載功能

發布時間:2020-11-20 16:36:47 來源:億速云 閱讀:224 作者:Leah 欄目:移動開發

這篇文章將為大家詳細講解有關android開發中使用Handler怎么實現預加載功能,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

在進行Android客戶端界面開發時,我們常常會需要將從服務端獲取的數據展示到頁面布局上,由于數據顯示到布局的前置條件是頁面布局已初始化完成,否則會出現空指針異常,所以一般我們需要將網絡請求放在布局初始化完成之后。
傳統的頁面加載流程是:

android開發中使用Handler怎么實現預加載功能

問題:

如果加載的UI布局比較復雜,或者初始化邏輯執行的時間比較多,那么網絡請求開始執行的時間就比較晚,最終完成頁面加載的時間就比較長。
如果頁面初始化和網絡加載能同時進行,等兩者都執行結束后,再在布局上展示網絡數據,這樣我們就可以縮短整個頁面的加載時間了。
所以,我們期望的頁面加載流程是:

android開發中使用Handler怎么實現預加載功能

這個流程我們稱之為:預加載

預加載的目標任務可以是一個網絡請求,也可以是其它一些耗時操作,例如:加載一張圖片到控件上展示
在實現預加載方案之前,我們需要了解一下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();
 }
}

通過預加載,讓一部分異步任務提前執行,可以用來提高整體速度。
以上都是以網絡請求作為預加載的目的,它同時還可以用來預加載圖片、預加載文件、讀取數據庫等;
除了預加載外,還可以用來作為多個任務并行,并全部執行完之后,再執行另一個任務對之前所有任務執行的結果進行處理。

關于android開發中使用Handler怎么實現預加載功能就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

汤原县| 林口县| 黄陵县| 秦安县| 丘北县| 佳木斯市| 武安市| 屏山县| 林口县| 泽普县| 漠河县| 万盛区| 松桃| 嘉定区| 宁南县| 琼结县| 乌鲁木齐市| 甘谷县| 融水| 绥中县| 灵璧县| 龙口市| 浮梁县| 缙云县| 东辽县| 福海县| 岚皋县| 广州市| 淳安县| 陈巴尔虎旗| 龙井市| 婺源县| 泊头市| 新津县| 灵璧县| 华池县| 临沂市| 镇沅| 怀远县| 腾冲县| 东乌珠穆沁旗|