主頁 > 移動端開發 > iOS 性能檢測新方式?——AnimationHitches

iOS 性能檢測新方式?——AnimationHitches

2021-10-29 07:12:38 移動端開發

eae57317cbc52effaaf6e2864e1612b2.gif

AnimationHitches 的運行原理

背景

在 Xcode12 中,Instrument 新增 AnimationHitches 檢測型別用以檢測卡頓,并去除 CoreAnimation 檢測方式,在支持 PromotionDisplay 的設備上幀率可調整至 120 幀,并且會根據當前用戶手勢和設備狀態進行動態調整,此時再繼續使用幀率來判斷性能的好壞及流暢度將會是一個錯誤的選擇,所以 AnimationHitches 主要用于代替幀率檢測,并且提出 卡頓時間比(Hitch Time Ratio) 的概念用于替代 FPS,由于目前關于 Hitch 相關的資料很少,而在 iPhone13Pro 之前 iPhone 螢屏最高重繪頻率仍為 60 HZ,所以很多同學都還未關注到該能力,所以本篇將主要介紹 Hitch(卡頓) 的概念、RenderLoop(渲染回圈) 的整體流程,卡頓型別及如何避免卡頓,

什么是卡頓?

? 概念

任何時候螢屏上出現晚于預計的幀都屬于卡頓,

e4d682592bce71e9efc296e0423978a5.png

? 實體

例如 滾動影片(Scroll)、點擊影片(Animation)、轉場影片(Transition),這些流暢的影片構建了一種用戶和螢屏內容的視覺連接感,而如果影片卡頓會導致影片畫面跳躍,打破這種連接感,用戶體驗會變得很差,

8fb5737fe2660744692f7d0640a22bc5.png

一個常見的例子,當用戶在操作一個滾動視圖上下滾動時,發生了卡頓,這是因為第四幀的延遲導致了第三幀占用了兩幀的時間,給用戶看到的就是卡頓掉幀的現象,

0cf659f6aa569c6e3b70b83e7ac326c6.png

RenderLoop

? 概念

RenderLoop 是一個連續的程序,通過用戶手勢等將事件傳給 App,接著 App 向作業系統傳遞事件并最終回應事件,再將回應傳遞給用戶的程序,

a5ffedffd4180a04a416c1e224ba42da.png

RenderLoop 的時間隨著設備重繪頻率,在 iPhone13 Pro(Max) 以下的 iPhone 設備最大均為 60 幀,而 iPhone13 Pro(Max) 及 iPadPro 則最高支持 120 幀,也就是最短僅需每 8.33 毫秒就可以顯示一個新幀,

fa941a771aeb4f2ec85604fd8bed9cc2.png

? 幀準備階段

在準備每一幀的程序中,可以總體分為三個階段,App、RenderServer 和 Display,其中 App 中主要進行一些用戶事件的處理,而 RenderServer 會進行真正的用戶界面繪制,這兩個階段都需要在下一個 VSNYC 到來前完成,最終到 Display 階段會將緩沖的幀展示出來,對這一幀進行雙幀處理我們把這稱之為雙緩沖,由于顯示幕是逐行掃描進行畫面顯示,雙緩沖和垂直同步機制避免了螢屏撕裂的現象,

b7fe8afd700ecdd280b411496c034b8b.png

當然,系統也提供備用的三緩沖機制,為 RenderServer 提供額外的一幀進行渲染,該機制通常情況下不會開啟,

086145438edbc76a619d4cfb6d68b18f.png

? 階段細節

整個渲染回圈可細分為 5 個階段,其中在我們 App 中的為 Event,Commit 階段,而 Commit 階段可進一步細分為 Layout、Display、Prepare 和 Commit,

  1. 在事件階段通過 touch,timer 等事件決定用戶界面是否需要改變;

  2. 而在 Commit 階段 App 會向渲染服務器 RenderServer 提交渲染命令;

  3. RenderServer 中的 Prepare,Execute 階段,在 Prepare 階段會為 GPU 的繪制做好準備,而在 Execute 階段會由 GPU 將用戶界面的影像繪制出來;

  4. 最后的 Display 階段會將緩沖幀交換到螢屏上顯示,

a2c8150227b49b8a5926a1d94afc481c.png

