تحسين فحص الرمز باستخدام التعليقات التوضيحية

إنّ استخدام أدوات فحص الرمز، مثل lint، قد يساعدك في العثور على المشاكل وتحسين الرمز البرمجي، غير أنّ أدوات الفحص يمكنها استنتاج الكثير فقط. على سبيل المثال، تستخدم معرّفات موارد Android int لتحديد السلاسل والرسومات والألوان وأنواع الموارد الأخرى، حتى لا تستطيع أدوات الفحص تحديد وقت تحديدك لمورد سلسلة حيث يجب تحديد لون. ويعني هذا أنّه قد يتم عرض تطبيقك بشكل غير صحيح أو قد يتعذّر تشغيله على الإطلاق، حتى في حال استخدام فحص الرموز.

تتيح لك التعليقات التوضيحية تقديم تلميحات حول أدوات فحص الرمز، مثل Lint، للمساعدة في اكتشاف مشاكل الرموز الأكثر دقة. تتمّ إضافة التعليقات التوضيحية كعلامات بيانات وصفية ترفقها بالمتغيرات والمَعلمات والقيم التي يرجعها لفحص القيم المعروضة للطريقة والمَعلمات التي تم تمريرها والمتغيرات المحلية والحقول. وعند استخدام التعليقات التوضيحية مع أدوات فحص الرمز، يمكن أن تساعدك في اكتشاف مشاكل مثل استثناءات المؤشر الفارغ وتعارض أنواع الموارد.

يتيح Android استخدام مجموعة متنوعة من التعليقات التوضيحية من خلال مكتبة التعليقات التوضيحية في Jetpack. يمكنك الوصول إلى المكتبة من خلال حزمة androidx.annotation.

ملاحظة: إذا كانت الوحدة تعتمد على معالج تعليقات توضيحية، عليك استخدام إعداد التبعية kapt أو ksp للغة Kotlin أو إعداد التبعية annotationProcessor للغة Java لإضافة تلك الاعتمادية.

إضافة تعليقات توضيحية إلى مشروعك

لتفعيل التعليقات التوضيحية في مشروعك، أضِف تبعية androidx.annotation:annotation إلى مكتبتك أو تطبيقك. يتم التحقّق من أي تعليقات توضيحية تضيفها عند تشغيل فحص الرموز أو مهمة lint.

إضافة تبعية مكتبة التعليقات التوضيحية في Jetpack

تم نشر مكتبة التعليقات التوضيحية في Jetpack على مستودع Maven من Google. لإضافة مكتبة Jetpack Anotations إلى مشروعك، عليك تضمين السطر التالي في مجموعة dependencies من ملفك build.gradle أو build.gradle.kts:

Kotlin

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

رائع

dependencies {
    implementation 'androidx.annotation:annotation:1.7.1'
}
بعد ذلك، في شريط الأدوات أو إشعار المزامنة الذي يظهر، انقر على المزامنة الآن.

إذا كنت تستخدم التعليقات التوضيحية في وحدة مكتبتك، سيتم تضمين التعليقات التوضيحية كجزء من عنصر "أرشيف Android" (AAR) بتنسيق XML في ملف annotations.zip. لا تؤدي إضافة تبعية androidx.annotation إلى إضافة تبعية لأيّ من مستخدمي مكتبتك.

ملاحظة: إذا كنت تستخدم مكتبات أخرى من Jetpack، قد لا تحتاج إلى إضافة تبعية androidx.annotation. نظرًا لأن العديد من مكتبات Jetpack الأخرى تعتمد على "مكتبة التعليقات التوضيحية"، قد تتمكن من الوصول إلى التعليقات التوضيحية.

للحصول على قائمة كاملة بالتعليقات التوضيحية المضمّنة في مستودع Jetpack، يمكنك إما مراجعة مرجع مكتبة Jetpack التعليقات التوضيحية أو استخدام ميزة الإكمال التلقائي لعرض الخيارات المتاحة لعبارة import androidx.annotation..

إجراء فحوصات الرموز

