เพิ่มประสิทธิภาพความเร็วของบิวด์

เวลาสร้างนานๆ จะทำให้ขั้นตอนการพัฒนาช้าลง หน้านี้นำเสนอเทคนิคบางอย่างที่สามารถช่วยคุณได้ แก้ปัญหาคอขวดของความเร็วบิลด์

ขั้นตอนทั่วไปในการปรับปรุงความเร็วในการสร้างแอปมีดังนี้

  1. เพิ่มประสิทธิภาพการกำหนดค่าบิลด์โดยใช้หัวข้อ ขั้นตอนที่ส่งผลดีต่อโปรเจ็กต์ส่วนใหญ่ของ Android Studio ได้ทันที
  2. ทำโปรไฟล์บิลด์เพื่อระบุและวินิจฉัยบิลด์ บริเวณคอขวดที่มีความซับซ้อนมากขึ้น ซึ่งอาจเฉพาะกับโครงการหรือเวิร์กสเตชันของคุณ

เมื่อพัฒนาแอป ให้ทำให้ใช้งานได้ในอุปกรณ์ที่ใช้ Android 7.0 (API ระดับ 24) ขึ้นไปหากเป็นไปได้ เวอร์ชันใหม่ของ แพลตฟอร์ม Android ใช้กลไกที่ดียิ่งขึ้นสำหรับการอัปเดตแอปของคุณ เช่น Android Runtime (ART) และการรองรับในตัวสำหรับไฟล์ DEX หลายไฟล์

หมายเหตุ: หลังจากสร้างเสร็จครั้งแรกแล้ว คุณอาจสังเกตเห็นว่า ทั้งในส่วนที่สะอาดตาและที่เพิ่มขึ้น สามารถทำงานได้เร็วขึ้นมากแม้ไม่ได้ใช้ การเพิ่มประสิทธิภาพที่อธิบายในหน้านี้ นั่นเป็นเพราะดีมอน Gradle มี "การอุ่นเครื่อง" ระยะเวลาการเพิ่มประสิทธิภาพ คล้ายกับ JVM อื่น กระบวนการ

เพิ่มประสิทธิภาพการกำหนดค่าบิลด์

ทำตามเคล็ดลับเหล่านี้เพื่อปรับปรุงบิลด์ ของโปรเจ็กต์ Android Studio

อัปเดตเครื่องมือให้เป็นปัจจุบันอยู่เสมอ

เครื่องมือ Android ได้รับการเพิ่มประสิทธิภาพบิลด์และฟีเจอร์ใหม่ๆ ด้วย อัปเดตทุกครั้ง เคล็ดลับในหน้านี้จะถือว่าคุณกําลังใช้เวอร์ชันล่าสุด เวอร์ชัน โปรดติดตามผลเพื่อใช้ประโยชน์จากการเพิ่มประสิทธิภาพล่าสุด ถึงปัจจุบัน:

ใช้ KSP แทน kapt

เครื่องมือประมวลผลคำอธิบายประกอบของ Kotlin (kapt) ทำงานได้ช้ากว่า Kotlin มาก ตัวประมวลผลสัญลักษณ์ (KSP) หากคุณเขียนซอร์สโค้ด Kotlin ที่มีคำอธิบายประกอบและใช้เครื่องมือนั้น ประมวลผลคำอธิบายประกอบ (เช่น ห้อง) ที่รองรับ KSP คุณควรย้ายข้อมูลไปยัง KSP

หลีกเลี่ยงการรวบรวมทรัพยากรที่ไม่จำเป็น

หลีกเลี่ยงการคอมไพล์และแพ็กเกจทรัพยากรที่ไม่ได้ทดสอบ เช่น การแปลภาษาเพิ่มเติมและแหล่งข้อมูลความหนาแน่นของหน้าจอ แต่ให้ระบุเพียงรายการเดียวแทน ทรัพยากรภาษาและความหนาแน่นของหน้าจอสำหรับ "เวอร์ชันที่กำลังพัฒนา" รสชาติ [flavor] ดังที่ปรากฏในตัวอย่างต่อไปนี้

ดึงดูด