以一個帶有陰影的渲染圖形為例,觀察下 RenderLoop 中每一幀所做的作業

9b05defa960e476fa2442cefcb99b3e3.png

  • App

Event

在該階段表示 App 接收到了事件,比如 touch 事件、網路請求回呼、鍵盤和 Timer ,一個 App 可以通過改變其層級結構或是用任何其他方式回應這些事件,

ad84111621ee8acd32dfb50682e01758.png

例如 App 能改變圖層的背景顏色,甚至能改變圖層的大小和位置,當 App 更新了圖層的限制范圍時, CoreAnimation 會同時會呼叫 setNeedsLayout,它能夠分辨哪些圖層必須要重新計算布局,系統會合并這些需要布局的請求并在 Commit 階段按順序執行,用以減少重復作業,

08dabfc11f8e56af0f6693fe1924888e.png

Commit

在一次事務的提交中共涉及四個不同的階段:布局階段、顯示階段、準備階段和最后的提交階段,

14d37eb269f63c895b7b20586a4b56ab.png

布局階段

在布局階段, layoutSubviews 會被所有需要布局的 View 呼叫,比如布局視圖(frame、bounds、transform),增加或移除視圖,亦或是直接呼叫 setNeedsLayout,注意這些布局操作并非立即執行,系統會合并這些布局請求,在 Runloop 休眠前統一執行這些操作,

顯示階段

在顯示階段,drawRect 會被每個需要被更新的 View 呼叫,比如 UILabel、UIImageView 或者只是任何重寫 drawRect 方法的類,他們必須呼叫 setNeedsDisplay 用以支持 View 的更新,在繪制時每個自定義的繪圖圖層都會接收到帶紋理的 CoreGraphics 的背景,他們將利用 CoreAnimation 進行繪制,這些圖層就變成了圖片,所以如果沒有必要則不要重寫 drawRect 方法,其不僅會額外開辟一塊記憶體用以存盤 bitmap,還會在 CPU 上進行繪制,增加了整體主執行緒時間占用,當自定義 drawRect 視圖較多時,對整體的記憶體壓力也比較大,

ee734042e1b990463a3fdfa11b7d5b5c.png

準備階段

在 Prepare 階段還沒有解碼的影像將會在這一步進行解碼,也就是我們需要優化的常見的圖片主執行緒解碼操作,

對于每個被解碼的影像, App 可能會持續存在大量的記憶體分配,這種記憶體分配與輸入影像的大小成正比,而與 FrameBuffer 中實際渲染的影像視圖的大小沒有必然聯系,當 App 占用越來越多的記憶體時,作業系統將會開始壓縮物理記憶體(physical memory),整個程序都需要 CPU 的參與,所以除了我們自己的 App 對 CPU 的使用外,還可能會增加無法控制的全域 CPU 使用率,最終,我們的 App 可能會消耗更多的物理記憶體,以至于作業系統需要啟動終止行程,它將從低優先級的后臺行程開始,如果我們的 App 對記憶體的消耗了達到了特定數量,可能會被終止,這也就是為什么經常會因為大圖的原因產生 OOM,

若某個影像的顏色格式 GPU 無法直接使用,也會在這一步進行格式轉換,這就要求對該影像進行 copy 操作,而不是直接使用指標,這樣會耗時更長及占用更多的記憶體,

提交階段

在提交階段中,視圖樹將會被遞回打包并發送到 RenderServer 中,所以當視圖層級較為復雜時,這個程序耗費的時間也會更長一些,所以需要盡量減輕視圖層級結構,

  • RenderServer

RenderServer 負責將我們的圖層樹轉換為真正可顯示的影像,RenderServer 有兩個階段:Prepare 和 Execute ,在 Prepare 階段我們的圖層樹被編譯成一系列簡單的指令,供 GPU 執行,幀影片也在此處進行處理,在渲染執行階段 GPU 將 App 的圖層繪制成最終影像,

fd3e9bb8a1f764c5ded7fc9a98ee5616.png

下面來一個渲染實體,在下面這個實體中,圓形和長條周圍都有陰影,

7318b6f317a56cdb8678c3966484e3c3.png

Prepare

