ปรับปรุงการตรวจสอบโค้ดด้วยหมายเหตุ

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

คำอธิบายประกอบช่วยให้คุณระบุคำแนะนำแก่เครื่องมือตรวจสอบโค้ด เช่น Lint เพื่อช่วยตรวจหาปัญหาโค้ดที่ละเอียดอ่อนมากขึ้นเหล่านี้ได้ ระบบจะเพิ่มคำอธิบายประกอบเป็นแท็กข้อมูลเมตาที่คุณแนบกับตัวแปร พารามิเตอร์ และค่าที่แสดงผลเพื่อตรวจสอบค่าที่แสดงผลของเมธอด พารามิเตอร์ที่ส่ง ตัวแปรในเครื่อง และฟิลด์ เมื่อใช้ร่วมกับเครื่องมือตรวจสอบโค้ด คำอธิบายประกอบจะช่วยให้คุณตรวจพบปัญหาต่างๆ เช่น null pointer exception และความขัดแย้งของประเภททรัพยากร

Android รองรับคำอธิบายประกอบที่หลากหลายผ่านไลบรารีคำอธิบายประกอบ Jetpack คุณเข้าถึงไลบรารีได้ผ่านแพ็กเกจ androidx.annotation

หมายเหตุ: หากโมดูลมีทรัพยากร Dependency ในโปรเซสเซอร์สำหรับคำอธิบายประกอบ คุณต้องใช้การกำหนดค่าทรัพยากร Dependency kapt หรือ ksp สำหรับ Kotlin หรือการกำหนดค่าทรัพยากร Dependency annotationProcessor สำหรับ Java เพื่อเพิ่มทรัพยากร Dependency นั้น

เพิ่มคำอธิบายประกอบลงในโปรเจ็กต์

หากต้องการเปิดใช้คำอธิบายประกอบในโปรเจ็กต์ ให้เพิ่มทรัพยากร Dependency androidx.annotation:annotation ลงในไลบรารีหรือแอป ระบบจะตรวจสอบคำอธิบายประกอบที่คุณเพิ่มเมื่อเรียกใช้การตรวจสอบโค้ดหรืองาน lint

เพิ่มทรัพยากร Dependency ของไลบรารี Jetpack Annotations

ไลบรารีคำอธิบายประกอบ Jetpack เผยแพร่อยู่ในที่เก็บ Maven ของ Google หากต้องการเพิ่มไลบรารี Jetpack Annotations ลงในโปรเจ็กต์ ให้ใส่บรรทัดต่อไปนี้ในบล็อก dependencies ของไฟล์ build.gradle หรือ build.gradle.kts

Kotlin

dependencies {
    implementation("androidx.annotation:annotation:1.11.0")
}

ดึงดูด

dependencies {
    implementation 'androidx.annotation:annotation:1.11.0'
}
จากนั้นคลิกซิงค์เลยในแถบเครื่องมือหรือการแจ้งเตือนการซิงค์ที่ปรากฏขึ้น

หากคุณใช้คำอธิบายประกอบในโมดูลไลบรารีของคุณเอง ระบบจะรวมคำอธิบายประกอบไว้เป็นส่วนหนึ่งของอาร์ติแฟกต์ Android ARchive (AAR) ในรูปแบบ XML ในไฟล์ annotations.zip การเพิ่มทรัพยากร Dependency androidx.annotation จะไม่ทำให้เกิดทรัพยากร Dependency สำหรับผู้ใช้ปลายทางของไลบรารี

หมายเหตุ: หากใช้ไลบรารี Jetpack อื่นๆ คุณอาจไม่จำเป็นต้องเพิ่มทรัพยากร Dependency androidx.annotation เนื่องจากไลบรารี Jetpack อื่นๆ จำนวนมากต้องใช้ไลบรารีคำอธิบายประกอบ คุณจึงอาจมีสิทธิ์เข้าถึงคำอธิบายประกอบอยู่แล้ว

