بهبود بازرسی کد با گزارمان‌ها

استفاده از ابزارهای بازرسی کد، مانند lint، می‌تواند به شما در یافتن مشکلات و بهبود کدتان کمک کند، اما ابزارهای بازرسی فقط می‌توانند تا حدودی استنباط کنند. شناسه‌های منبع Android، برای مثال، از int برای شناسایی رشته‌ها، گرافیک‌ها، رنگ‌ها، و دیگر انواع منبع استفاده می‌کنند، بنابراین ابزارهای بازرسی نمی‌توانند تشخیص دهند که چه زمانی منبع رشته‌ای را مشخص کرده‌اید درحالی‌که باید رنگ را مشخص می‌کردید. این وضعیت به این معنی است که ممکن است برنامه‌تان به‌درستی ارائه نشود یا اصلاً اجرا نشود، حتی اگر از بازرسی کد استفاده کنید.

حاشیه‌نویسی‌ها به شما امکان می‌دهند نکاتی را برای ابزارهای بازرسی کد، مانند lint، ارائه دهید تا به شناسایی این مشکلات ظریف‌تر کد کمک کنند. حاشیه‌نویسی‌ها به‌عنوان برچسب‌های فراداده اضافه می‌شوند که به متغیرها، پارامترها، و مقادیر برگشتی پیوست می‌کنید تا مقادیر برگشتی روش، پارامترهای ارسال‌شده، متغیرهای محلی، و فیلدها را بررسی کنید. وقتی از حاشیه‌نویسی‌ها به‌همراه ابزارهای بازرسی کد استفاده می‌شود، می‌توانند به شما کمک کنند مشکلاتی مثل استثنای اشاره‌گر تهی و تداخل نوع منبع را شناسایی کنید.

Android از انواع حاشیه‌نویسی‌ها ازطریق کتابخانه حاشیه‌نویسی‌های Jetpack پشتیبانی می‌کند. می‌توانید ازطریق بسته androidx.annotation به کتابخانه دسترسی پیدا کنید.

توجه: اگر ماژولی به پردازشگر گزارمان وابستگی دارد، باید از پیکربندی وابستگی kapt یا ksp برای Kotlin یا پیکربندی وابستگی annotationProcessor برای Java استفاده کنید تا آن وابستگی را اضافه کنید.

افزودن حاشیه‌نویسی به پروژه

برای فعال کردن حاشیه‌نویسی در پروژه‌تان، وابستگی androidx.annotation:annotation را به کتابخانه یا برنامه‌تان اضافه کنید. هر حاشیه‌نویسی‌ای که اضافه می‌کنید هنگام اجرای بازرسی کد یا تکلیف lint بررسی می‌شود.

افزودن وابستگی کتابخانه Jetpack Annotations

کتابخانه Jetpack Annotations در مخزن Maven در Google منتشر شده است. برای افزودن کتابخانه Jetpack Anotations به پروژه‌تان، خط زیر را در بلوک dependencies فایل build.gradle یا build.gradle.kts خود اضافه کنید:

کاتلین

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

شیک

dependencies {
    implementation 'androidx.annotation:annotation:1.11.0'
}
سپس در نوارابزار یا اعلان همگام‌سازی که ظاهر می‌شود، روی اکنون همگام‌سازی شود کلیک کنید.

اگر از حاشیه‌نویسی‌ها در واحد کتابخانه خودتان استفاده می‌کنید، حاشیه‌نویسی‌ها به‌عنوان بخشی از ساخته Android Archive (AAR) در قالب XML در فایل annotations.zip گنجانده می‌شوند. افزودن وابستگی androidx.annotation وابستگی‌ای برای کاربران پایین‌دستی کتابخانه‌تان ایجاد نمی‌کند.

توجه: اگر از کتابخانه‌های Jetpack دیگر استفاده می‌کنید، ممکن است لازم نباشد وابستگی androidx.annotation را اضافه کنید. ازآنجایی‌که بسیاری از کتابخانه‌های Jetpack دیگر به «کتابخانه حاشیه‌نویسی‌ها» وابسته هستند، ممکن است ازقبل به حاشیه‌نویسی‌ها دسترسی داشته باشید.

