Cải thiện việc kiểm tra mã bằng chú giải

Việc sử dụng các công cụ kiểm tra mã như lint (tìm lỗi mã nguồn) có thể giúp bạn tìm ra vấn đề và cải thiện mã, nhưng đa phần thì các công cụ kiểm tra chỉ có thể suy luận. Chẳng hạn, các giá trị nhận dạng tài nguyên Android sử dụng int để xác định chuỗi, đồ hoạ, màu sắc và các kiểu tài nguyên khác, do đó, các công cụ kiểm tra không biết lúc bạn chỉ định (nhầm) tài nguyên chuỗi trong khi đáng lẽ nên chỉ định màu. Trong trường hợp này, ứng dụng có thể hiển thị không chính xác hoặc không chạy được, ngay cả khi bạn sử dụng công cụ kiểm tra mã.

Thông qua các chú giải, bạn có thể đưa ra gợi ý cho các công cụ kiểm tra mã, chẳng hạn như lint (tìm lỗi mã nguồn) để giúp phát hiện các vấn đề tinh vi hơn về mã. Các chú giải này được thêm dưới dạng thẻ siêu dữ liệu đính kèm vào các biến, tham số và giá trị trả về để kiểm tra các giá trị trả về của phương thức, các tham số đã truyền, các biến cục bộ và các trường. Khi được dùng cùng với các công cụ kiểm tra mã, các chú giải có thể giúp bạn phát hiện các vấn đề, chẳng hạn như các ngoại lệ về con trỏ rỗng và các xung đột về kiểu tài nguyên.

Android hỗ trợ nhiều chú giải thông qua Thư viện Chú giải Jetpack. Bạn có thể truy cập vào thư viện thông qua gói androidx.annotation.

Lưu ý: Nếu một mô-đun có một phần phụ thuộc trên trình xử lý chú giải, thì bạn phải sử dụng cấu hình phần phụ thuộc kapt hoặc ksp cho Kotlin hoặc cấu hình phần phụ thuộc annotationProcessor cho Java để thêm phần phụ thuộc đó.

Thêm chú giải vào dự án

Để bật các chú giải trong dự án, hãy thêm phần phụ thuộc androidx.annotation:annotation vào thư viện hoặc ứng dụng. Bất kỳ chú giải nào mà bạn thêm vào đều được kiểm tra khi bạn chạy công cụ kiểm tra mã hoặc tác vụ lint.

Thêm phần phụ thuộc thư viện Chú giải Jetpack

Thư viện Chú giải Jetpack được xuất bản trên Kho lưu trữ Maven của Google. Để thêm thư viện Chú giải Jetpack vào dự án, hãy thêm dòng sau vào khối dependencies của tệp build.gradle hoặc build.gradle.kts:

Kotlin

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

Groovy

dependencies {
    implementation 'androidx.annotation:annotation:1.7.1'
}
Sau đó, trong thanh công cụ hoặc thông báo đồng bộ hoá xuất hiện, hãy nhấp vào Sync Now (Đồng bộ hoá ngay).

Nếu bạn sử dụng các chú giải trong mô-đun thư viện của riêng mình, thì các chú giải đó sẽ được đính kèm như một phần của cấu phần phần mềm Android Archive (AAR) ở định dạng XML trong tệp annotations.zip. Việc thêm phần phụ thuộc androidx.annotation sẽ không giới thiệu một phần phụ thuộc đến bất kỳ người dùng hạ nguồn (downstream user) nào sử dụng thư viện của bạn.

Lưu ý: Nếu đang sử dụng các thư viện Jetpack khác, bạn có thể không cần thêm phần phụ thuộc androidx.annotation. Vì nhiều thư viện Jetpack khác phụ thuộc vào Thư viện chú giải, nên bạn có thể đã có quyền truy cập vào các chú giải đó.

Để biết danh sách đầy đủ các chú giải có trong kho lưu trữ Jetpack, hãy xem Tài liệu tham khảo về thư viện Chú giải Jetpack hoặc sử dụng tính năng tự động hoàn thành để hiển thị các tuỳ chọn có sẵn cho câu lệnh import androidx.annotation..

Chạy kiểm tra mã

Để bắt đầu quy trình kiểm tra mã từ Android Studio, bao gồm việc xác thực các chú giải và tìm lỗi mã nguồn tự động, hãy chọn Analyze > Inspect Code (Phân tích > Kiểm tra mã) từ trình đơn. Android Studio hiển thị các thông báo xung đột để gắn cờ các sự cố có thể xảy ra do mã của bạn xung đột với các chú giải và để đề xuất giải pháp.

