最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android斬首行動(dòng)接口預(yù)請(qǐng)求

 更新時(shí)間:2023年03月03日 08:58:50   作者:孝之請(qǐng)回答  
這篇文章主要為大家介紹了Android斬首行動(dòng)之接口預(yù)請(qǐng)求實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

開(kāi)發(fā)同學(xué)應(yīng)該都很熟悉我們頁(yè)面的渲染過(guò)程一般是從Activity#onCreate開(kāi)始,再發(fā)起網(wǎng)絡(luò)請(qǐng)求,等請(qǐng)求回調(diào)回來(lái)后,再基于網(wǎng)絡(luò)數(shù)據(jù)渲染頁(yè)面。可以用下面這幅圖來(lái)粗略描述這個(gè)過(guò)程:

可以看到,目標(biāo)頁(yè)面渲染完成前必須得等待網(wǎng)絡(luò)請(qǐng)求,導(dǎo)致渲染速度并沒(méi)有那么快。尤其是當(dāng)網(wǎng)絡(luò)并不好的時(shí)候感受會(huì)更加明顯。并且,當(dāng)目標(biāo)頁(yè)面是H5頁(yè)面或者是Flutter頁(yè)面的時(shí)候,因?yàn)樯婕暗紿5容器與Flutter容器的創(chuàng)建,白屏?xí)r間會(huì)更長(zhǎng)。

那么有沒(méi)有可能提前發(fā)起請(qǐng)求,來(lái)縮短網(wǎng)絡(luò)請(qǐng)求這一部分的等待時(shí)間呢?這就是我們今天要講的部分,接口預(yù)請(qǐng)求。

目標(biāo)

我們要達(dá)到的目標(biāo)很簡(jiǎn)單,就是提前異步發(fā)起目標(biāo)頁(yè)面的網(wǎng)絡(luò)請(qǐng)求,從而加快目標(biāo)頁(yè)面的渲染速度。改善后的過(guò)程可以用下圖表示:

并且,我們的預(yù)請(qǐng)求能力需要盡量少地侵入業(yè)務(wù),與業(yè)務(wù)解耦,并保證能力的通用性,適用于工程內(nèi)的任意頁(yè)面(Android頁(yè)面、H5頁(yè)面、Flutter頁(yè)面)。

整體鏈路

首先給大家看一下整體鏈路,具體的細(xì)節(jié)可以先不用去摳,下面會(huì)一一講到。

預(yù)請(qǐng)求時(shí)機(jī)

預(yù)請(qǐng)求時(shí)機(jī)一般有三種選擇:

  • 由業(yè)務(wù)層自行選擇時(shí)機(jī)進(jìn)行異步預(yù)請(qǐng)求
  • 點(diǎn)擊控件時(shí)進(jìn)行異步預(yù)請(qǐng)求
  • 路由最終跳轉(zhuǎn)前進(jìn)行異步預(yù)請(qǐng)求

第1種選擇,由業(yè)務(wù)層自行選擇時(shí)機(jī)進(jìn)行預(yù)請(qǐng)求,需要涉及到業(yè)務(wù)層的改造,以及對(duì)時(shí)機(jī)合理性的把握。一方面是存在改造成本,另一方面是無(wú)法保證業(yè)務(wù)側(cè)調(diào)用時(shí)機(jī)的合理性。

第2種選擇,點(diǎn)擊控件時(shí)進(jìn)行預(yù)請(qǐng)求。若點(diǎn)擊時(shí)進(jìn)行預(yù)請(qǐng)求,點(diǎn)擊事件監(jiān)聽(tīng)并不是業(yè)務(wù)域統(tǒng)一的,無(wú)法形成有效封裝。并且,若后續(xù)路由攔截器修改了參數(shù),或是終止了跳轉(zhuǎn),這次預(yù)請(qǐng)求就失去了意義。

