佈局渲染筆記

来源:https://www.cnblogs.com/LiuZhen/archive/2019/05/19/10890472.html
-Advertisement-
Play Games

CPU 處理邏輯計算和記憶體管理,顯示操作。 GPU CPU無法顯示覆雜的圖形,GPU用於顯示覆雜圖形,分擔CPU的任務 xml佈局到屏幕的顯示流程:xml 通過 LayoutInflater 載入到記憶體中,然後經過CPU計算處理為多維圖形,在通過 OpenGL 調用GPU,GPU對圖形進行柵格化顯示 ...


CPU  處理邏輯計算和記憶體管理,顯示操作。

GPU  CPU無法顯示覆雜的圖形,GPU用於顯示覆雜圖形,分擔CPU的任務

xml佈局到屏幕的顯示流程:xml 通過 LayoutInflater 載入到記憶體中,然後經過CPU計算處理為多維圖形,在通過 OpenGL 調用GPU,GPU對圖形進行柵格化顯示到屏幕上,此時如果上面流程在16毫秒內完成,則直接顯示到顯示器,如果沒能完成,則垂直同步等待下一幀完成。

由於人類的眼睛看到畫面之幀率高於每秒約10-12幀的時候,就會認為是連貫的;

對於有聲電影的拍攝和播放幀率均為每秒24幀,對人是可以接受的,但是早期的高動態電子游戲幀率如果少於每秒30幀的話就會不連貫,因為沒有動態模糊使流暢度降低,在於手機交互的過程中,如果觸摸反饋60幀以下人是可以感覺出來的,60幀以上不能察覺變化,當手機上幀率低於60fps的時候會感覺畫面的卡頓和遲滯現象;

Android系統每隔16ms發出信號,觸發對UI進行渲染,如果每次渲染都成功,就能達到流程的畫面所需要的60fps,為了能夠實現60fps,這意味著計算渲染的太多數操作都必須在16ms內完成。

當一幀畫面渲染時間超過16ms的時候,垂直同步機制(每隔16ms刷新幀率)會讓顯示器硬體等待GPU完成柵格化渲染操作,這樣會讓一幀畫面多停留16ms甚至更多,這樣就造成了用戶看起來畫面停頓。

優化:

  CPU 減少xml轉換成對象的時間,比如減少層級

  GPU 減少重覆繪製

GPU的繪製過程根據CPU傳遞的指令來繪製,16ms繪製一次,指令來了就繪製,哪怕是同樣的繪製指令,如果層次太深,用戶看不到的區域也會被繪製,以及自定義控制項中,onDraw方法做了過多的繪製。

Android手機開發者選項中,打開GPU過度繪製調試,藍色 表示繪製了一次,淡綠色表示兩次,淡紅色表示三次,深紅色表示四次。

註意:Android的Theme-主題中,是自帶背景的,可以設置windowBackground為null

 下麵是一個過度繪製的離職,註釋部分為過度繪製,打開部分為優化後的繪製,打開GPU調試後運行查看過度繪製區域,作比較

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

import androidx.annotation.Nullable;

public class DroidCardsView extends View {

    private int mCardSpacing = 150;//圖片間隔
    private int mCardLeft = 50;//圖片左側距離
    private List<DroidCard> mDroidCards = new ArrayList<>();
    private Paint paint = new Paint();

    public DroidCardsView(Context context) {
        super(context);
        initCards();
    }