ดูรายการคำอธิบายประกอบทั้งหมดที่รวมอยู่ในที่เก็บ Jetpack ได้ที่ข้อมูลอ้างอิงไลบรารีคำอธิบายประกอบ Jetpack หรือใช้ฟีเจอร์เติมข้อความอัตโนมัติเพื่อแสดงตัวเลือกที่ใช้ได้สำหรับคำสั่ง import androidx.annotation.

เรียกใช้การตรวจสอบโค้ด

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

นอกจากนี้ คุณยังบังคับใช้คำอธิบายประกอบได้โดยเรียกใช้ งาน lint โดยใช้บรรทัดคำสั่ง แม้ว่าวิธีนี้อาจเป็นประโยชน์ในการแจ้งปัญหาเกี่ยวกับเซิร์ฟเวอร์การรวมอย่างต่อเนื่อง แต่งาน lint จะไม่บังคับใช้คำอธิบายประกอบ Nullness (อธิบายไว้ในส่วนต่อไปนี้) มีเพียง Android Studio เท่านั้นที่ทำเช่นนี้ ดูข้อมูลเพิ่มเติมเกี่ยวกับการเปิดใช้และการตรวจสอบ Lint ได้ที่การปรับปรุงโค้ดด้วยการตรวจสอบ Lint

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

คำอธิบายประกอบ Nullness

คำอธิบายประกอบ Nullness มีประโยชน์ในโค้ด Java เพื่อบังคับใช้ว่าค่าจะเป็น Null ได้หรือไม่ ซึ่งมีประโยชน์น้อยกว่าในโค้ด Kotlin เนื่องจาก Kotlin มีกฎความสามารถในการเว้นว่างในตัวที่บังคับใช้ในเวลาคอมไพล์

เพิ่มคำอธิบายประกอบ @Nullable และ @NonNull เพื่อตรวจสอบค่า Null ของตัวแปร พารามิเตอร์ หรือค่าที่แสดงผลที่ระบุ คำอธิบายประกอบ @Nullable ระบุตัวแปร พารามิเตอร์ หรือค่าที่แสดงผลซึ่งอาจเป็น Null ได้ @NonNull บ่งบอกถึงตัวแปร พารามิเตอร์ หรือค่าที่แสดงผลซึ่งเป็นค่า Null ไม่ได้

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

ตัวอย่างต่อไปนี้แสดงการทำงานของความสามารถในการเป็นค่า Null โค้ดตัวอย่าง Kotlin ไม่ได้ใช้ประโยชน์จากคำอธิบายประกอบ @NonNull เนื่องจากระบบจะเพิ่มคำอธิบายประกอบลงในไบต์โค้ดที่สร้างขึ้นโดยอัตโนมัติเมื่อมีการระบุประเภทที่ไม่มีค่า Null ตัวอย่าง Java ใช้ประโยชน์จากคำอธิบายประกอบ @NonNull ในพารามิเตอร์ context และ attrs เพื่อตรวจสอบว่าค่าพารามิเตอร์ที่ส่งมาไม่ใช่ค่า Null นอกจากนี้ยังตรวจสอบว่าเมธอด onCreateView() ไม่แสดงผลเป็น Null ด้วย

Kotlin

...
    /** Annotation not used because of the safe-call operator(?)**/
    override fun onCreateView(
            name: String?,
            context: Context,
            attrs: AttributeSet
    ): View? {
        ...
    }
...

Java

import androidx.annotation.NonNull;
...
    /** Add support for inflating the <fragment> tag. **/
    @NonNull
    @Override
    public View onCreateView(String name, @NonNull Context context,
      @NonNull AttributeSet attrs) {
      ...
      }
...

การวิเคราะห์ความสามารถในการเป็นค่า Null

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

  • การเรียกใช้เมธอดที่แสดงผลเป็น Null ได้
  • เมธอดที่ไม่ควรแสดงผลเป็น Null
  • ตัวแปร เช่น ฟิลด์ ตัวแปรภายใน และพารามิเตอร์ ที่อาจเป็น Null ได้
  • ตัวแปร เช่น ฟิลด์ ตัวแปรภายใน และพารามิเตอร์ ที่ไม่สามารถมีค่า Null