Bạn cũng có thể thực thi các chú giải bằng cách sử dụng dòng lệnh để chạy tác vụ lint. Mặc dù cách này có thể hữu ích cho việc gắn cờ sự cố bằng máy chủ tích hợp liên tục, nhưng tác vụ lint không thực thi các chú giải độ rỗng (được mô tả trong phần sau); chỉ Android Studio mới làm việc này. Để biết thêm thông tin về cách bật và chạy các công cụ tìm lỗi mã nguồn, hãy xem bài viết Cải thiện mã bằng công cụ tìm lỗi mã nguồn.

Mặc dù các xung đột chú giải tạo ra cảnh báo, nhưng các cảnh báo này không ngăn việc biên dịch ứng dụng.

Chú giải độ rỗng

Chú giải độ rỗng có thể hữu ích trong mã Java để thực thi xem giá trị có thể là giá trị rỗng hay không. Các chú giải này ít hữu ích hơn trong mã Kotlin, vì Kotlin đã tích hợp sẵn các quy tắc về tính chất rỗng để thực thi vào thời gian biên dịch.

Thêm chú giải @Nullable@NonNull để kiểm tra độ rỗng của một biến, tham số hoặc giá trị trả về nhất định. Chú giải @Nullable cho biết một biến, tham số hoặc giá trị trả về có thể có giá trị rỗng. @NonNull cho biết một biến, tham số hoặc giá trị trả về không thể có giá trị rỗng.

Chẳng hạn, nếu một biến cục bộ có chứa giá trị rỗng được truyền dưới dạng tham số đến một phương thức với chú giải @NonNull đi kèm với tham số đó, thì việc dựng mã sẽ tạo ra một cảnh báo cho biết xung đột không rỗng (non-null conflict). Ngoài ra, việc cố gắng tham chiếu kết quả của phương thức do @Nullable đánh dấu mà không kiểm tra trước tính chất rỗng của kết quả đó sẽ tạo ra cảnh báo độ rỗng (nullness warning). Chỉ sử dụng @Nullable trên giá trị trả về của một phương thức nếu mọi trường hợp sử dụng phương thức phải được kiểm tra rõ ràng về độ rỗng.

Ví dụ sau đây minh hoạ tính chất rỗng trong thực tế. Mã ví dụ về Kotlin không tận dụng chú giải @NonNull vì chú giải này sẽ tự động được thêm vào mã byte được tạo khi chỉ định một kiểu không thể có giá trị rỗng. Ví dụ về Java tận dụng chú giải @NonNull trên các tham số contextattrs để kiểm tra nhằm đảm bảo rằng các giá trị tham số đã chuyển không phải là giá trị rỗng. Chú giải này cũng kiểm tra để đảm bảo rằng chính phương thức onCreateView() không trả về giá trị rỗng:

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) {
      ...
      }
...

Phân tích tính chất rỗng

Android Studio hỗ trợ chạy quy trình phân tích tính chất rỗng để tự động suy luận và chèn chú giải độ rỗng trên mã của bạn. Quy trình phân tích tính chất rỗng sẽ quét các mối liên kết xuyên suốt hệ thống phân cấp phương thức trong mã của bạn để phát hiện:

  • Các phương thức gọi có thể trả về giá trị rỗng.
  • Các phương thức không được trả về giá trị rỗng.
  • Các biến, chẳng hạn như các trường, các biến cục bộ và các tham số có thể rỗng.
  • Các biến, chẳng hạn như các trường, các biến cục bộ và các tham số không thể chứa giá trị rỗng.

Sau đó, quy trình phân tích sẽ tự động chèn các chú giải rỗng thích hợp vào các vị trí đã phát hiện.

Để chạy quy trình phân tích tính chất rỗng (nullability) trong Android Studio, hãy chọn Analyze (Phân tích) > Infer Nullity (Dự đoán tính chất rỗng). Android Studio sẽ chèn các chú giải @Nullable@NonNull của Android tại các vị trí đã phát hiện trong mã của bạn. Sau khi chạy một quy trình phân tích rỗng, bạn nên xác minh các chú giải được chèn.