    public DroidCardsView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initCards();
    }

    private void initCards(){
        Resources res = getResources();
        mDroidCards.add(new DroidCard(res,R.mipmap.testpic1,mCardLeft));
        mCardLeft += mCardSpacing;
        mDroidCards.add(new DroidCard(res,R.mipmap.testpic2,mCardLeft));
        mCardLeft += mCardSpacing;
        mDroidCards.add(new DroidCard(res,R.mipmap.testpic1,mCardLeft));
        mCardLeft += mCardSpacing;
        mDroidCards.add(new DroidCard(res,R.mipmap.testpic2,mCardLeft));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//        for (DroidCard card : mDroidCards) {
//            drawDroidCard(canvas,card);
//        }
//        invalidate();

        for (int i = 0;i < mDroidCards.size() -1;i++) {//最後一張不裁剪
            drawDroidCard(canvas,mDroidCards,i);
        }
        drawLeftDroidCard(canvas,mDroidCards.get(mDroidCards.size() -1));
        invalidate();
    }

    private void drawDroidCard(Canvas canvas,DroidCard card){
        canvas.drawBitmap(card.bitmap,card.left,0f,paint);
    }

    private void drawLeftDroidCard(Canvas canvas,DroidCard card){
        canvas.drawBitmap(card.bitmap,card.left,0f,paint);
    }

    private void drawDroidCard(Canvas canvas,List<DroidCard> list,int i){
        DroidCard card = list.get(i);
        /*Canvas中當前路徑不屬於保存狀態,狀態包含線條,平移,顏色,漸變,陰影等*/
        canvas.save();//保存畫布狀態,第二次繪製在起點,因為這裡每一個的x坐標是以左側為起點累加的
        //獲取當前圖片的 left 值,裁剪出當前圖片顯示的區域,並且繪製
        canvas.clipRect(card.left,0f,list.get(i+1).left,card.height);
        canvas.drawBitmap(card.bitmap,card.left,0f,paint);
        canvas.restore();
    }

}

 

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class DroidCard {

    public Bitmap bitmap;
    public int left,width,height;


    public DroidCard(Resources resources,int resId,int left){
        this.bitmap = BitmapFactory.decodeResource(resources,resId);
        this.left = left;
        this.width = bitmap.getWidth();
        this.height = bitmap.getHeight();
    }

}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.example.testdemo.DroidCardsView
        android:layout_width="match_parent"
        android:layout_height="150dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</RelativeLayout>

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 日常開發中經常用到一個酒店下有多個標簽比如酒店的風格特點有: `場地方正 豪華 美食 自然採光 園林草坪 溫泉 景區周邊 水景 泳池 中式院落 西式裝修 少數民族 會場進車 高爾夫` 我們一般都會對其進行編號: 存放在資料庫時主要是存放該值的key值,如果一個酒店只有一個標簽是沒什麼問題的,但是如果 ...
  • 使用CTE,ROW_NUMBER,PARTITION BY來處理數據表重覆記錄。 先準備下麵的數據: IF OBJECT_ID('tempdb.dbo.#Part') IS NOT NULL DROP TABLE #Part CREATE TABLE #Part ( [ID] INT, [Item] ...
  • 如標題一樣,檢索每個組的最後一條記錄。 舉例說明,先準備一些數據: 要求是以[Category]來分組, 檢查以[Qty]數據最大的記錄。 CTE查詢分組表: SELECT數據: 只要我拿到row number為1的記錄即可,因為在CTE處理時,已經做好按[Category]來分組併排序。 ...
  • 高級查詢 分組查詢 查看EMPLOYEE表中,員工在同一部門做相同工作且總工資大於5000,平均工資小於1500的薪水情況和人數? 分組查詢註意事項: 如果在查詢結果中的某些欄位上沒有使用分組函數,那麼這些欄位就必須出現在group by子句中。這是一個分組查詢的強制性規則。 非等值連接 簡單地來說 ...
  • SELECT 表名 = Case When A.colorder=1 Then D.name Else '' End, 表說明 = Case When A.colorder=1 Then isnull(F.value,'') Else '' End, 欄位序號 = A.colorder, 欄位名 = ...
  • 我們經常說,看一個事兒千萬不要直接陷入細節里,你應該先鳥瞰其全貌,這樣能夠幫助你從高維度理解問題。同樣,對於MySQL的學習也是這樣。平時我們使用資料庫,看到的通常都是一個整體。比如,你有個最簡單的表,表裡只有一個ID欄位,在執行下麵這個查詢語句時: 我們看到的只是輸入一條語句,返回一個結果,卻不知 ...
  • 最近做了一個Excel的多級聯動的功能,具體是將全國所有的氣象局按一二三四級單位做成四列,實現各級的聯動下拉選擇,這和省市縣鄉的各級聯動的功能基本一樣,下麵記錄下具體的操作步驟。 1、首先需要從資料庫中將所有單位按照Id ,父級ID ,單位名稱,導出excel, 2、將所有單位中的一級單位單獨取出作 ...
  • 寫一個符合自己要求使用透視存儲過程。在開發時,直接使用即可。 SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- -- Author: Insus.NET -- Create date: 2019-05-19 -- Update date: 201 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...