برای مشاهده فهرست کامل حاشیه‌نویسی‌های موجود در مخزن Jetpack، یا به مرجع کتابخانه حاشیه‌نویسی‌های Jetpack مراجعه کنید یا از ویژگی تکمیل خودکار برای نمایش گزینه‌های دردسترس برای عبارت import androidx.annotation. استفاده کنید.

اجرای بازرسی کد

برای شروع بازرسی کد از «استودیو Android»، که شامل اعتبارسنجی حاشیه‌نویسی‌ها و بررسی خودکار lint می‌شود، تحلیل > بازرسی کد را از منو انتخاب کنید. «استودیو Android» پیام‌های تداخل را نمایش می‌دهد تا مشکلات احتمالی را که در آن کد شما با حاشیه‌نویسی‌ها تداخل دارد علامت‌گذاری کند و راه‌حل‌های ممکن را پیشنهاد دهد.

همچنین می‌توانید با اجرای تکلیف lint بااستفاده از خط فرمان، حاشیه‌نویسی‌ها را اعمال کنید. اگرچه این کار ممکن است برای پرچم‌گذاری مشکلات با سرور ادغام پیوسته مفید باشد، اما تکلیف lint حاشیه‌نویسی‌های پوچی را اجرا نمی‌کند (در بخش زیر شرح داده شده است)؛ فقط Android Studio این کار را انجام می‌دهد. برای اطلاعات بیشتر درباره فعال کردن و اجرای بازرسی‌های lint، به بهبود کد با بررسی‌های lint مراجعه کنید.

اگرچه تداخل حاشیه‌نویسی هشدار ایجاد می‌کند، این هشدارها مانع از کامپایل شدن برنامه‌تان نمی‌شود.

حاشیه‌نویسی‌های Nullness

حاشیه‌نویسی‌های Nullness می‌تواند در کد Java برای اعمال اینکه آیا مقادیر می‌توانند null باشند یا نه مفید باشد. این حاشیه‌نویسی‌ها در کد Kotlin کمتر مفید هستند، زیرا Kotlin دارای قوانین تهی‌پذیری داخلی است که در زمان ترجمه اعمال می‌شوند.

حاشیه‌نویسی‌های @Nullable و @NonNull را اضافه کنید تا تهی بودن متغیر، پارامتر، یا مقدار برگشتی داده‌شده را بررسی کنید. حاشیه‌نویسی @Nullable نشان‌دهنده متغیر، پارامتر، یا مقدار برگشتی است که می‌تواند تهی باشد. @NonNull نشان‌دهنده متغیر، پارامتر، یا مقدار برگشتی است که نمی‌تواند تهی باشد.

برای مثال، اگر متغیر محلی‌ای که حاوی مقدار تهی است به‌عنوان پارامتر به روشی ارسال شود که حاشیه‌نویسی @NonNull به آن پارامتر پیوست شده باشد، ساختن کد هشداری تولید می‌کند که نشان‌دهنده تداخل غیرتهی است. همچنین، تلاش برای ارجاع به نتیجه روشی که با @Nullable علامت‌گذاری شده است، بدون بررسی اولیه اینکه آیا نتیجه تهی است یا نه، هشدار تهی بودن ایجاد می‌کند. فقط زمانی از @Nullable در مقدار بازگشتی روش استفاده کنید که هر استفاده از روش باید به‌طور صریح بررسی تهی شود.

مثال زیر تهی‌پذیری را در عمل نشان می‌دهد. کد نمونه Kotlin از حاشیه‌نویسی @NonNull استفاده نمی‌کند زیرا وقتی نوع غیرقابل‌تهی مشخص می‌شود، این حاشیه‌نویسی به‌طور خودکار به بایت‌کد تولیدشده اضافه می‌شود. نمونه Java از حاشیه‌نویسی @NonNull در پارامترهای context و attrs استفاده می‌کند تا بررسی کند که مقادیر پارامترهای ارسال‌شده تهی نباشند. همچنین بررسی می‌کند که خود روش onCreateView() مقدار تهی برنگرداند:

کاتلین

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

جاوا

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