Lưu ý: Khi thêm các chú giải độ rỗng, tính năng tự động hoàn thành có thể đề xuất các chú giải @Nullable@NotNull của IntelliJ thay vì các chú giải rỗng của Android và có thể tự động nhập thư viện tương ứng. Tuy nhiên, trình kiểm tra lint (tìm lỗi mã nguồn) của Android Studio chỉ tìm các chú giải rỗng của Android. Khi xác minh các chú giải, hãy xác nhận rằng dự án của bạn sử dụng chú giải rỗng của Android để trình kiểm tra lint (tìm lỗi mã nguồn) có thể thông báo đúng cách cho bạn trong quá trình kiểm tra mã.

Chú giải tài nguyên

Việc xác thực các kiểu tài nguyên có thể hữu ích vì Android sẽ tham chiếu đến các tài nguyên (chẳng hạn như các tài nguyên đối tượng có thể vẽ và các tài nguyên chuỗi) được chuyển dưới dạng số nguyên.

Mã dự kiến tham số tham chiếu đến một loại tài nguyên cụ thể, chẳng hạn như String, có thể được chuyển đến loại tham chiếu dự kiến của int, nhưng thực tế lại tham chiếu một loại tài nguyên khác, chẳng hạn như tài nguyên R.string.

Chẳng hạn, thêm các chú giải @StringRes để kiểm tra xem tham số tài nguyên có chứa dữ liệu tham chiếu R.string hay không, như minh hoạ bên dưới:

Kotlin

abstract fun setTitle(@StringRes resId: Int)

Java

public abstract void setTitle(@StringRes int resId)

Trong quá trình kiểm tra mã, chú giải sẽ tạo cảnh báo nếu một dữ liệu tham chiếu R.string không được chuyển vào tham số.

Bạn có thể thêm các chú giải cho các kiểu tài nguyên khác, chẳng hạn như @DrawableRes, @DimenRes, @ColorRes@InterpolatorRes, bằng cách sử dụng cùng một định dạng chú giải và chạy trong quá trình kiểm tra mã.

Nếu tham số của bạn hỗ trợ nhiều loại tài nguyên, bạn có thể đặt nhiều chú giải loại tài nguyên trên một tham số nhất định. Sử dụng @AnyRes để cho biết rằng tham số được chú giải có thể là loại tài nguyên R bất kỳ.

Mặc dù bạn có thể sử dụng @ColorRes để chỉ định rằng một tham số phải là tài nguyên màu, nhưng số nguyên màu (ở định dạng RRGGBB hoặc AARRGGBB) không được coi là tài nguyên màu. Thay vào đó, hãy sử dụng chú giải @ColorInt để cho biết rằng tham số phải là số nguyên màu. Các công cụ bản dựng sẽ gắn cờ những đoạn mã không chính xác (chuyển tới các phương thức chú giải các giá trị nhận dạng tài nguyên màu như android.R.color.black thay vì số nguyên màu).

Chú giải luồng

Các chú giải luồng kiểm tra xem một phương thức có được gọi từ một loại luồng cụ thể hay không. Các chú giải luồng sau được hỗ trợ:

Các công cụ bản dựng xem các chú giải @MainThread@UiThread là thay thế được cho nhau, vì vậy bạn có thể gọi phương thức @UiThread từ phương thức @MainThread và ngược lại. Tuy nhiên, trong trường hợp ứng dụng hệ thống có nhiều khung hiển thị trên các luồng khác nhau, luồng giao diện người dùng có thể khác với luồng chính. Do đó, bạn nên chú giải các phương thức liên kết với hệ phân cấp khung hiển thị của ứng dụng bằng @UiThread và chỉ chú giải các phương thức liên kết với vòng đời của ứng dụng bằng @MainThread.

Nếu tất cả các phương thức trong một lớp có cùng yêu cầu về phân luồng, thì bạn có thể thêm một chú giải luồng đơn lẻ cho lớp đó để xác minh rằng tất cả các phương thức trong lớp được gọi từ cùng một loại luồng.

Việc sử dụng chú giải luồng phổ biến là để xác thực rằng các phương thức hoặc lớp được chú giải bằng @WorkerThread chỉ được gọi từ một luồng nền thích hợp.

Chú giải quy tắc ràng buộc giá trị

Sử dụng chú giải @IntRange, @FloatRange@Size để xác thực giá trị của các tham số đã chuyển. Cả @IntRange@FloatRange đều hữu ích nhất khi được áp dụng cho các tham số mà người dùng có khả năng nhận không đúng phạm vi.