在準備階段, RenderServer 會廣度優先遍歷 App 的圖層樹,準備一個線性管線,這樣 GPU 就能按照順序執行命令進行繪制,從根圖層開始逐層遍歷,最終才有了 GPU 可以在下一個執行階段執行的整個管線,

14d525be16971ca02df066e02f698b77.png

Execute

執行階段主要是由 GPU 根據前面 prepare 階段準備好的圖層樹進行頂點著色、形狀裝配、幾何著色、光柵化、片段著色與圖層混合,一旦 GPU 執行完會將渲染好的影像放入幀快取區中等待下一個 VSYNC 的到來并交換到螢屏上進行顯示,

6342a1f5f60efff9ab3a042fab120c34.png

在該例中, GPU 的作業就是利用該管線將每一步都繪制成紋理并最終合成,最終在顯示階段會在螢屏上顯示該紋理,

從第一個藍色的圖層開始,它在指定的邊界內繪制顏色,然后深藍色被繪制在其邊界內,但是當前圓形和矩形中都有陰影,所以現在 GPU 必須先去繪制陰影,而陰影的形狀由還未繪制的兩層定義,所以需要先繪制圓形和矩形,為了避免這兩圖層被陰影遮擋,所以需要切換到不同的紋理先繪制陰影,對于這種情況我們稱之為“離屏渲染”,在這里需要額外開辟一塊記憶體用以繪制圓形和矩形,然后將該圖層變為黑色并且模糊來實作陰影的效果,

80e7d95b0a2d02441e428239a19a1c1a.png

然后 GPU 可以將陰影的離屏渲染紋理復制到最終的紋理中,陰影圖層就完成了,下一步是再次繪制圓形和矩形,可以注意到的是,這里不僅開辟了一塊額外的存盤空間用以渲染陰影,圓形和矩形也被渲染了兩次,對性能損害極大,

而最后的文本是在 CPU 上完成繪制的, GPU 會通過復制 CPU 繪制的文本影像來完成,完成上述流程后,幀已經準備好進行顯示了,

需要注意在這個程序中我們不得不用離屏渲染來渲染陰影,導致渲染需要更長的時間,

2149a758302945ec105c3ebeb6ad7153.png

離屏渲染

離屏渲染通道指的是 GPU 必須先在其它地方開辟一塊記憶體進行圖層渲染,然后再將其復制回來,就陰影而言,它必須繪制圖層,以確定最終形狀,

8b6ecec44da5249548eab918dab1d225.png

偶爾的離屏渲染對性能影響并不大,但離屏通道可能會積少成多,導致渲染出現卡頓,因此需要在 App 中監控并盡量避免,主要有四種主要型別的離屏通道可以優化:陰影、蒙版、圓角和毛玻璃,

Shadow:比如在實體中,如果不先繪制附加到圖形上面的陰影,GPU 就沒有足夠的資訊來繪制陰影,

6f9030677e0cd18df584d3db47ed8afe.png

Mask:當圖層或圖層樹需要被遮蔽時,GPU 需要渲染被遮蔽的子樹,它也需要避免覆寫被遮蔽形狀外的像素,因此它只會把最終需要顯示的像素復制回最終紋理,由于最終結果可能由多層渲染結果疊加,所以必須要利用額外的記憶體空間對中間的渲染結果進行快取,因此系統會默認來觸發離屏渲染,這種離屏渲染可能會導致渲染了許多用戶永遠不會看到的像素,

b560a99c7eb7fa1a9fcc550cf8da8b6e.png

CornerRadius:由于 GPU 繪制時會先從根節點開始繪制,所以如果根節點上設定了圓角,并且設定了 maskToBounds 裁剪屬性,那就會需要一個額外的離屏渲染 buffer 用以快取中間的裁剪結果,并最終將圓角內的像素復制回來,組透明度等屬性都可能會觸發離屏渲染,

54a2af8534af1fec6ce9cf168f4ba3de.png

iOS8 中開始支持 UIBlurEffectView 控制元件用以支持模糊化和鮮亮化,要應用這些效果,GPU 必須用離屏通道將內容復制到另一個紋理中,然后對其進行模糊、縮放疊加等操作并將最終結果復制回來,

1a35a6dc3fcff1799d2ce33227f64fd1.png

  • Display

Display 的程序實際上就是將幀快取區中的內容交換到顯示幕上進行最終顯示,這一程序我們參與不多,