android {
    ...
    productFlavors {
        dev {
            ...
            // The following configuration limits the "dev" flavor to using
            // English stringresources and xxhdpi screen-density resources.
            resourceConfigurations "en", "xxhdpi"
        }
        ...
    }
}

Kotlin

android {
    ...
    productFlavors {
        create("dev") {
            ...
            // The following configuration limits the "dev" flavor to using
            // English stringresources and xxhdpi screen-density resources.
            resourceConfigurations("en", "xxhdpi")
        }
        ...
    }
}

ทดลองใช้พอร์ทัลปลั๊กอิน Gradle เป็นครั้งสุดท้าย

ใน Android ปลั๊กอินทั้งหมดจะอยู่ใน google() และ ที่เก็บ mavenCentral() รายการ อย่างไรก็ตาม บิลด์ของคุณอาจ ซึ่งจำเป็นต้องใช้ปลั๊กอินของบุคคลที่สามที่ได้รับการแก้ไขโดยใช้ gradlePluginPortal() service.

Gradle ค้นหาที่เก็บตามลำดับที่มีการประกาศ ดังนั้นประสิทธิภาพของบิลด์จะได้รับการปรับปรุงหากที่เก็บที่ระบุไว้มี ของปลั๊กอินส่วนใหญ่ ดังนั้น ให้ลองใช้ gradlePluginPortal() รายการโดยวางรายการล่าสุดในบล็อกที่เก็บใน settings.gradle ของคุณ ในกรณีส่วนใหญ่ วิธีนี้จะช่วยลดจำนวนการค้นหาปลั๊กอินที่ซ้ำซ้อนและ จะช่วยเพิ่มความเร็วในการสร้าง

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่ Gradle ไปยังส่วนต่างๆ ของที่เก็บหลายแหล่ง โปรดดู การประกาศที่เก็บหลายรายการ ในเอกสารประกอบของ Gradle

ใช้ค่าการกำหนดค่าบิลด์แบบคงที่กับบิลด์การแก้ไขข้อบกพร่อง

ใช้ค่าคงที่เสมอสำหรับพร็อพเพอร์ตี้ที่อยู่ในไฟล์ Manifest หรือไฟล์ทรัพยากรสำหรับ ประเภทบิลด์การแก้ไขข้อบกพร่อง

การใช้รหัสเวอร์ชันแบบไดนามิก ชื่อเวอร์ชัน ทรัพยากร หรือ ตรรกะบิลด์อื่นๆ ที่เปลี่ยนแปลงไฟล์ Manifest จำเป็นต้องมีบิลด์ของแอป ทุกครั้งที่คุณต้องการทำการเปลี่ยนแปลง แม้ว่าการเปลี่ยนแปลงจริงๆ อาจ มิฉะนั้นจะใช้เพียงการสลับด่วนเท่านั้น หากการกำหนดค่าบิลด์ของคุณจำเป็นต้องใช้ แบบไดนามิก จากนั้นแยกพร็อพเพอร์ตี้เหล่านั้นไปยังตัวแปรบิลด์รุ่นและเก็บ ค่าคงที่สำหรับบิลด์การแก้ไขข้อบกพร่องดังที่แสดงในตัวอย่างต่อไปนี้

  ...
  // Use a filter to apply onVariants() to a subset of the variants.
  onVariants(selector().withBuildType("release")) { variant ->
      // Because an app module can have multiple outputs when using multi-APK, versionCode
      // is only available on the variant output.
      // Gather the output when we are in single mode and there is no multi-APK.
      val mainOutput = variant.outputs.single { it.outputType == OutputType.SINGLE }

      // Create the version code generating task.
      val versionCodeTask = project.tasks.register("computeVersionCodeFor${variant.name}", VersionCodeTask::class.java) {
          it.outputFile.set(project.layout.buildDirectory.file("versionCode${variant.name}.txt"))
      }

      // Wire the version code from the task output.
      // map will create a lazy Provider that:
      // 1. Runs just before the consumer(s), ensuring that the producer (VersionCodeTask) has run
      //    and therefore the file is created.
      // 2. Contains task dependency information so that the consumer(s) run after the producer.
      mainOutput.versionCode.set(versionCodeTask.flatMap { it.outputFile.map { it.asFile.readText().toInt() } })
  }
  ...

  abstract class VersionCodeTask : DefaultTask() {

    @get:OutputFile
    abstract val outputFile: RegularFileProperty

    @TaskAction
    fun action() {
        outputFile.get().asFile.writeText("1.1.1")
    }
  }