Chú giải @IntRange xác thực rằng một giá trị tham số kiểu số nguyên hoặc tham số dài nằm trong một phạm vi đã chỉ định. Ví dụ sau đây cho biết rằng tham số alpha phải chứa một giá trị số nguyên từ 0 đến 255:

Kotlin

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

Java

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

Chú giải @FloatRange kiểm tra để đảm bảo rằng một giá trị tham số thuộc kiểu số thực hoặc kiểu double nằm trong phạm vi giá trị dấu phẩy động được chỉ định. Ví dụ sau đây cho biết rằng tham số alpha phải chứa một giá trị số thực từ 0,0 đến 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) {...}

Chú giải @Size kiểm tra kích thước của một bộ sưu tập, mảng hoặc độ dài của một chuỗi. Bạn có thể sử dụng chú giải @Size để xác minh các khía cạnh sau:

  • Kích thước tối thiểu, chẳng hạn như @Size(min=2)
  • Kích thước tối đa, chẳng hạn như @Size(max=2)
  • Kích thước chính xác, chẳng hạn như @Size(2)
  • Kích thước phải là bội số của một số, chẳng hạn như @Size(multiple=2)

Chẳng hạn, @Size(min=1) kiểm tra xem một bộ sưu tập có trống hay không và @Size(3) xác thực rằng một mảng chứa đúng 3 giá trị.

Ví dụ sau đây cho thấy mảng location phải chứa ít nhất 1 phần tử:

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);
}

Chú giải quyền

Sử dụng chú giải @RequiresPermission để xác thực quyền của phương thức gọi đối với một phương thức. Để kiểm tra một quyền trong danh sách các quyền hợp lệ, hãy sử dụng thuộc tính anyOf. Để kiểm tra một nhóm quyền, hãy sử dụng thuộc tính allOf. Ví dụ sau đây chú giải phương thức setWallpaper() để cho biết rằng phương thức gọi của phương thức đó phải có quyền 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;

Ví dụ sau đây yêu cầu phương thức gọi của phương thức copyImageFile() phải có cả quyền đọc bộ nhớ ngoài và quyền đọc siêu dữ liệu vị trí trong hình ảnh đã sao chép:

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) {
    //...
}

Để có các quyền đối với ý định, hãy thiết lập yêu cầu về quyền trên trường chuỗi giúp khai báo tên của thao tác theo ý định:

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";

Để có các quyền đối với nhà cung cấp nội dung (cần có quyền riêng để truy cập chức năng đọc và ghi), hãy gói từng yêu cầu cấp quyền trong một chú giải @RequiresPermission.Read hoặc @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");

Quyền gián tiếp

Khi một quyền phụ thuộc vào giá trị cụ thể được cung cấp cho một tham số của phương thức, hãy sử dụng @RequiresPermission trên chính tham số đó mà không cần liệt kê các quyền cụ thể. Chẳng hạn, phương thức startActivity(Intent) sử dụng quyền gián tiếp đối với ý định được chuyển vào phương thức này:

Kotlin

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

Java

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

Khi bạn sử dụng quyền gián tiếp, các công cụ bản dựng sẽ thực hiện việc phân tích luồng dữ liệu để kiểm tra xem đối số đã chuyển vào phương thức này có chú giải @RequiresPermission nào không. Sau đó, các công cụ này thực thi mọi chú giải hiện có từ tham số trong chính phương thức đó. Trong ví dụ startActivity(Intent), các chú giải trong lớp Intent sẽ dẫn đến kết quả là các cảnh báo về việc sử dụng startActivity(Intent) không hợp lệ khi một ý định không có quyền thích hợp được chuyển vào phương thức này, như trong Hình 1.

Hình 1. Cảnh báo được tạo từ một chú giải quyền gián tiếp trên phương thức startActivity(Intent).

Các công cụ bản dựng tạo cảnh báo trên startActivity(Intent) từ chú giải trên tên của thao tác theo ý định tương ứng trong lớp 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";

Nếu cần, bạn có thể thay thế @RequiresPermission cho @RequiresPermission.Read hoặc @RequiresPermission.Write khi chú giải một tham số của phương thức. Tuy nhiên, đối với quyền gián tiếp, bạn không nên dùng @RequiresPermission với các chú giải quyền đọc hoặc chú giải quyền ghi.