จากนั้นการวิเคราะห์จะแทรกคำอธิบายประกอบ Null ที่เหมาะสมในตำแหน่งที่ตรวจพบโดยอัตโนมัติ

หากต้องการเรียกใช้การวิเคราะห์ความสามารถในการเป็นค่า Null ใน Android Studio ให้เลือกวิเคราะห์ > อนุมานค่า Null Android Studio จะแทรกคำอธิบายประกอบ @Nullable และ @NonNull ของ Android ในตำแหน่งที่ตรวจพบในโค้ด หลังจากเรียกใช้การวิเคราะห์ค่า Null แล้ว แนวทางปฏิบัติแนะนำคือการยืนยันคำอธิบายประกอบที่แทรก

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

คำอธิบายประกอบทรัพยากร

การตรวจสอบประเภททรัพยากรมีประโยชน์เนื่องจากการอ้างอิงทรัพยากรของ Android เช่น ทรัพยากร drawable และ ทรัพยากรสตริง string จะส่งเป็นจำนวนเต็ม

โค้ดที่คาดหวังพารามิเตอร์เพื่ออ้างอิงทรัพยากรประเภทที่เฉพาะเจาะจง เช่น String สามารถส่งไปยังประเภทข้อมูลอ้างอิงที่คาดหวังของ int ได้ แต่อันที่จริงแล้วจะอ้างอิงทรัพยากรประเภทอื่น เช่น ทรัพยากร R.string

เช่น เพิ่มคำอธิบายประกอบ @StringRes เพื่อตรวจสอบว่าพารามิเตอร์ทรัพยากรมีการอ้างอิง R.string หรือไม่ ดังที่แสดงที่นี่

Kotlin

abstract fun setTitle(@StringRes resId: Int)

Java

public abstract void setTitle(@StringRes int resId)

ในระหว่างการตรวจสอบโค้ด คำอธิบายประกอบจะสร้างคำเตือนหากไม่มีการส่งการอ้างอิง R.string ในพารามิเตอร์

คุณสามารถเพิ่มคำอธิบายประกอบสำหรับทรัพยากรประเภทอื่นๆ เช่น @DrawableRes, @DimenRes, @ColorRes และ @InterpolatorRes ได้โดยใช้รูปแบบคำอธิบายประกอบเดียวกันและเรียกใช้ระหว่างการตรวจสอบโค้ด

หากพารามิเตอร์รองรับทรัพยากรหลายประเภท คุณสามารถใส่คำอธิบายประกอบประเภททรัพยากรมากกว่า 1 รายการในพารามิเตอร์ที่กำหนดได้ ใช้ @AnyRes เพื่อระบุว่าพารามิเตอร์ที่มีคำอธิบายประกอบสามารถเป็นทรัพยากร R ประเภทใดก็ได้

แม้ว่าคุณจะใช้ @ColorRes เพื่อระบุว่าพารามิเตอร์ควรเป็นทรัพยากรสีได้ แต่ระบบจะไม่รู้จักจำนวนเต็มสี (ในรูปแบบ RRGGBB หรือ AARRGGBB) เป็นทรัพยากรสี แต่ให้ใช้คำอธิบายประกอบ @ColorInt เพื่อระบุว่าพารามิเตอร์ต้องเป็นจำนวนเต็มสีแทน เครื่องมือสร้างจะแจ้งโค้ดที่ไม่ถูกต้องซึ่งส่งรหัสทรัพยากรสี เช่น android.R.color.black ไปยังเมธอดที่มีคำอธิบายประกอบ แทนที่จะเป็นจำนวนเต็มสี

คำอธิบายประกอบชุดข้อความ

คำอธิบายประกอบเทรดจะตรวจสอบว่ามีการเรียกใช้เมธอดจากเทรดประเภทใดประเภทหนึ่งหรือไม่ ระบบรองรับคำอธิบายประกอบชุดข้อความต่อไปนี้

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

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