因此這里我們選擇第3種,基于統(tǒng)一路由框架,在路由最終跳轉(zhuǎn)前進(jìn)行預(yù)請(qǐng)求。既保證了良好的封裝性,也實(shí)現(xiàn)了對(duì)業(yè)務(wù)的零侵入,同時(shí)也做到了懶請(qǐng)求,即用戶必然要發(fā)起該請(qǐng)求時(shí)才會(huì)去預(yù)請(qǐng)求。這里需要注意的是必須是在最終跳轉(zhuǎn)前進(jìn)行預(yù)請(qǐng)求,可以理解為是路由的最后一個(gè)前置異步攔截器。

預(yù)請(qǐng)求規(guī)則配置

我們通過(guò)本地的json文件(當(dāng)然,有需要也可以上云通過(guò)配置后臺(tái)下發(fā)),對(duì)預(yù)請(qǐng)求的規(guī)則進(jìn)行配置,并將這份配置在App啟動(dòng)階段異步讀入到內(nèi)存。后續(xù)在路由過(guò)程中,只有命中了預(yù)請(qǐng)求規(guī)則,才能發(fā)起預(yù)請(qǐng)求。配置demo如下:

{
  "routeConfig":{
    "scheme://domain/path?param1=true&itemId=123":["prefetchKey"],
    "route2":["prefetchKey2"],
    "route3":["prefetchKey3","prefetchKey4"]
  },
  "prefetcher":{
    "prefetchKey":{
      "prefetchType":"network",
      "prefetchInfo":{
        "api":"network.api.name",
        "apiVersion":"1.0",
        "method":"post",
        "needLogin":"false",
        "showLoginUI":"false",
        "params": {
          "itemId":"$route.itemId",
          "firstTime":"true"
        },
        "headers": {
          
        },
        "prefetchImgInResponse": [
          {
            "imgUrl":"$data.imgData.img",
            "imgWidth":"$data.imgData.imgWidth",
            "imgHeight":150
          }
        ]
      }
    },
    "prefetchKey2":{
      "prefetchType":"network",
      "prefetchInfo":{
        "api":"network.api.name2",
        "apiVersion":"1.0",
        "method":"post",
        "needLogin":"false",
        "showLoginUI":"false",
        "params": {
          "itemId":"$route.productId",
          "firstTime":"false"
        },
        "headers": {
          
        }
    },
    "prefetchKey3":{
      "prefetchType":"image",
      "prefetchInfo":{
        "imgUrl":"$route.imgUrl",
        "imgWidth":"$route.imgWidth",
        "imgHeight": 150
      }
    },
    "prefetchKey4":{
      "prefetchInfo":{}
    }
  }
}

規(guī)則解讀

參數(shù)名描述備注
routeConfig路由配置配置路由到預(yù)請(qǐng)求的映射
prefetcher預(yù)請(qǐng)求配置記錄所有的預(yù)請(qǐng)求
prefetchKey預(yù)請(qǐng)求的key
prefetchType預(yù)請(qǐng)求類型分為network類型與image類型,兩種類型所需要的參數(shù)不同
prefetchInfo預(yù)請(qǐng)求所需要的信息其中value若為route.param格式,那么該值從路由中獲?。蝗魹閞oute.param格式,那么該值從路由中獲?。蝗魹閞oute.param格式,那么該值從路由中獲取;若為data.param格式,則從響應(yīng)數(shù)據(jù)中獲取。
paramsnetwork請(qǐng)求所需要的請(qǐng)求params
headersnetwork請(qǐng)求所需要的請(qǐng)求headers
prefetchImgFromResponse預(yù)請(qǐng)求的響應(yīng)返回后,需要預(yù)加載的圖片用于需要預(yù)加載圖片時(shí),無(wú)法確定圖片url,圖片url只能從預(yù)請(qǐng)求響應(yīng)中獲取的場(chǎng)景。

舉例說(shuō)明

網(wǎng)絡(luò)預(yù)請(qǐng)求

例如跳轉(zhuǎn)目標(biāo)頁(yè)面,它的路由是scheme://domain/path?param1=true&itemId=123

首先我們?cè)谔D(zhuǎn)路由時(shí),若跳轉(zhuǎn)的路由是這個(gè)目標(biāo)頁(yè)面,我們就會(huì)嘗試去發(fā)起預(yù)請(qǐng)求。根據(jù)上面的demo配置文件,它將匹配到prefetchKey這個(gè)預(yù)請(qǐng)求。