Chú giải giá trị trả về

Sử dụng chú giải @CheckResult để xác thực rằng kết quả hoặc giá trị trả về của một phương thức thực sự được sử dụng. Thay vì chú giải mọi phương thức không trống (non-void) bằng @CheckResult, hãy thêm chú giải để làm rõ kết quả của các phương thức có thể gây nhầm lẫn.

Chẳng hạn, các nhà phát triển Java mới thường hiểu nhầm rằng <String>.trim() sẽ xoá khoảng trắng khỏi chuỗi ban đầu. Việc chú giải một phương thức bằng các cờ @CheckResult sẽ sử dụng <String>.trim() mà trong đó phương thức gọi không làm gì với giá trị trả về của phương thức đó.

Ví dụ sau đây chú giải phương thức checkPermissions() để kiểm tra xem giá trị trả về của phương thức này có thực sự được tham chiếu hay không. Ví dụ này cũng đặt tên phương thức enforcePermission() là một phương thức đề xuất dành cho nhà phát triển để sử dụng thay thế:

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);

Chú giải CallSuper

Sử dụng chú giải @CallSuper để xác thực rằng phương thức ghi đè sẽ gọi quá trình triển khai cấp cao của phương thức đó.

Ví dụ sau đây chú giải phương thức onCreate() để đảm bảo rằng mọi quá trình triển khai phương thức ghi đè sẽ gọi super.onCreate():

Kotlin

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

Java

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

Chú giải Typedef

Các chú giải typedef kiểm tra xem một tham số, giá trị trả về hoặc trường cụ thể có tham chiếu đến một tập hợp các hằng số cụ thể hay không. Các chú giải này cũng bật tính năng hoàn thành mã nhằm tự động cung cấp các hằng số được cho phép.

Sử dụng các chú giải @IntDef@StringDef để tạo các chú giải liệt kê của các tập hợp số nguyên cũng như của chuỗi để xác thực các loại tham chiếu mã khác.

Các chú giải typedef sử dụng @interface để khai báo loại chú giải được liệt kê mới. Các chú giải @IntDef@StringDef, cùng với @Retention, chú giải về sự cần thiết phải sử dụng các chú giải mới để khai báo loại liệt kê. Chú giải @Retention(RetentionPolicy.SOURCE) yêu cầu trình biên dịch không lưu trữ dữ liệu chú giải được liệt kê trong tệp .class.

Ví dụ sau đây minh hoạ các bước tạo một chú giải giúp kiểm tra xem giá trị được chuyển dưới dạng tham số phương thức có tham chiếu đến một trong các hằng số xác định hay không:

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);
}

Khi tạo bản dựng từ mã này, một cảnh báo sẽ được tạo nếu tham số mode không tham chiếu đến một trong các hằng số đã khai báo (NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST hoặc NAVIGATION_MODE_TABS).

Kết hợp @IntDef@IntRange để cho biết rằng một số nguyên có thể là tập hợp các hằng số hoặc một giá trị nhất định trong phạm vi.

Bật tính năng kết hợp các hằng số với cờ

Nếu người dùng có thể kết hợp các hằng số được phép với một cờ (chẳng hạn như |, &, ^, v.v.), bạn có thể xác định một chú giải có thuộc tính flag để kiểm tra xem tham số hoặc giá trị trả về có tham chiếu đến một mẫu hợp lệ hay không.

Ví dụ sau đây sẽ tạo chú giải DisplayOptions với danh sách các hằng số DISPLAY_ hợp lệ:

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 {}

...

Khi bạn tạo mã có cờ chú giải, một cảnh báo sẽ được tạo nếu tham số hoặc giá trị trả về được trang trí không tham chiếu đến mẫu hợp lệ.

Chú giải Keep

Chú giải @Keep đảm bảo rằng lớp hoặc phương thức được chú giải sẽ không bị xoá khi mã được rút gọn tại thời điểm tạo bản dựng. Chú giải này thường được thêm vào các phương thức và các lớp được truy cập thông qua đối tượng phản chiếu (reflection) để ngăn trình biên dịch xem đoạn mã đó là không được sử dụng.

Thận trọng: Các lớp và phương thức mà bạn chú giải bằng @Keep luôn xuất hiện trong tệp APK của ứng dụng, ngay cả khi bạn hoàn toàn không tham chiếu đến các lớp và phương thức này trong logic của ứng dụng.