ดูสูตร setVersionsFromTask บน GitHub เพื่อดูวิธีตั้งค่า รหัสเวอร์ชันแบบไดนามิกในโปรเจ็กต์ของคุณ

ใช้เวอร์ชันที่ขึ้นต่อกันแบบคงที่

เมื่อคุณประกาศทรัพยากร Dependency ในไฟล์ build.gradle ให้หลีกเลี่ยงการใช้เวอร์ชันแบบไดนามิก ตัวเลข (ที่มีเครื่องหมายบวกต่อท้าย เช่น 'com.android.tools.build:gradle:2.+') การใช้หมายเลขเวอร์ชันแบบไดนามิกอาจทำให้เกิดการอัปเดตเวอร์ชันที่ไม่คาดคิด ทำให้แปลงเวอร์ชันได้ยาก และบิลด์ที่ช้ากว่าซึ่งเกิดจากการที่ Gradle ตรวจหาอัปเดต โปรดใช้หมายเลขเวอร์ชันแบบคงที่แทน

สร้างโมดูลไลบรารี

มองหาโค้ดในแอปที่สามารถแปลงเป็นโมดูลไลบรารี Android ได้ การทำให้โค้ดเป็นโมดูลย่อยด้วยวิธีนี้ทำให้ระบบบิลด์สามารถคอมไพล์เฉพาะ โมดูลที่คุณแก้ไขและแคชเอาต์พุตเหล่านั้นสำหรับบิลด์ในอนาคต การแยกส่วนยังช่วยให้ การดำเนินการโครงการพร้อมกันจะมีประสิทธิภาพมากขึ้นเมื่อคุณ ให้เปิดใช้การเพิ่มประสิทธิภาพนั้น

สร้างงานสำหรับตรรกะบิลด์ที่กำหนดเอง

หลังจากที่คุณสร้างโปรไฟล์บิลด์ หากบิลด์ โปรไฟล์แสดงว่าใช้เวลาสร้างค่อนข้างนานใน **การกำหนดค่า ระยะของโครงการ** ให้ตรวจสอบสคริปต์ build.gradle ของคุณและมองหา ที่จะรวมไว้ในงาน Gradle ที่กำหนดเอง โดยการย้ายตรรกะบิลด์บางส่วน เป็นงาน คุณจึงช่วยให้มั่นใจว่างานจะทำงานเมื่อจำเป็นต้องใช้เท่านั้น และสามารถแคชผลลัพธ์ได้ บิลด์ที่ตามมา และตรรกะของบิลด์นั้นจะมีสิทธิ์ทำงานพร้อมกันหากคุณเปิดใช้การดำเนินการโปรเจ็กต์พร้อมกัน ดูข้อมูลเพิ่มเติมเกี่ยวกับ tak สำหรับบิลด์ที่กำหนดเอง ให้อ่านเอกสาร Gradle อย่างเป็นทางการ

เคล็ดลับ: หากบิลด์มีงานที่กำหนดเองจำนวนมาก คุณอาจ ต้องการจัดระเบียบไฟล์ build.gradle โดยสร้างคลาสงานที่กำหนดเอง เพิ่มชั้นเรียนของคุณลงใน project-root/buildSrc/src/main/groovy/ ไดเรกทอรี; Gradle รวมชั้นเรียนเหล่านั้นไว้ในคลาสพาธสำหรับทุกคนโดยอัตโนมัติ build.gradle ไฟล์ในโปรเจ็กต์

แปลงรูปภาพเป็น WebP

WebP คือไฟล์ภาพ ที่มีการบีบอัดแบบสูญเสียบางส่วน (เช่น JPEG) และมีความโปร่งใส (เช่น PNG) WebP สามารถบีบอัดได้ดีกว่า JPEG หรือ PNG