那么我們?cè)敿?xì)看prefetchKey這個(gè)預(yù)請(qǐng)求,預(yù)請(qǐng)求類型prefetchTypenetwork,是一個(gè)網(wǎng)絡(luò)預(yù)請(qǐng)求,prefetchInfo中具備了請(qǐng)求的基本參數(shù)(如apiName、apiVersion、method、請(qǐng)求params與請(qǐng)求headers,不同工程不一樣,大家可以根據(jù)自己的工程項(xiàng)目進(jìn)行修改)。具體看params中,有一個(gè)參數(shù)為itemId:$route.itemId。以$route.開(kāi)頭的意思,就是這個(gè)value值要從路由中獲取,即itemId=123,那么這個(gè)值就是123。

圖片預(yù)請(qǐng)求

在做網(wǎng)絡(luò)預(yù)請(qǐng)求的過(guò)程中,我忽然想到圖片做預(yù)請(qǐng)求也是可以大大提升用戶體驗(yàn)的,尤其是當(dāng)大圖片首次下載到內(nèi)存中渲染需要的時(shí)間會(huì)比較長(zhǎng)。圖片預(yù)請(qǐng)求分為url已知url未知兩種場(chǎng)景,下面各舉兩個(gè)例子。

圖片url已知

什么是圖片url已知呢?比如我們?cè)谑醉?yè)跳轉(zhuǎn)首頁(yè)的二級(jí)頁(yè)面時(shí),如果二級(jí)頁(yè)面需要預(yù)加載的圖片跟首頁(yè)的某張圖是一樣的(尺寸可能不同),那么首頁(yè)跳轉(zhuǎn)路由時(shí)我們是能夠提前知道這個(gè)圖片的url的,所以我們看到prefetchKey3中配置了prefetchTypeimage的預(yù)請(qǐng)求。image的信息來(lái)自于路由參數(shù),需要在跳轉(zhuǎn)時(shí)將圖片url和寬高作為路由參數(shù)之一。

比如scheme://domain/path?imgUrl=${encodeUrl}&imgWidth=200,那么根據(jù)配置項(xiàng),我們將提前將encodeUrl這個(gè)圖片以寬200,高150的尺寸,加載到內(nèi)存中去。當(dāng)目標(biāo)頁(yè)面用到這個(gè)圖片時(shí),將能很快渲染出來(lái)。

圖片url未知

相反,當(dāng)跳轉(zhuǎn)目標(biāo)頁(yè)面時(shí),目標(biāo)頁(yè)面所要加載的圖片url沒(méi)法取到,就對(duì)應(yīng)了圖片url未知的場(chǎng)景。

例如閃屏頁(yè)跳轉(zhuǎn)首頁(yè)時(shí),如果需要預(yù)加載首頁(yè)頂部的圖片,此時(shí)閃屏頁(yè)是無(wú)法獲取到圖片的url的,因?yàn)檫@個(gè)圖片url是首頁(yè)接口返回的。這種情況下,我們只能依賴首頁(yè)的預(yù)請(qǐng)求進(jìn)行。

在demo配置文件中,我們可以看到prefetchImgFromResponse字段。這個(gè)字段代表著,當(dāng)這個(gè)預(yù)請(qǐng)求響應(yīng)回來(lái)之后,我需要去預(yù)請(qǐng)求某張圖片。其中,imgUrl$data.param格式,以$data.開(kāi)頭,代表著這份數(shù)據(jù)是來(lái)自于響應(yīng)數(shù)據(jù)的。響應(yīng)數(shù)據(jù)就是一串json串,可以憑此,索引到預(yù)請(qǐng)求響應(yīng)中圖片url的位置,就能實(shí)現(xiàn)圖片的提前加載了。