การใช้คำอธิบายประกอบเธรดที่พบบ่อยคือการตรวจสอบว่าเมธอดหรือคลาสที่มีคำอธิบายประกอบ @WorkerThread ได้รับการเรียกใช้จากเธรดเบื้องหลังที่เหมาะสมเท่านั้น

คำอธิบายประกอบข้อจำกัดของค่า

ใช้คำอธิบายประกอบ @IntRange, @FloatRange และ @Size เพื่อตรวจสอบค่าของพารามิเตอร์ที่ส่งมา ทั้ง @IntRange และ @FloatRange จะมีประโยชน์มากที่สุดเมื่อใช้กับพารามิเตอร์ที่ผู้ใช้มีแนวโน้มที่จะระบุช่วงผิด

คำอธิบายประกอบ @IntRange จะตรวจสอบว่าค่าพารามิเตอร์จำนวนเต็มหรือแบบยาวอยู่ภายในช่วงที่ระบุ ตัวอย่างต่อไปนี้แสดงให้เห็นว่าพารามิเตอร์ alpha ต้องมีค่าจำนวนเต็มตั้งแต่ 0 ถึง 255

Kotlin

fun setAlpha(@IntRange(from = 0, to = 255) alpha: Int) { ... }

Java

public void setAlpha(@IntRange(from=0,to=255) int alpha) { ... }

คำอธิบายประกอบ @FloatRange จะตรวจสอบว่าค่าพารามิเตอร์ Float หรือ Double อยู่ในช่วงค่าจุดลอยตัวที่ระบุหรือไม่ ตัวอย่างต่อไปนี้ระบุว่าพารามิเตอร์ alpha ต้องมีค่าจำนวนจริงตั้งแต่ 0.0 ถึง 1.0

Kotlin

fun setAlpha(@FloatRange(from = 0.0, to = 1.0) alpha: Float) {...}

Java

public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {...}

คำอธิบายประกอบ @Size จะตรวจสอบขนาดของคอลเล็กชันหรืออาร์เรย์ หรือความยาวของสตริง คุณใช้คำอธิบายประกอบ @Size เพื่อยืนยันคุณภาพต่อไปนี้ได้

  • ขนาดขั้นต่ำ เช่น @Size(min=2)
  • ขนาดสูงสุด เช่น @Size(max=2)
  • ขนาดที่แน่นอน เช่น @Size(2)
  • ตัวเลขที่ขนาดต้องเป็นจำนวนเท่า เช่น @Size(multiple=2)

ตัวอย่างเช่น @Size(min=1) จะตรวจสอบว่าคอลเล็กชันไม่ว่างเปล่า และ @Size(3) จะตรวจสอบว่าอาร์เรย์มีค่า 3 ค่าพอดี

ตัวอย่างต่อไปนี้แสดงให้เห็นว่าอาร์เรย์ location ต้องมีองค์ประกอบอย่างน้อย 1 รายการ

Kotlin

fun getLocation(button: View, @Size(min=1) location: IntArray) {
    button.getLocationOnScreen(location)
}

Java

void getLocation(View button, @Size(min=1) int[] location) {
    button.getLocationOnScreen(location);
}

คำอธิบายประกอบสิทธิ์

ใช้คำอธิบายประกอบ @RequiresPermission เพื่อตรวจสอบสิทธิ์ของผู้เรียกใช้เมธอด หากต้องการตรวจสอบสิทธิ์เดียวจากรายการสิทธิ์ที่ถูกต้อง ให้ใช้แอตทริบิวต์ anyOf หากต้องการตรวจสอบชุดสิทธิ์ ให้ใช้แอตทริบิวต์ allOf ตัวอย่างต่อไปนี้จะใส่คำอธิบายประกอบเมธอด setWallpaper() เพื่อระบุว่าผู้เรียกใช้เมธอดต้องมีสิทธิ์ permission.SET_WALLPAPERS

Kotlin

@RequiresPermission(Manifest.permission.SET_WALLPAPER)
@Throws(IOException::class)
abstract fun setWallpaper(bitmap: Bitmap)

Java