? 總結

為了達到目標幀速率并且保持低輸入延遲,RenderLoop 的整個程序實際上是在每一幀中并行進行的,這樣管線就成了并行的,在系統渲染前一幀的同時 CPU 可以準備一個新幀,所以每幀的截止期都很重要,

6aadc433c2614898bc3526eb1afbdb98.png

卡頓型別

上面已經描述了 RenderLoop 的整個作業流程,實際上主要是在 App 和 RenderServer 中進行,所以總共有兩種主要型別的卡頓:提交卡頓(發生在 App 中),渲染卡頓(發生在 RenderServer 中),

d483eb97caf78f5f184a24f2328e53f4.png

? 提交卡頓

  • 概念

提交卡頓指的是 App 花費過長時間來處理或提交事件,

在提交中用了太長的時間而錯過了截止期,所以在下一個 VSYNC 中 RenderServer 沒有事情可以處理,必須等待下一個 VSYNC 到來后才能開始渲染,現在已經把幀傳送的時間推遲了一幀,以毫秒計時這將是 iPhone(60hz) 或 iPad 上的 16.67 毫秒,這個延遲時間就被稱為“卡頓時間(Hitch Time)”,如果提交作業花了更長的時間,比如通過了下一個 VSYNC 的起始時間,那么這一幀就晚了兩幀或者說是 33.34 毫秒,在這 33.34 毫秒中用戶都無法得到順暢的滾動,

b6bbc99577db1ec9a04381843f867057.png

  • 如何避免卡頓

保持視圖的輕量

  1. 為了保持視圖的輕量盡可能地利用CALayer 上 GPU 加速的可用屬性,如非必要需要避免使用 CPU 進行自定義繪制,

  2. 若非必要情況下不要重寫 drawRect 屬性,因為其會開辟額外的記憶體空間進行 CPU 繪制,并且在 CPU 上繪制會耗費更多的時間主執行緒,針對于文本、圖片等原本就在 CPU 上進行繪制的系統控制元件,我們可以嘗試使用其更底層執行緒安全的 CoreGraphics 能力,比如 TextKit、CoreText 等搭配多執行緒異步繪制減輕主執行緒壓力,

  3. 盡量復用視圖而不是頻繁的添加或移除視圖,

  4. 如果要把某一視圖從某一影片中移除,盡量使用 hidden 屬性,

  5. 對于 Prepare 階段,當我們的 UIImage 容器視圖的大小小于圖片本身時,我們通常可以使用 下采樣技術(downsampling) 來進行縮略圖的創建以節省部分記憶體空間,

避免復雜布局

  1. 減少代價過高且重復的布局,在需要更新布局時盡量只使用 setNeedsLayout,layoutIfNeeded 會消耗當前事務的生命周期也會造成卡頓,大多數時候你可以等到下一次 Runloop 執行時再更新你的布局,

  2. 嘗試使用最少的約束來完成布局,

  3. 視圖應該只能使自己或自己的子視圖無效,而不能使其同級視圖或父視圖無效,避免遞回布局,

  4. 避免非必要的視圖層級創建,復雜的視圖層級會增加提交階段的整體耗時

合理多執行緒能力

  1. 學會利用 GCD 的多執行緒能力,充分利用 CPU 多核優勢,提前在子執行緒進行布局等 UI 無關操作,避免主執行緒掛起(hang),

  2. 避免主執行緒 IO 等磁盤相關操作,

  3. 而針對于常見的主執行緒解碼操作,在 iOS15 之前,我們通常都是自己封裝或是利用最常見的第三方庫 SDWebImage 替我們在子執行緒進行解碼操作,而在 iOS15 中,Apple 終于提供了官方的解決方案以解決該問題:UIImage 的 prepareThumbnailOfSize:completionHandler: 等新介面,

  4. 針對于必須在 CPU 上進行繪制的組件,嘗試結合多執行緒使用異步繪制能力減輕主執行緒壓力,

? 渲染卡頓

  • 概念

渲染卡頓會在渲染服務器無法按時準備或者執行圖層樹時出現,這里顯然 Execute 的時長超過了 VSYNC 的界限,因此這一幀無法按時準備好,綠色的畫面比預期的晚了一幀于是有了 16 毫秒的卡頓