至于圖片怎么提前加載到內(nèi)存中,以及真實(shí)圖片的加載怎么匹配到內(nèi)存中的圖片,這一部分是通過(guò)glide已有的preload機(jī)制實(shí)現(xiàn)的,感興趣的同學(xué)可以去看一下源碼了解一下,這里就不展開(kāi)了。后面講的預(yù)請(qǐng)求的方案細(xì)節(jié),都只限于網(wǎng)絡(luò)請(qǐng)求。

預(yù)請(qǐng)求匹配

預(yù)請(qǐng)求匹配指的是實(shí)際的業(yè)務(wù)請(qǐng)求怎樣與已經(jīng)執(zhí)行的預(yù)請(qǐng)求匹配上,從而節(jié)省請(qǐng)求的空中時(shí)間,直接返回預(yù)請(qǐng)求的結(jié)果。

首先網(wǎng)絡(luò)預(yù)請(qǐng)求執(zhí)行前先在內(nèi)存中生成一份PrefetchRecord,代表著已經(jīng)執(zhí)行的預(yù)請(qǐng)求,其中的字段跟配置文件中差不多,主要就是記錄預(yù)請(qǐng)求相關(guān)的信息:

class PrefetchRecord {
    // 請(qǐng)求信息
    String api;
    String apiVersion;
    String method;
    String needLogin;
    String showLoginUI;
    JSONObject params;
    JSONObject headers;

    // 預(yù)請(qǐng)求狀態(tài)
    int status;
    // 預(yù)請(qǐng)求結(jié)果
    ResponseModel response;
    // 生成的請(qǐng)求id
    String requestId;

    boolean isMatch(RealRequest realRequest) {
        requestId.equals(realRequest.requestId)
    }
}

每一個(gè)PrefetchRecord生成時(shí),都會(huì)生成一個(gè)requestId,用于跟實(shí)際業(yè)務(wù)請(qǐng)求進(jìn)行匹配。requestId的生成規(guī)則可以自行制定,比如將所有請(qǐng)求信息包一起做一下md5處理之類。

在實(shí)際業(yè)務(wù)請(qǐng)求發(fā)起之前,也會(huì)根據(jù)同樣的規(guī)則生成requestId。若內(nèi)存中存在相同requestId對(duì)應(yīng)的PrefetchRecord,那么就相當(dāng)于匹配成功了。匹配成功后,再根據(jù)預(yù)請(qǐng)求的狀態(tài)進(jìn)行進(jìn)一步的處理。

預(yù)請(qǐng)求狀態(tài)

預(yù)請(qǐng)求狀態(tài)分為START、FINISH、ABORT,對(duì)應(yīng)“正在發(fā)起預(yù)請(qǐng)求”、“已經(jīng)獲得預(yù)請(qǐng)求結(jié)果”、“預(yù)請(qǐng)求被拋棄”。ABORT狀態(tài)下一節(jié)再講。

為什么要記錄這個(gè)狀態(tài)呢?因?yàn)槲覀儫o(wú)法保證,預(yù)請(qǐng)求的響應(yīng)一定在實(shí)際請(qǐng)求之前。用圖來(lái)表示:

因?yàn)轭A(yù)請(qǐng)求是一個(gè)并發(fā)行為。當(dāng)預(yù)請(qǐng)求的空中時(shí)間特別長(zhǎng),長(zhǎng)到目標(biāo)頁(yè)面已經(jīng)發(fā)出實(shí)際請(qǐng)求了,預(yù)請(qǐng)求的響應(yīng)還沒(méi)回來(lái),即預(yù)請(qǐng)求狀態(tài)為START,而非FINISH。那么此時(shí)該怎么辦?我們就需要讓實(shí)際請(qǐng)求在一旁等著(記錄到內(nèi)存中,RealRequestRecord),等預(yù)請(qǐng)求接收到響應(yīng)了,再根據(jù)requestId去進(jìn)行匹配,匹配到RealRequestRecord了,就觸發(fā)RealRequestRecord中的回調(diào),返回?cái)?shù)據(jù)。