تجزیه‌وتحلیل پوچ‌پذیری

Android Studio از اجرای تجزیه‌وتحلیل تهی‌پذیری برای استنباط خودکار و درج حاشیه‌نویسی‌های تهی‌پذیری در کد شما پشتیبانی می‌کند. تجزیه‌وتحلیل پوچ‌پذیری، قراردادها را در سراسر سلسله‌مراتب روش در کد شما اسکن می‌کند تا موارد زیر را شناسایی کند:

  • فراخوانی روش‌هایی که می‌توانند مقدار تهی برگردانند.
  • روش‌هایی که نباید مقدار تهی برگردانند.
  • متغیرهایی مثل فیلدها، متغیرهای محلی، و پارامترهایی که می‌توانند تهی باشند.
  • متغیرهایی مانند فیلدها، متغیرهای محلی، و پارامترها که نمی‌توانند مقدار تهی داشته باشند.

سپس تجزیه‌وتحلیل به‌طور خودکار حاشیه‌نویسی‌های تهی مناسب را در مکان‌های شناسایی‌شده درج می‌کند.

برای اجرای تجزیه‌وتحلیل تهی‌پذیری در Android Studio، تجزیه‌وتحلیل > استنباط تهی‌پذیری را انتخاب کنید. Android Studio حاشیه‌نویسی‌های Android @Nullable و @NonNull را در مکان‌های شناسایی‌شده در کدتان درج می‌کند. پس‌از اجرای تجزیه‌وتحلیل تهی، بهتر است حاشیه‌نویسی‌های تزریق‌شده را درستی‌سنجی کنید.

توجه: هنگام افزودن حاشیه‌نویسی‌های پوچی، تکمیل خودکار ممکن است حاشیه‌نویسی‌های IntelliJ @Nullable و @NotNull را به‌جای حاشیه‌نویسی‌های پوچی Android پیشنهاد دهد و ممکن است کتابخانه مربوطه را به‌طور خودکار وارد کند. بااین‌حال، بررسی‌کننده lint «استودیو Android» فقط حاشیه‌نویسی‌های null در Android را جستجو می‌کند. هنگام درستی‌سنجی حاشیه‌نویسی‌هایتان، مطمئن شوید که پروژه‌تان از حاشیه‌نویسی‌های تهی Android استفاده می‌کند تا بررسی‌کننده lint بتواند به‌درستی درطول بازرسی کد به شما اطلاع دهد.

حاشیه‌نویسی‌های منبع

اعتبارسنجی انواع منابع می‌تواند مفید باشد زیرا ارجاع‌های Android به منابع، مثل منابع drawable و string، به‌صورت عدد صحیح منتقل می‌شوند.

کدی که انتظار دارد پارامتری به نوع خاصی از منبع، مانند String، ارجاع دهد، می‌تواند به نوع مرجع موردانتظار int منتقل شود، اما درواقع به نوع دیگری از منبع، مانند منبع R.string، ارجاع دهد.

برای مثال، حاشیه‌نویسی‌های @StringRes را اضافه کنید تا بررسی کنید آیا پارامتر منبع حاوی مرجع R.string است یا نه، همان‌طور که در اینجا نشان داده شده است:

کاتلین

abstract fun setTitle(@StringRes resId: Int)

جاوا

public abstract void setTitle(@StringRes int resId)

درطول بازرسی کد، اگر مرجع R.string در پارامتر ارسال نشود، حاشیه‌نویسی هشداری ایجاد می‌کند.

حاشیه‌نویسی برای انواع دیگر منابع، مانند @DrawableRes، @DimenRes، @ColorRes، و @InterpolatorRes، می‌تواند بااستفاده از همان قالب حاشیه‌نویسی اضافه شود و درطول بازرسی کد اجرا شود.

اگر پارامتر شما از چند نوع منبع پشتیبانی می‌کند، می‌توانید بیش‌از یک حاشیه‌نویسی نوع منبع را روی پارامتر موردنظر قرار دهید. از @AnyRes استفاده کنید تا نشان دهید پارامتر حاشیه‌نویسی‌شده می‌تواند هر نوعی از منبع R باشد.