การลดขนาดไฟล์รูปภาพโดยไม่ต้องบีบอัดเวลาบิลด์ สามารถเร่งงานสร้างของคุณได้ โดยเฉพาะอย่างยิ่งหากแอปของคุณใช้อิมเมจจำนวนมาก ที่ไม่ซับซ้อน แต่คุณอาจเห็นว่าการใช้งาน CPU ของอุปกรณ์เพิ่มขึ้นเล็กน้อยในขณะที่ การขยายรูปภาพ WebP ใช้ Android Studio ได้ง่ายๆ แปลงรูปภาพ กับ WebP

ปิดใช้การคลิปไฟล์ PNG

หากไม่แปลง PNG ไปยัง WebP ได้ คุณยังเร่งสร้างให้เร็วขึ้นได้โดยปิดใช้ การบีบอัดรูปภาพทุกครั้งที่คุณสร้างแอป

หากใช้ปลั๊กอิน Android Gradle 3.0.0 หรือสูงกว่า ตามค่าเริ่มต้น ระบบจะปิดใช้งานการครอบตัด PNG สำหรับ "การแก้ไขข้อบกพร่อง" ประเภทบิลด์ หากต้องการปิดใช้ การเพิ่มประสิทธิภาพสำหรับบิลด์ประเภทอื่นๆ ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ build.gradle

ดึงดูด

android {
    buildTypes {
        release {
            // Disables PNG crunching for the "release" build type.
            crunchPngs false
        }
    }
}

Kotlin

android {
    buildTypes {
        getByName("release") {
            // Disables PNG crunching for the "release" build type.
            isCrunchPngs = false
        }
    }
}

เนื่องจากประเภทบิลด์หรือรสชาติของผลิตภัณฑ์ไม่ได้กำหนดพร็อพเพอร์ตี้นี้ คุณจึงต้อง เพื่อตั้งค่าพร็อพเพอร์ตี้นี้เป็น true ด้วยตนเองเมื่อสร้างรุ่น เวอร์ชันแอปของคุณ

ทดลองใช้เครื่องมือเก็บขยะแบบขนาน JVM

ปรับปรุงประสิทธิภาพของบิลด์ได้ด้วยการกำหนดค่าเครื่องมือรวบรวมขยะ JVM ที่เหมาะสมที่สุดที่ Gradle นำมาใช้ แม้ว่า JDK 8 จะกำหนดค่าให้ใช้เครื่องมือเก็บข้อมูลขยะแบบขนานโดยค่าเริ่มต้น แต่ JDK 9 ขึ้นไป มีการกำหนดค่าให้ใช้ เครื่องมือเก็บขยะ G1

เราขอแนะนำเพื่อเพิ่มโอกาสในการปรับปรุงประสิทธิภาพของบิลด์ การทดสอบบิลด์ Gradle ของคุณกับโหมดคู่ขนาน เครื่องมือเก็บขยะ ใน gradle.properties ให้ตั้งค่าต่อไปนี้

org.gradle.jvmargs=-XX:+UseParallelGC

หากมีตัวเลือกอื่นๆ ที่ตั้งค่าไว้แล้วในช่องนี้ ให้เพิ่มตัวเลือกใหม่ดังนี้

org.gradle.jvmargs=-Xmx1536m -XX:+UseParallelGC

หากต้องการวัดความเร็วของบิลด์ด้วยการกำหนดค่าต่างๆ โปรดดู ทำโปรไฟล์บิลด์

เพิ่มขนาดฮีป JVM

ถ้าคุณสังเกตเห็นงานสร้างที่ช้า และโดยเฉพาะอย่างยิ่ง ที่เก็บข้อมูลขยะใช้เวลามากกว่า 15% ของ ใน เครื่องมือวิเคราะห์บิลด์ คุณควรเพิ่มขนาดฮีปของ Java Virtual Machine (JVM) ในไฟล์ gradle.properties ให้กำหนดขีดจำกัดเป็น 4, 6 หรือ 8 กิกะไบต์ ดังที่ปรากฏในตัวอย่างต่อไปนี้

org.gradle.jvmargs=-Xmx6g

จากนั้นทดสอบเพื่อเพิ่มความเร็วของบิลด์ วิธีที่ง่ายที่สุดในการระบุฮีปที่เหมาะสมที่สุด ขนาดคือเพิ่มขีดจำกัดขึ้นเล็กน้อย แล้วทดสอบว่าบิลด์เพียงพอ เร็วขึ้น