另外,在匹配過(guò)程中需要注意一點(diǎn),因?yàn)槊看温酚商D(zhuǎn),如果發(fā)起預(yù)請(qǐng)求了,總會(huì)生成一個(gè)Record在內(nèi)存中等待匹配。因此在匹配結(jié)束后,不管是匹配成功還是匹配失敗,都要及時(shí)釋放將Record從內(nèi)存中釋放掉。

超時(shí)重試機(jī)制

基于實(shí)際請(qǐng)求等待預(yù)請(qǐng)求響應(yīng)的場(chǎng)景,我們?cè)傺由煲幌隆H纛A(yù)請(qǐng)求請(qǐng)求超時(shí),遲遲拿不到響應(yīng),該怎么辦?用圖表示:

假設(shè)目前的網(wǎng)絡(luò)請(qǐng)求,端上默認(rèn)的超時(shí)時(shí)間是30s。那么在超時(shí)場(chǎng)景下,實(shí)際的業(yè)務(wù)請(qǐng)求在30s內(nèi)若拿不到預(yù)請(qǐng)求的結(jié)果,就需要重新發(fā)起業(yè)務(wù)請(qǐng)求,拋棄預(yù)請(qǐng)求,并將預(yù)請(qǐng)求的狀態(tài)置為ABORT,這樣即使后面預(yù)請(qǐng)求響應(yīng)回來(lái)了也不做任何處理。

忽然想到一個(gè)很貼切的場(chǎng)景來(lái)比喻這個(gè)預(yù)請(qǐng)求方案。

我們把跳轉(zhuǎn)頁(yè)面理解為去柜臺(tái)取餐。

預(yù)請(qǐng)求代表著我們?nèi)诉€沒(méi)到柜臺(tái),就先遠(yuǎn)程下單讓柜員去準(zhǔn)備食物。

如果柜員準(zhǔn)備得比較快,那么我們到柜臺(tái)后就能直接把食物拿走了,就能快點(diǎn)吃上了(代表著頁(yè)面渲染速度變快)。

如果柜員準(zhǔn)備得比較慢,那么我們到柜臺(tái)后還是得等一會(huì)兒才能取餐,但總體上吃上食物的速度還是要比到柜臺(tái)后再點(diǎn)餐來(lái)得快。

但如果這個(gè)柜員消極怠工準(zhǔn)備得太慢了,我們到柜臺(tái)等了很久都沒(méi)拿到食物,那么我們就只能換個(gè)柜員重新點(diǎn)了(超時(shí)后發(fā)起實(shí)際的業(yè)務(wù)請(qǐng)求),同時(shí)還不忘投訴一把(預(yù)請(qǐng)求空中時(shí)間太慢了)。

總結(jié)

通過(guò)這篇文章,我們知道了什么是接口預(yù)請(qǐng)求,怎么實(shí)現(xiàn)接口預(yù)請(qǐng)求。我們通過(guò)配置文件+統(tǒng)一路由處理+預(yù)請(qǐng)求發(fā)起、匹配、回調(diào),實(shí)現(xiàn)了與業(yè)務(wù)解耦的,可適用于任意頁(yè)面的輕量級(jí)預(yù)請(qǐng)求方案,從而提升頁(yè)面的渲染速度。