اگرچه می‌توانید از @ColorRes برای مشخص کردن اینکه یک پارامتر باید منبع رنگ باشد استفاده کنید، عدد صحیح رنگ (در قالب RRGGBB یا AARRGGBB) به‌عنوان منبع رنگ شناخته نمی‌شود. به‌جای آن، از حاشیه‌نویسی @ColorInt استفاده کنید تا نشان دهید پارامتر باید عدد صحیح رنگ باشد. ابزارهای ساخت، کد نادرستی را که شناسه منبع رنگی مانند android.R.color.black را به‌جای عدد صحیح رنگ به روش‌های حاشیه‌نویسی‌شده ارسال می‌کند پرچم‌گذاری خواهند کرد.

حاشیه‌نویسی‌های رشته

حاشیه‌نویسی‌های رشته بررسی می‌کنند که آیا روشی از نوع خاصی از رشته فراخوانی می‌شود یا نه. حاشیه‌نویسی‌های رشته زیر پشتیبانی می‌شود:

ابزارهای ساخت با حاشیه‌نویسی‌های @MainThread و @UiThread به‌عنوان قابل‌تعویض رفتار می‌کنند، بنابراین می‌توانید روش‌های @UiThread را از روش‌های @MainThread فراخوانی کنید و برعکس. بااین‌حال، در برنامه‌های سیستم با چند نما در رشته‌های مختلف، ممکن است رشته میانای کاربر با رشته اصلی متفاوت باشد. بنابراین، باید روش‌های مرتبط با سلسله‌مراتب نمای برنامه را با @UiThread حاشیه‌نویسی کنید و فقط روش‌های مرتبط با چرخه حیات برنامه را با @MainThread حاشیه‌نویسی کنید.

اگر همه روش‌ها در یک کلاس الزامات رشته‌ای یکسانی داشته باشند، می‌توانید یک حاشیه‌نویسی رشته‌ای واحد به کلاس اضافه کنید تا تأیید شود که همه روش‌ها در کلاس از یک نوع رشته فراخوانی می‌شوند.

یکی از کاربردهای رایج حاشیه‌نویسی رشته‌ای، اعتبارسنجی این است که روش‌ها یا کلاس‌های حاشیه‌نویسی‌شده با @WorkerThread فقط از یک رشته پس‌زمینه مناسب فراخوانی می‌شوند.

حاشیه‌نویسی‌های محدودیت مقدار

از حاشیه‌نویسی‌های @IntRange، @FloatRange، و @Size برای اعتبارسنجی مقادیر پارامترهای ارسال‌شده استفاده کنید. هر دو @IntRange و @FloatRange زمانی بیشترین کاربرد را دارند که برای پارامترهایی اعمال شوند که کاربران احتمالاً محدوده را اشتباه می‌گیرند.

حاشیه‌نویسی @IntRange درستی‌سنجی می‌کند که مقدار پارامتر عدد صحیح یا طولانی در محدوده مشخص‌شده باشد. مثال زیر نشان می‌دهد که پارامتر alpha باید حاوی مقدار عدد صحیح از ۰ تا ۲۵۵ باشد:

کاتلین

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

جاوا

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

حاشیه‌نویسی @FloatRange بررسی می‌کند که آیا مقدار پارامتر اعشاری یا دوبرابر در محدوده مشخصی از مقادیر اعشاری قرار دارد یا نه. مثال زیر نشان می‌دهد که پارامتر alpha باید حاوی مقدار اعشاری از ۰٫۰ تا ۱٫۰ باشد:

کاتلین

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

جاوا

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) تأیید می‌کند که آرایه‌ای دقیقاً سه مقدار دارد.

مثال زیر نشان می‌دهد که آرایه location باید حداقل یک عنصر داشته باشد:

کاتلین

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

جاوا

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

حاشیه‌نویسی‌های اجازه

از حاشیه‌نویسی @RequiresPermission برای اعتبارسنجی اجازه‌های فراخواننده روش استفاده کنید. برای بررسی یک اجازه خاص از فهرست اجازه‌های معتبر، از مشخصه anyOf استفاده کنید. برای بررسی مجموعه‌ای از اجازه‌ها، از مشخصه allOf استفاده کنید. مثال زیر حاشیه‌نویسی می‌کند روش setWallpaper() برای نشان دادن اینکه فراخواننده روش باید داشته باشد اجازه permission.SET_WALLPAPERS:

کاتلین

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

جاوا

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

مثال زیر مستلزم این است که فراخواننده روش copyImageFile() هم دسترسی خواندن به فضای ذخیره‌سازی خارجی و هم دسترسی خواندن به فراداده‌های مکان در تصویر کپی‌شده داشته باشد:

کاتلین

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

جاوا

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

برای اجازه‌های مربوط به هدف‌ها، الزام اجازه را در فیلد رشته‌ای که نام کنش هدف را تعریف می‌کند قرار دهید:

کاتلین

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

جاوا

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

برای اجازه‌های ارائه‌دهندگان محتوا که به اجازه‌های جداگانه برای دسترسی خواندن و نوشتن نیاز دارند، هر الزام اجازه را در حاشیه‌نویسی @RequiresPermission.Read یا @RequiresPermission.Write قرار دهید:

کاتلین

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

جاوا

@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) از اجازه غیرمستقیم در هدف منتقل‌شده به روش استفاده می‌کند:

کاتلین

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

جاوا

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

وقتی از اجازه‌های غیرمستقیم استفاده می‌کنید، ابزارهای ساخت تجزیه‌وتحلیل جریان داده را انجام می‌دهند تا بررسی کنند که آیا آرگومان ارسال‌شده به روش دارای حاشیه‌نویسی @RequiresPermission است یا نه. سپس هرگونه حاشیه‌نویسی موجود را از پارامتر روی خود روش اعمال می‌کنند. در مثال startActivity(Intent)، حاشیه‌نویسی‌ها در کلاس Intent باعث ایجاد هشدارهای حاصل در استفاده‌های نامعتبر از startActivity(Intent) می‌شوند، وقتی که قصدی بدون اجازه‌های مناسب به روش منتقل می‌شود، همان‌طور که در شکل ۱ نشان داده شده است.

شکل ۱. هشدار ایجادشده از حاشیه‌نویسی اجازه‌های غیرمستقیم در روش startActivity(Intent).

ابزارهای ساخت هشدار را در startActivity(Intent) از حاشیه‌نویسی روی نام کنش هدف مربوطه در کلاس Intent تولید می‌کنند:

کاتلین

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

جاوا

@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() را به‌عنوان روشی برای پیشنهاد به توسعه‌دهنده به‌عنوان جایگزین نام‌گذاری می‌کند:

کاتلین

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

جاوا

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

حاشیه‌نویسی‌های CallSuper

از حاشیه‌نویسی @CallSuper برای اعتبارسنجی اینکه روش لغوکننده پیاده‌سازی فوق‌العاده روش را فراخوانی می‌کند استفاده کنید.

مثال زیر روش onCreate() را حاشیه‌نویسی می‌کند تا اطمینان حاصل شود که هرگونه پیاده‌سازی روش لغوکننده، super.onCreate() را فراخوانی می‌کند:

کاتلین

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

جاوا

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

حاشیه‌نویسی‌های Typedef

حاشیه‌نویسی‌های Typedef بررسی می‌کنند که آیا پارامتر، مقدار بازگشتی، یا فیلد خاصی به مجموعه مشخصی از ثابت‌ها ارجاع می‌دهد یا نه. همچنین تکمیل کد را فعال می‌کنند تا به‌طور خودکار ثابت‌های مجاز را پیشنهاد دهد.

از حاشیه‌نویسی‌های @IntDef و @StringDef برای ایجاد حاشیه‌نویسی‌های شمارشی از مجموعه‌های عدد صحیح و رشته‌ای برای اعتبارسنجی انواع دیگر ارجاع‌های کد استفاده کنید.

حاشیه‌نویسی‌های Typedef از @interface برای اعلام نوع حاشیه‌نویسی شمارشی جدید استفاده می‌کنند. حاشیه‌نویسی‌های @IntDef و @StringDef، همراه با @Retention، حاشیه‌نویسی جدید را حاشیه‌نویسی می‌کنند و برای تعریف نوع شمارشی ضروری هستند. حاشیه‌نویسی @Retention(RetentionPolicy.SOURCE) به کامپایلر می‌گوید داده‌های حاشیه‌نویسی شمارش‌شده را در فایل .class ذخیره نکند.