หากคุณใช้ เครื่องมือเก็บขยะแบบขนาน JVM บรรทัดทั้งบรรทัดควรมีลักษณะดังนี้

org.gradle.jvmargs=-Xmx6g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g

คุณสามารถวิเคราะห์ข้อผิดพลาดด้านหน่วยความจํา JVM ได้โดยการบิด HeapDumpOnOutOfMemoryError แจ้งว่าไม่เหมาะสม การทำเช่นนี้จะทำให้ JVM สร้างฮีปดัมป์เมื่อหน่วยความจำเต็ม

ใช้คลาส R ที่ไม่ใช่แบบสําเนา

ใช้ R คลาสแบบไม่สับเปลี่ยนเพื่อให้สร้างบิลด์ได้เร็วขึ้น สำหรับแอปที่มีหลายโมดูล เพราะจะช่วยป้องกันการสร้างทรัพยากรซ้ำโดยตรวจสอบว่า คลาส R ของแต่ละโมดูลมีเฉพาะการอ้างอิงไปยังทรัพยากรของตนเองโดยไม่ได้ดึงข้อมูลการอ้างอิงจาก ทรัพยากร Dependency โดยตรง ซึ่งจะทำให้สร้างบิลด์ได้เร็วขึ้นและได้ประโยชน์ที่สอดคล้องกันจากการคอมไพล์ เพื่อหลีกเลี่ยง ซึ่งเป็นลักษณะการทำงานเริ่มต้นในปลั๊กอิน Android Gradle เวอร์ชัน 8.0.0 ขึ้นไป

ตั้งแต่ Android Studio Bumblebee เป็นต้นไป ระบบจะเปิดใช้ชั้นเรียน R แบบไม่เปลี่ยนชั่วคราวสำหรับโปรเจ็กต์ใหม่โดยค่าเริ่มต้น สำหรับโปรเจ็กต์ที่สร้างด้วย Android Studio เวอร์ชันก่อนหน้า ให้อัปเดตโปรเจ็กต์เหล่านั้นไปใช้แบบไม่ใช่แบบสัญจร R ชั้นเรียนโดยไปที่เปลี่ยนโครงสร้างภายในโค้ด > ย้ายข้อมูลไปยังคลาส R แบบไม่เปลี่ยนผ่าน

โปรดดูข้อมูลเพิ่มเติมเกี่ยวกับแหล่งข้อมูลของแอปและชั้นเรียน R ที่ ภาพรวมแหล่งข้อมูลของแอป

ใช้คลาส R ที่ไม่คงที่

ใช้คลาส R ที่ไม่คงที่ ในแอปและการทดสอบเพื่อปรับปรุงการคอมไพล์ Java และช่วยให้ลดขนาดทรัพยากรได้แม่นยำยิ่งขึ้น ช่องของชั้นเรียน R ช่อง สำหรับไลบรารีต่างๆ เสมอ เนื่องจากทรัพยากรมีตัวเลข เมื่อทำแพ็กเกจ APK สำหรับแอปหรือการทดสอบที่ต้องใช้ไลบรารีนั้น ซึ่งเป็นลักษณะการทำงานเริ่มต้นในปลั๊กอิน Android Gradle 8.0.0 ขึ้นไป

ปิดใช้ Flag Jetifier

เนื่องจากโปรเจ็กต์ส่วนใหญ่ใช้ไลบรารี AndroidX โดยตรง คุณจึงนำโค้ด Flag Jetifier เพื่อประสิทธิภาพในการสร้างที่ดียิ่งขึ้น วิธีนำออก ธง Jetifier ตั้งค่า android.enableJetifier=false ใน gradle.properties

ตัววิเคราะห์บิลด์สามารถทำการตรวจสอบเพื่อดูว่าแฟล็กสามารถ ถูกนำออกอย่างปลอดภัยเพื่อให้โปรเจ็กต์มีประสิทธิภาพในการสร้างที่ดีขึ้นและย้ายข้อมูลออกจาก ไลบรารีการสนับสนุน Android ที่ไม่มีการบำรุงรักษา หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับเครื่องมือวิเคราะห์บิลด์ โปรดดู แก้ปัญหาประสิทธิภาพของบิลด์