@RequiresPermission(Manifest.permission.SET_WALLPAPER)
public abstract void setWallpaper(Bitmap bitmap) throws IOException;

ตัวอย่างต่อไปนี้กำหนดให้ผู้เรียกใช้เมธอด copyImageFile() ต้องมีทั้งสิทธิ์อ่านในที่จัดเก็บข้อมูลภายนอกและสิทธิ์อ่านข้อมูลเมตาตำแหน่งในรูปภาพที่คัดลอก

Kotlin

@RequiresPermission(allOf = [
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.ACCESS_MEDIA_LOCATION
])
fun copyImageFile(dest: String, source: String) {
    ...
}

Java

@RequiresPermission(allOf = {
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.ACCESS_MEDIA_LOCATION})
public static final void copyImageFile(String dest, String source) {
    //...
}

สำหรับสิทธิ์ใน Intent ให้วางข้อกำหนดสิทธิ์ในช่องสตริงที่กำหนดชื่อการดำเนินการของ Intent ดังนี้

Kotlin

@RequiresPermission(android.Manifest.permission.BLUETOOTH)
const val ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"

Java

@RequiresPermission(android.Manifest.permission.BLUETOOTH)
public static final String ACTION_REQUEST_DISCOVERABLE =
            "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";

สำหรับสิทธิ์ใน Content Provider ที่ต้องใช้สิทธิ์แยกต่างหากสำหรับการเข้าถึงแบบอ่านและเขียน ให้รวมข้อกำหนดสิทธิ์แต่ละรายการไว้ในคำอธิบายประกอบ @RequiresPermission.Read หรือ @RequiresPermission.Write ดังนี้

Kotlin

@RequiresPermission.Read(RequiresPermission(READ_HISTORY_BOOKMARKS))
@RequiresPermission.Write(RequiresPermission(WRITE_HISTORY_BOOKMARKS))
val BOOKMARKS_URI = Uri.parse("content://browser/bookmarks")

Java

@RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))
@RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))
public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");

สิทธิ์โดยอ้อม

เมื่อสิทธิ์ขึ้นอยู่กับค่าที่เฉพาะเจาะจงซึ่งระบุไว้ในพารามิเตอร์ของเมธอด ให้ใช้ @RequiresPermission ในพารามิเตอร์เองโดยไม่ต้องระบุสิทธิ์ที่เฉพาะเจาะจง เช่น เมธอด startActivity(Intent) ใช้สิทธิ์ทางอ้อมใน Intent ที่ส่งไปยังเมธอด ดังนี้

Kotlin

abstract fun startActivity(@RequiresPermission intent: Intent, bundle: Bundle?)

Java

public abstract void startActivity(@RequiresPermission Intent intent, @Nullable Bundle)

เมื่อคุณใช้สิทธิ์ทางอ้อม เครื่องมือสร้างจะทำการวิเคราะห์โฟลว์ข้อมูลเพื่อตรวจสอบว่าอาร์กิวเมนต์ที่ส่งไปยังเมธอดมีคำอธิบายประกอบ @RequiresPermission หรือไม่ จากนั้นจึงบังคับใช้คำอธิบายประกอบที่มีอยู่จากพารามิเตอร์ในเมธอดเอง ในตัวอย่าง startActivity(Intent) คำอธิบายประกอบในคลาส Intent จะทำให้เกิดคำเตือนที่ได้จากการใช้ startActivity(Intent) ที่ไม่ถูกต้องเมื่อมีการส่ง Intent ที่ไม่มีสิทธิ์ที่เหมาะสมไปยังเมธอด ดังที่แสดงในรูปที่ 1

รูปที่ 1 คำเตือนที่สร้างขึ้นจากคำอธิบายประกอบสิทธิ์ทางอ้อมในเมธอด startActivity(Intent)

เครื่องมือสร้างจะสร้างคำเตือนใน startActivity(Intent) จากคำอธิบายประกอบในชื่อการดำเนินการ Intent ที่เกี่ยวข้องในคลาส Intent ดังนี้

Kotlin

@RequiresPermission(Manifest.permission.CALL_PHONE)
const val ACTION_CALL = "android.intent.action.CALL"