لبدء فحص الرمز من "استوديو Android"، والذي يشمل التحقّق من صحة التعليقات التوضيحية وفحص الوبر التلقائي، اختَر تحليل > فحص الرمز من القائمة. يعرض استوديو Android رسائل التعارض للإبلاغ عن المشاكل المحتملة التي تتعارض فيها التعليمات البرمجية مع التعليقات التوضيحية واقتراح الحلول المحتملة.

يمكنك أيضًا فرض التعليقات التوضيحية من خلال تشغيل مهمة lint باستخدام سطر الأوامر. وعلى الرغم من أنّ ذلك قد يكون مفيدًا للإبلاغ عن المشاكل باستخدام خادم الدمج المستمر، لا تفرض مَهمّة lint تعليقات توضيحية على القيمة الفارغة (موضَّحة في القسم التالي)، بل يتم تنفيذ ذلك فقط من خلال "استوديو Android". لمزيد من المعلومات حول تفعيل وتشغيل عمليات فحص الوبر، يمكنك الاطّلاع على تحسين الرمز البرمجي باستخدام عمليات فحص الوبر.

وبالرغم من أن تعارض التعليقات التوضيحية ينشأ تحذيرات، فإن هذه التحذيرات لا تمنع تطبيقك من تجميع.

التعليقات التوضيحية التي لا تحتوي على قيم

يمكن أن تكون التعليقات التوضيحية الخالية من البيانات مفيدة في التعليمات البرمجية لـ Java لفرض ما إذا كان يمكن أن تكون القيم فارغة. وهي أقل فائدة في لغة البرمجة Kotlin، حيث تم تضمين قواعد إمكانية القيم الفارغة والتي يتم فرضها في وقت التجميع.

أضِف تعليقات @Nullable و@NonNull التوضيحية للتحقّق من القيمة الفارغة لمتغيّر أو مَعلمة أو قيمة إرجاع معيّنة. يشير التعليق التوضيحي @Nullable إلى متغيّر أو مَعلمة أو قيمة إرجاع يمكن أن تكون فارغة. تشير القيمة @NonNull إلى متغيّر أو مَعلمة أو قيمة إرجاع لا يمكن أن تكون فارغة.

على سبيل المثال، إذا تم تمرير متغيّر محلي يحتوي على قيمة فارغة كمَعلمة إلى طريقة تتضمّن تعليق @NonNull التوضيحي المرفَق بهذه المَعلمة، سيؤدي إنشاء الرمز إلى إنشاء تحذير يشير إلى حدوث تعارض غير خالٍ. بالإضافة إلى ذلك، تؤدي محاولة الرجوع إلى نتيجة طريقة تم وضع علامة @Nullable عليها بدون التحقق أولاً مما إذا كانت النتيجة "خالية" تؤدي إلى إنشاء تحذير بشأن القيمة الفارغة. لا تستخدم @Nullable إلا في القيمة المعروضة لأي طريقة إذا كان يجب تحديد قيمة فارغة في كل استخدام لها.

يوضح المثال التالي قابلية عدم القيمة عمليًا. لا يستفيد رمز نموذج Kotlin من التعليق التوضيحي @NonNull لأنه تتم إضافته تلقائيًا إلى رمز البايت الذي تم إنشاؤه عند تحديد نوع غير قابل للقيم. يستفيد مثال جافا من التعليق التوضيحي @NonNull على المعلمتين context وattrs للتحقق من أن قيم المعلمات التي تم تمريرها ليست فارغة. تتحقّق أيضًا من أنّ الطريقة onCreateView() نفسها لا تعرض قيمة فارغة:

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

تحليل القيم الفارغة

يتيح "استوديو Android" إجراء تحليل لقيم القيم الفارغة لاستنتاج تلقائيًا وإدراج تعليقات توضيحية فارغة في رمزك. يفحص تحليل القيم الفارغة العقود خلال التسلسلات الهرمية للطريقة في الترميز لرصد ما يلي:

  • طرق الاتصال التي يمكن أن تعرض قيمة فارغة.
  • الطرق التي يجب ألا تعرض قيمة فارغة.
  • المتغيّرات، مثل الحقول والمتغيّرات المحلية والمَعلمات التي يمكن أن تكون فارغة.
  • المتغيّرات، مثل الحقول والمتغيّرات المحلية والمَعلمات التي لا يمكن أن تحتوي على قيمة فارغة.

