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

溫馨提示×

溫馨提示×

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

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

Android斬首行動接口預請求問題怎么解決

發布時間:2023-03-09 15:03:27 來源:億速云 閱讀:95 作者:iii 欄目:開發技術

本篇內容介紹了“Android斬首行動接口預請求問題怎么解決”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    前言

    開發同學應該都很熟悉我們頁面的渲染過程一般是從Activity#onCreate開始,再發起網絡請求,等請求回調回來后,再基于網絡數據渲染頁面。可以用下面這幅圖來粗略描述這個過程:

    Android斬首行動接口預請求問題怎么解決

    可以看到,目標頁面渲染完成前必須得等待網絡請求,導致渲染速度并沒有那么快。尤其是當網絡并不好的時候感受會更加明顯。并且,當目標頁面是H5頁面或者是Flutter頁面的時候,因為涉及到H5容器與Flutter容器的創建,白屏時間會更長。

    那么有沒有可能提前發起請求,來縮短網絡請求這一部分的等待時間呢?這就是我們今天要講的部分,接口預請求。

    目標

    我們要達到的目標很簡單,就是提前異步發起目標頁面的網絡請求,從而加快目標頁面的渲染速度。改善后的過程可以用下圖表示:

    Android斬首行動接口預請求問題怎么解決

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

    整體鏈路

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

    Android斬首行動接口預請求問題怎么解決

    預請求時機

    預請求時機一般有三種選擇:

    • 由業務層自行選擇時機進行異步預請求

    • 點擊控件時進行異步預請求

    • 路由最終跳轉前進行異步預請求

    第1種選擇,由業務層自行選擇時機進行預請求,需要涉及到業務層的改造,以及對時機合理性的把握。一方面是存在改造成本,另一方面是無法保證業務側調用時機的合理性。

    第2種選擇,點擊控件時進行預請求。若點擊時進行預請求,點擊事件監聽并不是業務域統一的,無法形成有效封裝。并且,若后續路由攔截器修改了參數,或是終止了跳轉,這次預請求就失去了意義。

    因此這里我們選擇第3種,基于統一路由框架,在路由最終跳轉前進行預請求。既保證了良好的封裝性,也實現了對業務的零侵入,同時也做到了懶請求,即用戶必然要發起該請求時才會去預請求。這里需要注意的是必須是在最終跳轉前進行預請求,可以理解為是路由的最后一個前置異步攔截器。

    預請求規則配置

    我們通過本地的json文件(當然,有需要也可以上云通過配置后臺下發),對預請求的規則進行配置,并將這份配置在App啟動階段異步讀入到內存。后續在路由過程中,只有命中了預請求規則,才能發起預請求。配置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":{}
        }
      }
    }

    規則解讀

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

    舉例說明

    網絡預請求

    例如跳轉目標頁面,它的路由是scheme://domain/path?param1=true&itemId=123

    首先我們在跳轉路由時,若跳轉的路由是這個目標頁面,我們就會嘗試去發起預請求。根據上面的demo配置文件,它將匹配到prefetchKey這個預請求。

    那么我們詳細看prefetchKey這個預請求,預請求類型prefetchTypenetwork,是一個網絡預請求,prefetchInfo中具備了請求的基本參數(如apiName、apiVersion、method、請求params與請求headers,不同工程不一樣,大家可以根據自己的工程項目進行修改)。具體看params中,有一個參數為itemId:$route.itemId。以$route.開頭的意思,就是這個value值要從路由中獲取,即itemId=123,那么這個值就是123。

    圖片預請求

    在做網絡預請求的過程中,我忽然想到圖片做預請求也是可以大大提升用戶體驗的,尤其是當大圖片首次下載到內存中渲染需要的時間會比較長。圖片預請求分為url已知url未知兩種場景,下面各舉兩個例子。

    圖片url已知

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

    比如scheme://domain/path?imgUrl=${encodeUrl}&imgWidth=200,那么根據配置項,我們將提前將encodeUrl這個圖片以寬200,高150的尺寸,加載到內存中去。當目標頁面用到這個圖片時,將能很快渲染出來。

    圖片url未知

    相反,當跳轉目標頁面時,目標頁面所要加載的圖片url沒法取到,就對應了圖片url未知的場景。

    例如閃屏頁跳轉首頁時,如果需要預加載首頁頂部的圖片,此時閃屏頁是無法獲取到圖片的url的,因為這個圖片url是首頁接口返回的。這種情況下,我們只能依賴首頁的預請求進行。

    在demo配置文件中,我們可以看到prefetchImgFromResponse字段。這個字段代表著,當這個預請求響應回來之后,我需要去預請求某張圖片。其中,imgUrl$data.param格式,以$data.開頭,代表著這份數據是來自于響應數據的。響應數據就是一串json串,可以憑此,索引到預請求響應中圖片url的位置,就能實現圖片的提前加載了。

    至于圖片怎么提前加載到內存中,以及真實圖片的加載怎么匹配到內存中的圖片,這一部分是通過glide已有的preload機制實現的,感興趣的同學可以去看一下源碼了解一下,這里就不展開了。后面講的預請求的方案細節,都只限于網絡請求。

    預請求匹配

    預請求匹配指的是實際的業務請求怎樣與已經執行的預請求匹配上,從而節省請求的空中時間,直接返回預請求的結果。

    首先網絡預請求執行前先在內存中生成一份PrefetchRecord,代表著已經執行的預請求,其中的字段跟配置文件中差不多,主要就是記錄預請求相關的信息:

    class PrefetchRecord {
        // 請求信息
        String api;
        String apiVersion;
        String method;
        String needLogin;
        String showLoginUI;
        JSONObject params;
        JSONObject headers;
    
        // 預請求狀態
        int status;
        // 預請求結果
        ResponseModel response;
        // 生成的請求id
        String requestId;
    
        boolean isMatch(RealRequest realRequest) {
            requestId.equals(realRequest.requestId)
        }
    }

    每一個PrefetchRecord生成時,都會生成一個requestId,用于跟實際業務請求進行匹配。requestId的生成規則可以自行制定,比如將所有請求信息包一起做一下md5處理之類。

    在實際業務請求發起之前,也會根據同樣的規則生成requestId。若內存中存在相同requestId對應的PrefetchRecord,那么就相當于匹配成功了。匹配成功后,再根據預請求的狀態進行進一步的處理。

    預請求狀態

    預請求狀態分為START、FINISH、ABORT,對應“正在發起預請求”、“已經獲得預請求結果”、“預請求被拋棄”。ABORT狀態下一節再講。

    為什么要記錄這個狀態呢?因為我們無法保證,預請求的響應一定在實際請求之前。用圖來表示:

    Android斬首行動接口預請求問題怎么解決

    因為預請求是一個并發行為。當預請求的空中時間特別長,長到目標頁面已經發出實際請求了,預請求的響應還沒回來,即預請求狀態為START,而非FINISH。那么此時該怎么辦?我們就需要讓實際請求在一旁等著(記錄到內存中,RealRequestRecord),等預請求接收到響應了,再根據requestId去進行匹配,匹配到RealRequestRecord了,就觸發RealRequestRecord中的回調,返回數據。

    另外,在匹配過程中需要注意一點,因為每次路由跳轉,如果發起預請求了,總會生成一個Record在內存中等待匹配。因此在匹配結束后,不管是匹配成功還是匹配失敗,都要及時釋放將Record從內存中釋放掉。

    超時重試機制

    基于實際請求等待預請求響應的場景,我們再延伸一下。若預請求請求超時,遲遲拿不到響應,該怎么辦?用圖表示:

    Android斬首行動接口預請求問題怎么解決

    假設目前的網絡請求,端上默認的超時時間是30s。那么在超時場景下,實際的業務請求在30s內若拿不到預請求的結果,就需要重新發起業務請求,拋棄預請求,并將預請求的狀態置為ABORT,這樣即使后面預請求響應回來了也不做任何處理。

    忽然想到一個很貼切的場景來比喻這個預請求方案。

    我們把跳轉頁面理解為去柜臺取餐。

    預請求代表著我們人還沒到柜臺,就先遠程下單讓柜員去準備食物。

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

    如果柜員準備得比較慢,那么我們到柜臺后還是得等一會兒才能取餐,但總體上吃上食物的速度還是要比到柜臺后再點餐來得快。

    但如果這個柜員消極怠工準備得太慢了,我們到柜臺等了很久都沒拿到食物,那么我們就只能換個柜員重新點了(超時后發起實際的業務請求),同時還不忘投訴一把(預請求空中時間太慢了)。

    “Android斬首行動接口預請求問題怎么解決”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

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

    AI

    久治县| 偏关县| 长治市| 永泰县| 于都县| 莫力| 兴宁市| 罗山县| 洪洞县| 丰都县| 财经| 青浦区| 安康市| 黎城县| 长沙县| 彝良县| 阿拉善左旗| 阜城县| 湘潭县| 邛崃市| 茌平县| 漳平市| 会昌县| 乳山市| 嵊州市| 九江县| 郴州市| 天门市| 曲水县| 和政县| 拉孜县| 福州市| 梁河县| 塔城市| 象州县| 兴安县| 康乐县| 原阳县| 会理县| 中阳县| 阿拉善盟|