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 và dự đoá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.9.1") }
Groovy
dependencies { implementation 'androidx.annotation:annotation:1.9.1' }
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
và @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ố context
và attrs
để 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
và @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
và @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ú thích 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 vẽ được 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
và @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
và @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
và @Size
để xác thực giá trị của các tham số đã chuyển. Cả @IntRange
và @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.
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
và @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
và @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
và @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ử.