Để đảm bảo ứng dụng luôn có kích thước nhỏ, hãy cân nhắc xem có cần thiết lưu giữ từng chú giải @Keep trong ứng dụng hay không. Nếu bạn sử dụng phương pháp phản chiếu để truy cập một lớp hoặc phương thức được chú giải, hãy dùng một điều kiện -if trong quy tắc ProGuard để chỉ định lớp thực hiện lệnh gọi phản chiếu.

Để biết thêm thông tin về cách giảm kích thước mã và chỉ định mã không cần xoá, hãy xem bài viết Rút gọn, làm rối mã nguồn và tối ưu hoá ứng dụng.

Chú giải chế độ hiển thị mã

Sử dụng các chú giải sau để biểu thị chế độ hiển thị của các phần mã cụ thể, chẳng hạn như các phương thức, lớp, trường hoặc gói.

Hiển thị mã để kiểm thử

Chú giải @VisibleForTesting cho biết rằng một phương thức được chú giải cần phải có mức độ hiển thị nhiều hơn bình thường để bạn có thể kiểm thử phương thức đó. Chú giải này có một đối số otherwise không bắt buộc cho phép bạn chỉ định chế độ hiển thị mà phương thức cần phải có nếu không cần thiết phải hiển thị phương thức đó cho mục đích kiểm thử. Công cụ tìm lỗi mã nguồn sử dụng đối số otherwise để thực thi chế độ hiển thị đã dự định.

Trong ví dụ sau, myMethod() thường là private, nhưng trong trường hợp này là package-private cho các quá trình kiểm thử. Với chỉ định VisibleForTesting.PRIVATE, công cụ lint (tìm lỗi mã nguồn) sẽ hiển thị một thông báo nếu phương thức này được gọi từ bên ngoài ngữ cảnh mà quyền truy cập private cho phép, chẳng hạn như từ một đơn vị biên dịch khác.

Kotlin

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

Java

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

Bạn cũng có thể chỉ định @VisibleForTesting(otherwise = VisibleForTesting.NONE) để cho biết rằng một phương thức chỉ tồn tại trong quá trình kiểm thử. Biểu mẫu này giống với việc sử dụng @RestrictTo(TESTS). Cả hai đều thực hiện cùng một quy trình kiểm tra mã.

Hạn chế một API

Chú giải @RestrictTo cho biết rằng quyền truy cập vào API được chú giải (gói, lớp hoặc phương thức) bị giới hạn như sau:

Lớp con

Sử dụng biểu mẫu chú giải @RestrictTo(RestrictTo.Scope.SUBCLASSES) để hạn chế chỉ cho phép API truy cập vào các lớp con.

Chỉ những lớp mở rộng lớp được chú giải mới có thể truy cập vào API này. Đối tượng sửa đổi Java protected không hạn chế đầy đủ vì công cụ này cho phép truy cập từ các lớp không liên quan trong cùng một gói. Ngoài ra, có những trường hợp mà bạn muốn để một phương thức ở chế độ public nhằm có sự linh hoạt trong tương lai vì bạn không bao giờ có thể đặt phương thức được protected và ghi đè trước đó ở chế độ public, nhưng bạn muốn cung cấp một gợi ý rằng lớp này chỉ dành cho các mục đích sử dụng trong lớp hoặc từ các lớp con.

Thư viện

Dùng biểu mẫu chú giải @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) để hạn chế quyền truy cập của API vào các thư viện của bạn.

Chỉ mã thư viện của bạn mới có thể truy cập vào API được chú giải. Điều này cho phép bạn không chỉ sắp xếp mã theo bất kỳ hệ thống phân cấp gói nào, mà còn chia sẻ mã giữa một nhóm các thư viện liên quan. Tuỳ chọn này đã có sẵn đối với các thư viện Jetpack có nhiều mã triển khai không dành cho mục đích sử dụng bên ngoài, nhưng phải dùng public để chia sẻ mã trên các thư viện Jetpack bổ sung.

Kiểm thử

Sử dụng biểu mẫu thẻ chú giải @RestrictTo(RestrictTo.Scope.TESTS) để ngăn không cho các nhà phát triển khác truy cập các API đang kiểm thử.

Chỉ mã kiểm thử mới có thể truy cập vào API được chú giải. Chú giải này ngăn các nhà phát triển khác sử dụng các API, vì mục đích phát triển mà bạn dự kiến chỉ là kiểm thử.