Java

@RequiresPermission(Manifest.permission.CALL_PHONE)
public static final String ACTION_CALL = "android.intent.action.CALL";

หากจำเป็น คุณสามารถใช้ @RequiresPermission แทน @RequiresPermission.Read หรือ @RequiresPermission.Write ได้เมื่อใส่คำอธิบายประกอบพารามิเตอร์ของเมธอด อย่างไรก็ตาม สำหรับสิทธิ์ทางอ้อม ไม่ควรใช้ @RequiresPermission ร่วมกับคำอธิบายประกอบสิทธิ์อ่านหรือเขียน

คำอธิบายประกอบค่าที่แสดงผล

ใช้คำอธิบายประกอบ @CheckResult เพื่อตรวจสอบว่ามีการใช้ผลลัพธ์หรือค่าที่แสดงผลของเมธอดจริง แทนที่จะใส่คำอธิบายประกอบเมธอดที่ไม่ใช่โมฆะทุกเมธอดด้วย @CheckResult ให้เพิ่มคำอธิบายประกอบเพื่อชี้แจงผลลัพธ์ของเมธอดที่อาจทำให้สับสน

ตัวอย่างเช่น นักพัฒนาซอฟต์แวร์ Java มือใหม่มักเข้าใจผิดว่า <String>.trim() จะนำช่องว่างออกจากสตริงเดิม การใส่คำอธิบายประกอบเมธอดด้วย @CheckResult จะแจ้งการใช้ <String>.trim() ที่ผู้เรียกไม่ได้ดำเนินการใดๆ กับค่าที่แสดงผลของเมธอด

ตัวอย่างต่อไปนี้จะใส่คำอธิบายประกอบเมธอด checkPermissions() เพื่อตรวจสอบว่ามีการอ้างอิงค่าที่แสดงผลของเมธอดจริงหรือไม่ นอกจากนี้ยังตั้งชื่อเมธอด enforcePermission() เป็นเมธอดที่จะแนะนำให้นักพัฒนาแอปใช้แทนด้วย

Kotlin

@CheckResult(suggest = "#enforcePermission(String,int,int,String)")
abstract fun checkPermission(permission: String, pid: Int, uid: Int): Int

Java

@CheckResult(suggest="#enforcePermission(String,int,int,String)")
public abstract int checkPermission(@NonNull String permission, int pid, int uid);

คำอธิบายประกอบ CallSuper

ใช้คำอธิบายประกอบ @CallSuper เพื่อตรวจสอบว่าเมธอดที่ลบล้างเรียกใช้การใช้งานระดับสูงของเมธอด

ตัวอย่างต่อไปนี้จะใส่คำอธิบายประกอบเมธอด onCreate() เพื่อให้แน่ใจว่าการติดตั้งใช้งานเมธอดที่ลบล้างจะเรียกใช้ super.onCreate()

Kotlin

@CallSuper
override fun onCreate(savedInstanceState: Bundle?) {
}

Java

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

คำอธิบายประกอบ Typedef

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

ใช้คำอธิบายประกอบ @IntDef และ @StringDef เพื่อสร้างคำอธิบายประกอบแบบแจกแจงของชุดจำนวนเต็มและสตริงเพื่อตรวจสอบการอ้างอิงโค้ดประเภทอื่นๆ

คำอธิบายประกอบ Typedef ใช้ @interface เพื่อประกาศประเภทคำอธิบายประกอบที่แจกแจงใหม่ คำอธิบายประกอบ @IntDef และ @StringDef พร้อมด้วย @Retention จะอธิบายคำอธิบายประกอบใหม่และจำเป็นสำหรับการกำหนดประเภทที่แจกแจง คำอธิบายประกอบ @Retention(RetentionPolicy.SOURCE) จะบอกคอมไพเลอร์ไม่ให้จัดเก็บข้อมูลคำอธิบายประกอบที่แจกแจงไว้ในไฟล์ .class

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

Kotlin