以上就是Android斬首行動(dòng)接口預(yù)請(qǐng)求的詳細(xì)內(nèi)容,更多關(guān)于Android接口預(yù)請(qǐng)求的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 關(guān)于Android的 DiskLruCache磁盤緩存機(jī)制原理

    關(guān)于Android的 DiskLruCache磁盤緩存機(jī)制原理

    DiskLruCache是一種管理數(shù)據(jù)存儲(chǔ)的技術(shù),單從Cache的字面意思也可以理解到,"Cache","高速緩存";今天我們來(lái)從源碼上分析下DiskLruCache;關(guān)于Android LruCache的緩存機(jī)制原理,需要的朋友可以參考下面文章的具體內(nèi)容
    2021-09-09
  • Android NotificationManager簡(jiǎn)單使用詳解

    Android NotificationManager簡(jiǎn)單使用詳解

    這篇文章主要為大家詳細(xì)介紹了Android NotificationManager的簡(jiǎn)單使用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Android畢業(yè)設(shè)計(jì)備忘錄APP

    Android畢業(yè)設(shè)計(jì)備忘錄APP

    這篇文章主要介紹了一個(gè)Android畢業(yè)設(shè)計(jì)備忘錄APP,它很小,但是功能很全,可實(shí)現(xiàn)添加、刪除、修改、查看的功能,使用Java語(yǔ)言開(kāi)發(fā),風(fēng)格簡(jiǎn)練
    2021-08-08
  • Android開(kāi)發(fā)人臉識(shí)別統(tǒng)計(jì)人臉數(shù)

    Android開(kāi)發(fā)人臉識(shí)別統(tǒng)計(jì)人臉數(shù)

    這篇文章主要介紹了Android開(kāi)發(fā)人臉識(shí)別統(tǒng)計(jì)人臉數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • Android仿QQ左滑刪除置頂ListView操作

    Android仿QQ左滑刪除置頂ListView操作

    這篇文章主要為大家詳細(xì)介紹了Android仿QQ左滑刪除置頂ListView操作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Android簡(jiǎn)單的短信驗(yàn)證功能的實(shí)現(xiàn)代碼

    Android簡(jiǎn)單的短信驗(yàn)證功能的實(shí)現(xiàn)代碼

    這篇文章主要介紹了Android簡(jiǎn)單的短信驗(yàn)證功能的實(shí)現(xiàn)代碼,本文是小編使用sdk過(guò)程的一些心得,需要的朋友可以參考下
    2018-07-07
  • viewpager實(shí)現(xiàn)自動(dòng)循環(huán)輪播圖

    viewpager實(shí)現(xiàn)自動(dòng)循環(huán)輪播圖

    這篇文章主要為大家詳細(xì)介紹了viewpager實(shí)現(xiàn)自動(dòng)循環(huán)輪播圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-01-01
  • Android BottomSheet效果的兩種實(shí)現(xiàn)方式

    Android BottomSheet效果的兩種實(shí)現(xiàn)方式

    這篇文章主要介紹了Android BottomSheet效果的兩種實(shí)現(xiàn)方式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • Android異步回調(diào)中的UI同步性問(wèn)題分析

    Android異步回調(diào)中的UI同步性問(wèn)題分析

    這篇文章主要為大家詳細(xì)分析了Android異步回調(diào)中的UI同步性問(wèn)題,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Android大作業(yè)功能設(shè)計(jì)之自動(dòng)登錄和記住密碼

    Android大作業(yè)功能設(shè)計(jì)之自動(dòng)登錄和記住密碼

    SharedPreferences是Android平臺(tái)上一個(gè)輕量級(jí)的存儲(chǔ)類,主要是保存一些常用的配置參數(shù),它是采用xml文件存放數(shù)據(jù)的,文件存放在"/data/data<package?name>/shared_prefs"目錄下,由于SharedPreferences是一個(gè)接口,而且在這個(gè)接口里沒(méi)有提供寫入數(shù)據(jù)和讀取數(shù)據(jù)的能力
    2023-01-01

最新評(píng)論

措美县| 龙游县| 天台县| 噶尔县| 新绛县| 白水县| 景宁| 东平县| 曲麻莱县| 瓦房店市| 涡阳县| 易门县| 承德市| 乐陵市| 昭平县| 三都| 磴口县| 金沙县| 河池市| 浪卡子县| 镇江市| 准格尔旗| 盖州市| 台北市| 泸水县| 尼木县| 沛县| 蒙城县| 容城县| 磴口县| 九龙坡区| 昌乐县| 买车| 庆云县| 油尖旺区| 顺昌县| 兴海县| 玉环县| 凤凰县| 米林县| 砚山县|