بعد ذلك، يدرج التحليل تلقائيًا التعليقات التوضيحية الفارغة المناسبة في المواقع التي تم رصدها.

لإجراء تحليل قابلية القيم الفارغة في "استوديو Android"، اختَر تحليل > استنتاج القيمة الخالية. يدرج "استوديو Android" التعليقات التوضيحية @Nullable و@NonNull لنظام التشغيل Android في المواقع التي يتم اكتشافها في الرمز. بعد إجراء تحليل فارغ، من الممارسات الجيدة التحقّق من التعليقات التوضيحية التي تم إدخالها.

ملاحظة: عند إضافة تعليقات توضيحية فارغة، قد تقترح ميزة "الإكمال التلقائي" التعليقات التوضيحية @Nullable و@NotNull لـ IntelliJ بدلاً من التعليقات التوضيحية الفارغة في Android، وقد يتم استيراد المكتبة المقابلة تلقائيًا. مع ذلك، تبحث أداة التحقّق من الوبر في "استوديو Android" فقط عن التعليقات التوضيحية الفارغة في Android. عند التحقق من التعليقات التوضيحية، تأكَّد من أنّ مشروعك يستخدم التعليقات التوضيحية الفارغة في Android كي تتمكن أداة التحقق من الوبر من إشعارك بشكل صحيح أثناء فحص الرمز.

التعليقات التوضيحية للموارد

يمكن أن يكون التحقّق من أنواع الموارد مفيدًا لأنّ مراجع Android التي تشير إلى الموارد، مثل موارد السحب والسلسلة، يتم تمريرها كأعداد صحيحة.

الرمز الذي يُتوقّع من معلَمة أن تشير إلى نوع محدّد من الموارد، مثل 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 باستخدام تنسيق التعليقات التوضيحية نفسه وتشغيلها أثناء فحص الرمز.

إذا كانت مَعلمتك تدعم أنواع موارد متعدّدة، يمكنك وضع أكثر من تعليق توضيحي واحد لنوع المورد على معلَمة معيّنة. استخدِم @AnyRes للإشارة إلى أنّ المَعلمة التي تتضمّن تعليقات توضيحية يمكن أن تكون أي نوع من موارد R.

مع أنّه يمكنك استخدام @ColorRes لتحديد أنّ المَعلمة يجب أن تكون موردًا للألوان، لا يمكن التعرّف على العدد الصحيح للون (بالتنسيق RRGGBB أو AARRGGBB) كمورد لون. بدلاً من ذلك، يمكنك استخدام التعليق التوضيحي @ColorInt للإشارة إلى أن المعلَمة يجب أن تكون عددًا صحيحًا للون. ستضع أدوات التصميم علامة على الرموز غير الصحيحة التي تمرِّر معرّف مورد ألوان مثل android.R.color.black، بدلاً من عدد صحيح للون، إلى الطرق التي تتضمّن تعليقات توضيحية.

التعليقات التوضيحية لسلاسل المحادثات

تتحقّق التعليقات التوضيحية لسلاسل المحادثات مما إذا كان يتم استدعاء طريقة من نوع معيّن من سلاسل المحادثات. التعليقات التوضيحية للسلاسل التالية متوافقة:

تتعامل أدوات الإنشاء مع تعليقات @MainThread و@UiThread التوضيحية كتعليقات قابلة للتبادل، لذا يمكنك استدعاء طُرق @UiThread من طرق @MainThread والعكس صحيح. ومع ذلك، من الممكن أن تختلف سلسلة تعليمات واجهة المستخدم عن سلسلة التعليمات الرئيسية، وذلك في حال تطبيقات النظام ذات طرق العرض المتعددة على سلاسل المحادثات المختلفة. لذلك، يجب إضافة تعليقات توضيحية إلى الطرق المرتبطة بالتسلسل الهرمي لطريقة عرض التطبيق باستخدام @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 مما إذا كانت قيمة المعلمة العائمة أو قيمة المعلمة المزدوجة ضمن نطاق محدد من قيم النقطة العائمة. يشير المثال التالي إلى أنّ المعلَمة 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) من أنّ المصفوفة تحتوي على ثلاث قيم بالضبط.