ใช้แคชการกำหนดค่า

แคชการกำหนดค่า ช่วยให้ Gradle บันทึกข้อมูลเกี่ยวกับกราฟงานของบิลด์และนำกลับมาใช้ซ้ำในบิลด์ต่อๆ มาได้ Gradle ไม่จำเป็นต้องกำหนดค่าบิลด์ทั้งหมดอีกครั้ง

หากต้องการเปิดใช้งานแคชการกำหนดค่า ให้ทำตามขั้นตอนต่อไปนี้

  1. ตรวจสอบว่าปลั๊กอินโปรเจ็กต์ทั้งหมดใช้งานร่วมกันได้

    ใช้เมนู สร้างเครื่องมือวิเคราะห์เพื่อตรวจสอบว่า โปรเจ็กต์เข้ากันได้กับแคชการกำหนดค่า ตัววิเคราะห์บิลด์จะเรียกใช้ลำดับการทดสอบ เพื่อระบุว่าสามารถเปิดฟีเจอร์นี้สำหรับโปรเจ็กต์ได้หรือไม่ โปรดดู ปัญหา #13490 สำหรับ รายการปลั๊กอินที่สนับสนุน

  2. เพิ่มโค้ดต่อไปนี้ลงในไฟล์ gradle.properties

      org.gradle.configuration-cache=true
      # Use this flag carefully, in case some of the plugins are not fully compatible.
      org.gradle.configuration-cache.problems=warn

เมื่อเปิดใช้แคชการกำหนดค่า ครั้งแรกที่คุณเรียกใช้โปรเจ็กต์ เอาต์พุตของบิลด์ พูดว่า Calculating task graph as no configuration cache is available for tasks ระหว่าง การเรียกใช้ครั้งต่อๆ ไป เอาต์พุตของบิลด์จะระบุว่า Reusing configuration cache

หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับแคชการกำหนดค่า โปรดดูบล็อกโพสต์ เจาะลึกการแคชการกำหนดค่า และ ในเอกสารของ Gradle เกี่ยวกับ แคชการกำหนดค่า

พบปัญหาเกี่ยวกับแคชการกำหนดค่าใน Gradle 8.1 และปลั๊กอิน Android Gradle 8.1

แคชการกำหนดค่ามีความเสถียรใน Gradle 8.1 และได้แนะนำ File API ด้วย เครื่องมือวัด Conversion การโทร เช่น File.exists(), File.isDirectory() และ File.list() จะบันทึกโดย Gradle ติดตามไฟล์อินพุตการกำหนดค่า

ปลั๊กอิน Android Gradle (AGP) 8.1 ใช้ API ของ File เหล่านี้สำหรับบางไฟล์ที่ Gradle ควร ไม่ถือว่าเป็นอินพุตของแคช การดำเนินการนี้จะทริกเกอร์การทำให้แคชใช้งานไม่ได้เพิ่มเติมเมื่อใช้กับ Gradle 8.1 ขึ้นไปจะทำให้ประสิทธิภาพบิลด์ช้าลง ข้อมูลต่อไปนี้ถือเป็นอินพุตแคชใน AGP 8.1

อินพุต เครื่องมือติดตามปัญหา แก้ไขแล้วใน
$GRADLE_USER_HOME/android/FakeDependency.jar ปัญหา #289232054 AGP 8.2
เอาต์พุต cmake ปัญหา #287676077 AGP 8.2
$GRADLE_USER_HOME/.android/analytics.settings ปัญหา #278767328 AGP 8.3

หากคุณใช้ API เหล่านี้หรือปลั๊กอินที่ใช้ API เหล่านี้ คุณอาจพบปัญหาการถดถอยในเวลาบิลด์ เนื่องจากตรรกะบิลด์บางรายการที่ใช้ API เหล่านี้ อาจทริกเกอร์การทำให้แคชใช้งานไม่ได้เพิ่มเติม โปรดดู การปรับปรุงการติดตามอินพุตการกําหนดค่าบิลด์ เพื่อพูดคุยเกี่ยวกับรูปแบบเหล่านี้และวิธีแก้ไขตรรกะของบิลด์ หรือปิดใช้ชั่วคราว การติดตาม API ของไฟล์