import androidx.annotation.IntDef
//...
// Define the list of accepted constants and declare the NavigationMode annotation.
@Retention(AnnotationRetention.SOURCE)
@IntDef(NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS)
annotation class NavigationMode

// Declare the constants.
const val NAVIGATION_MODE_STANDARD = 0
const val NAVIGATION_MODE_LIST = 1
const val NAVIGATION_MODE_TABS = 2

abstract class ActionBar {

    // Decorate the target methods with the annotation.
    // Attach the annotation.
    @get:NavigationMode
    @setparam:NavigationMode
    abstract var navigationMode: Int

}

Java

import androidx.annotation.IntDef;
//...
public abstract class ActionBar {
    //...
    // Define the list of accepted constants and declare the NavigationMode annotation.
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
    public @interface NavigationMode {}

    // Declare the constants.
    public static final int NAVIGATION_MODE_STANDARD = 0;
    public static final int NAVIGATION_MODE_LIST = 1;
    public static final int NAVIGATION_MODE_TABS = 2;

    // Decorate the target methods with the annotation.
    @NavigationMode
    public abstract int getNavigationMode();

    // Attach the annotation.
    public abstract void setNavigationMode(@NavigationMode int mode);
}

เมื่อคุณสร้างโค้ดนี้ ระบบจะสร้างคำเตือนหากพารามิเตอร์ mode ไม่อ้างอิงค่าคงที่ที่กำหนดไว้ (NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST หรือ NAVIGATION_MODE_TABS)

รวม @IntDef และ @IntRange เพื่อระบุว่าจำนวนเต็มอาจเป็นชุดค่าคงที่ที่กำหนดหรือค่าภายในช่วงก็ได้

เปิดใช้การรวมค่าคงที่กับแฟล็ก

หากผู้ใช้สามารถรวมค่าคงที่ที่อนุญาตเข้ากับแฟล็ก (เช่น |, &, ^ และอื่นๆ) คุณสามารถกำหนดคำอธิบายประกอบด้วยแอตทริบิวต์ flag เพื่อตรวจสอบว่าพารามิเตอร์หรือค่าที่แสดงผลอ้างอิงรูปแบบที่ถูกต้องหรือไม่

ตัวอย่างต่อไปนี้สร้างคำอธิบายประกอบ DisplayOptions ด้วยรายการค่าคงที่ DISPLAY_ ที่ถูกต้อง

Kotlin

import androidx.annotation.IntDef
...

@IntDef(flag = true, value = [
    DISPLAY_USE_LOGO,
    DISPLAY_SHOW_HOME,
    DISPLAY_HOME_AS_UP,
    DISPLAY_SHOW_TITLE,
    DISPLAY_SHOW_CUSTOM
])
@Retention(AnnotationRetention.SOURCE)
annotation class DisplayOptions
...

Java

import androidx.annotation.IntDef;
...

@IntDef(flag=true, value={
        DISPLAY_USE_LOGO,
        DISPLAY_SHOW_HOME,
        DISPLAY_HOME_AS_UP,
        DISPLAY_SHOW_TITLE,
        DISPLAY_SHOW_CUSTOM
})
@Retention(RetentionPolicy.SOURCE)
public @interface DisplayOptions {}

...

เมื่อคุณสร้างโค้ดที่มีแฟล็กคำอธิบายประกอบ ระบบจะสร้างคำเตือนหากพารามิเตอร์ที่ตกแต่งหรือค่าที่แสดงผลไม่ได้อ้างอิงรูปแบบที่ถูกต้อง

เก็บคำอธิบายประกอบไว้

คำอธิบายประกอบ @Keep ช่วยให้มั่นใจได้ว่าระบบจะไม่นำคลาสหรือเมธอดที่มีคำอธิบายประกอบออกเมื่อมีการลดขนาดโค้ดในเวลาบิลด์ โดยทั่วไปแล้ว ระบบจะเพิ่มคำอธิบายประกอบนี้ลงในเมธอดและคลาสที่เข้าถึงผ่านการสะท้อนเพื่อป้องกันไม่ให้คอมไพเลอร์ถือว่าโค้ดไม่ได้ใช้