يشير المثال التالي إلى أنّ مصفوفة location يجب أن تحتوي على عنصر واحد على الأقل:

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

بالنسبة إلى الأذونات المتعلّقة بالأغراض، ضَع متطلب الإذن في حقل السلسلة الذي يحدِّد اسم إجراء النية:

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

للحصول على أذونات موفّري المحتوى الذين يحتاجون إلى أذونات منفصلة للوصول إلى المحتوى للقراءة والكتابة، عليك تضمين كل من متطلبات الأذونات في تعليق توضيحي @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) إذنًا غير مباشر في الغرض الذي يتم تمريره إلى الطريقة:

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) عند تمرير غرض بدون الأذونات المناسبة إلى الطريقة، كما هو موضّح في الشكل 1.

الشكل 1. التحذير الذي يتم إنشاؤه من التعليق التوضيحي للأذونات غير المباشرة على طريقة startActivity(Intent)

تعرض أدوات الإصدار تحذيرًا في startActivity(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). يُجري كلاهما نفس فحص الوبر.

حصر إمكانية الوصول إلى واجهة برمجة تطبيقات

يشير التعليق التوضيحي @RestrictTo إلى أنّ الوصول إلى واجهة برمجة التطبيقات التي تتضمّن تعليقات توضيحية (الحزمة أو الفئة أو الطريقة) محدود، على النحو التالي:

الفئات الفرعية

استخدِم نموذج التعليقات التوضيحية @RestrictTo(RestrictTo.Scope.SUBCLASSES) لحصر الوصول إلى واجهة برمجة التطبيقات على الفئات الفرعية فقط.

لا يمكن الوصول إلى واجهة برمجة التطبيقات هذه إلا للصفوف التي تُضيف تعليقات توضيحية. إنّ عنصر تعديل لغة protected في Java غير محدود بدرجة كافية، لأنّه يسمح بالوصول من فئات غير مرتبطة ببعضها ضمن الحزمة نفسها. هناك أيضًا حالات تريد فيها ترك إحدى الطرق public لتوفير المرونة في المستقبل، لأنّه لا يمكنك أبدًا إجراء protected طريقة تم إلغاؤها سابقًا public، ولكنك تريد تقديم تلميح بأنّ الفئة مخصّصة للاستخدام ضمن الفئة أو من الفئات الفرعية فقط.

مكتبات

استخدِم نموذج التعليقات التوضيحية @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) لحظر وصول واجهة برمجة التطبيقات إلى مكتباتك فقط.

يمكن فقط لرمز مكتبتك الوصول إلى واجهة برمجة التطبيقات التي تمت إضافة تعليقات توضيحية إليها. يتيح لك ذلك تنظيم الرمز الخاص بك في أي تدرّج هرمي تريده للحزمة، فضلاً عن مشاركة الرمز بين مجموعة من المكتبات ذات الصلة. هذا الخيار متاح حاليًا لمكتبات Jetpack التي تحتوي على الكثير من رموز التنفيذ التي لا يُقصد استخدامها للاستخدام الخارجي، ولكن يجب أن تكون public لتتمكّن من مشاركتها في مكتبات Jetpack التكميلية المختلفة.

الاختبار

استخدِم نموذج التعليقات التوضيحية @RestrictTo(RestrictTo.Scope.TESTS) لمنع المطوّرين الآخرين من الوصول إلى واجهات برمجة التطبيقات التجريبية.

يمكن استخدام رمز الاختبار فقط للوصول إلى واجهة برمجة التطبيقات التي تمت إضافة تعليقات توضيحية إليها. وهذا يمنع المطوّرين الآخرين من استخدام واجهات برمجة التطبيقات لأغراض التطوير فقط.