مثال زیر مراحل ایجاد حاشیه‌نویسی را نشان می‌دهد که بررسی می‌کند آیا مقدار ارسال‌شده به‌عنوان پارامتر روش به یکی از ثابت‌های تعریف‌شده ارجاع می‌دهد یا نه:

کاتلین

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

}

جاوا

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_ ایجاد می‌کند:

کاتلین

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
...

جاوا

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، اگر این روش از خارج از بافت مجاز توسط دسترسی private فراخوانی شود، مثلاً از واحد گردآوری متفاوت، lint پیامی نمایش می‌دهد.

کاتلین

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

جاوا

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

همچنین می‌توانید @VisibleForTesting(otherwise = VisibleForTesting.NONE) را مشخص کنید تا نشان دهید روشی فقط برای آزمایش وجود دارد. این فرم همانند استفاده از @RestrictTo(TESTS) است. هر دو یک بررسی lint را انجام می‌دهند.

محدود کردن میانای برنامه‌سازی کاربردی

حاشیه‌نویسی @RestrictTo نشان می‌دهد که دسترسی به میانای برنامه‌سازی کاربردی حاشیه‌نویسی‌شده (بسته، کلاس، یا روش) به‌صورت زیر محدود شده است:

زیرکلاس‌ها

از فرم حاشیه‌نویسی @RestrictTo(RestrictTo.Scope.SUBCLASSES) برای محدود کردن دسترسی API فقط به زیرکلاس‌ها استفاده کنید.

فقط کلاس‌هایی که کلاس حاشیه‌نویسی‌شده را گسترش می‌دهند می‌توانند به این API دسترسی داشته باشند. اصلاح‌کننده Java protected به‌اندازه کافی محدودکننده نیست، زیرا اجازه دسترسی از کلاس‌های نامرتبط در همان بسته را می‌دهد. همچنین، مواردی وجود دارد که می‌خواهید یک روش public را برای انعطاف‌پذیری در آینده رها کنید، زیرا هرگز نمی‌توانید یک روش قبلاً protected و لغو‌شده را public کنید، اما می‌خواهید یک نکته ارائه دهید که کلاس برای استفاده در داخل کلاس یا فقط از زیرکلاس‌ها درنظر گرفته شده است.

کتابخانه

از فرم حاشیه‌نویسی @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) استفاده کنید تا دسترسی API را فقط به کتابخانه‌هایتان محدود کنید.

فقط کد کتابخانه شما می‌تواند به میانای برنامه‌سازی کاربردی حاشیه‌نویسی‌شده دسترسی داشته باشد. این کار به شما امکان می‌دهد نه‌تنها کدتان را در هر سلسله‌مراتب بسته‌ای که می‌خواهید سازمان‌دهی کنید، بلکه کد را بین گروهی از کتابخانه‌های مرتبط هم‌رسانی کنید. این گزینه ازقبل برای کتابخانه‌های Jetpack دردسترس است که کد پیاده‌سازی زیادی دارند که برای استفاده خارجی درنظر گرفته نشده است، اما باید public باشد تا بتوان آن را در کتابخانه‌های تکمیلی مختلف Jetpack هم‌رسانی کرد.

آزمایش

از فرم حاشیه‌نویسی @RestrictTo(RestrictTo.Scope.TESTS) استفاده کنید تا از دسترسی توسعه‌دهندگان دیگر به میاناهای برنامه‌سازی کاربردی آزمایشی‌تان جلوگیری کنید.

فقط کد آزمایشی می‌تواند به میانای برنامه‌سازی کاربردی حاشیه‌نویسی‌شده دسترسی داشته باشد. این کار مانع از آن می‌شود که توسعه‌دهندگان دیگر از میاناهای برنامه‌سازی کاربردی‌ای که فقط برای اهداف آزمایشی درنظر گرفته‌اید برای توسعه استفاده کنند.