ข้อควรระวัง: คลาสและเมธอดที่คุณใส่คำอธิบายประกอบโดยใช้ @Keep จะปรากฏใน APK ของแอปเสมอ แม้ว่าคุณจะไม่เคยอ้างอิงคลาสและเมธอดเหล่านี้ภายในตรรกะของแอปก็ตาม

หากต้องการให้แอปมีขนาดเล็ก ให้พิจารณาว่าจำเป็นต้องเก็บคำอธิบายประกอบ @Keep แต่ละรายการไว้ในแอปหรือไม่ หากคุณใช้การสะท้อนเพื่อเข้าถึงคลาสหรือเมธอดที่มีคำอธิบายประกอบ ให้ใช้เงื่อนไข -if ในกฎ ProGuard โดยระบุคลาสที่ทำการเรียกการสะท้อน

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

คำอธิบายประกอบระดับการเข้าถึงโค้ด

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

แสดงโค้ดสำหรับการทดสอบ

คำอธิบายประกอบ @VisibleForTesting ระบุว่าเมธอดที่มีคำอธิบายประกอบจะมองเห็นได้มากกว่าที่จำเป็นตามปกติเพื่อให้เมธอดนั้นทดสอบได้ คำอธิบายประกอบนี้มีอาร์กิวเมนต์ otherwise ที่ไม่บังคับ ซึ่งช่วยให้คุณกำหนดระดับการเข้าถึงของเมธอดได้ หากไม่จำเป็นต้องทำให้มองเห็นได้สำหรับการทดสอบ Lint ใช้อาร์กิวเมนต์ otherwise เพื่อบังคับใช้ระดับการเข้าถึงที่ต้องการ

ในตัวอย่างต่อไปนี้ โดยปกติแล้ว myMethod() จะเป็น private แต่จะเป็น package-private สำหรับการทดสอบ เมื่อมีการกำหนด VisibleForTesting.PRIVATE Lint จะแสดงข้อความหากมีการเรียกใช้เมธอดนี้จากภายนอกบริบทที่ได้รับอนุญาตโดยการเข้าถึง private เช่น จากหน่วยการคอมไพล์อื่น

Kotlin

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun myMethod() {
    ...
}

Java

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
void myMethod() { ... }

นอกจากนี้ คุณยังระบุ @VisibleForTesting(otherwise = VisibleForTesting.NONE) เพื่อระบุว่ามีเมธอดสำหรับการทดสอบเท่านั้นได้ด้วย รูปแบบนี้เหมือนกับการใช้ @RestrictTo(TESTS) ทั้ง 2 รายการจะทำการตรวจสอบ Lint เดียวกัน

จำกัด API

คำอธิบายประกอบ @RestrictTo บ่งชี้ว่าการเข้าถึง API ที่มีคำอธิบายประกอบ (แพ็กเกจ คลาส หรือเมธอด) ถูกจำกัด ดังนี้

คลาสย่อย

ใช้รูปแบบคำอธิบายประกอบ @RestrictTo(RestrictTo.Scope.SUBCLASSES) เพื่อจำกัดการเข้าถึง API เฉพาะคลาสย่อยเท่านั้น

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

ห้องสมุด

ใช้แบบฟอร์มคำอธิบายประกอบ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) เพื่อจำกัดการเข้าถึง API ให้เฉพาะไลบรารีของคุณเท่านั้น

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

การทดสอบ

ใช้แบบฟอร์มคำอธิบายประกอบ @RestrictTo(RestrictTo.Scope.TESTS) เพื่อป้องกันไม่ให้นักพัฒนาแอปรายอื่นเข้าถึง API การทดสอบของคุณ

มีเพียงโค้ดทดสอบเท่านั้นที่เข้าถึง API ที่มีคำอธิบายประกอบได้ ซึ่งจะช่วยป้องกันไม่ให้นักพัฒนาแอปรายอื่นใช้ API สำหรับการพัฒนาที่คุณตั้งใจจะใช้เพื่อการทดสอบเท่านั้น