0551eeb62dd3b25c297e909e571c7141.png

  • 如何避免卡頓

準備階段我們影響較少,通常主要影響在于執行階段的離屏渲染,對于陰影來說,在設定陰影時,確保設定 shadowPath 以減少大量離屏通道,在圓化矩形時,使用 cornerRadius 和 cornerCurve 屬性避免用蒙版或角內容來構成圓角矩形,

498f1762ef4e21603e34199e7d741b13.png

優化整個 App 的 Mask,使用 masksToBounds 遮蔽為矩形圓角矩形或橢圓形的性能比自定義蒙版圖層好得多,重要的是用 Instruments 來對 App 進行分析并檢查圖層樹以獲得重要的技巧從而降低整體離屏計數,

330452cbb01c611d9fecb8f0a8e411e1.png

合理并謹慎的使用 shouldRasterize 屬性,它會對一塊圖層進行光柵化操作并進行快取,若針對于需要頻繁重繪的圖層使用該屬性反而對性能有著負面影響,

盡量使用非透明的圖層以盡量減少圖層混合,

檢測卡頓

當只著眼于一個卡頓或幾個卡頓時,卡頓時間是很有用的,但在像在滾動、影片或者是轉場等時長更長的事件時會變得很難處理,除非每次滾動或者影片用的都是完全相同的時間,這樣就會有相同的幀數,并且 iOS 設備并不總是更新螢屏,如果沒有事務發送到 RenderServer 上,新的一幀就不會被提交,通過測驗來比較卡頓時間就更難了,所以 Apple 提供了一種叫 “卡頓時間比(Hitch Time Ratio)” 的指標來衡量一段時間內的卡頓情況,

卡頓時間比就是一個區間內的總卡頓時間除以它的持續時間,因為它標準化為總時間,我們就能在不同的實踐中交叉比較,它是由每秒中的卡頓毫秒時間來測定的,所以代表著設備在每秒內出現卡頓的毫秒數,

a45e3ff045c6d7e6a248458c59451949.png

一個實體如下,在一臺 iPhone(60HZ) 上這是半秒的作業量,每一幀都在 VSYNC 到來前準備好了,所以用戶看不到卡頓,卡頓時間為 0,卡頓時間比也為 0,

214a0526e73b3a0c1c1b10918ba3c734.png

第二個例子如下,在該例中有時是在提交階段的卡頓,有時是在 RenderServer 中造成了卡頓,將卡頓時間加起來結果就是 100.02 ms 半秒,我們就得到了每秒 200.04 ms 的卡頓時間比,

aa46f80e50ff0eac71fb89254783642a.png

以下是蘋果建議的卡頓時間比目標,目標是 5 ms/s 以下的卡頓,是最不易被用戶察覺到的,5~10 ms/s 的卡頓用戶就會察覺到一些中斷,超過 10 ms/s 就會嚴重影響用戶體驗,

ee2401a9e4b79c0f825a27f12771a3e5.png

總結

本篇主要討論了 RenderLoop 以及新的一幀展現給用戶的整個流程,并且著眼于什么是卡頓,以及它的兩種型別:提交卡頓以及渲染卡頓,并最終定義了卡頓時間比用以測量當前 App 的卡頓程度和性能,相信大家對整個渲染回圈和卡頓型別有了更清晰的認識,在日常編碼中也可以盡量避免這些問題,

本篇主要介紹了一些原理相關的概念,那么具體的卡頓應該如何測量?下一篇將會通過實踐結合 Instrument 的 AnimationHitches 能力分析 DXSDK 作為卡片層面在日常資訊流的使用程序中在性能方面存在的一些問題,以及 DXSDK 上半年做的一些性能優化改進,

參考資料

WWDC 2020,2021

? 拓展閱讀

fea4b344aaa1ccc6ad1fa16e21ab6d7e.png

fbafa26d905c135491a51005eb551374.png

作者|嵐遙

編輯|橙子君

出品|阿里巴巴新零售淘系技術

5cfd9af119014c1ee546955ca15c3f3d.png

b0d12d3c311f7866c76479801a79bccc.png

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/340457.html

標籤:其他

上一篇:Android坑點-ByteBuffer.array() 入過坑嗎

下一篇:Android 優雅的呼叫權限申請

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more