يمكن أن يساعدك استخدام أدوات فحص الرموز، مثل lint، في العثور على
المشاكل وتحسين الرمز، ولكن لا يمكن لأدوات الفحص استنتاج الكثير من المعلومات. على سبيل المثال، تستخدم أرقام تعريف موارد Androidint
لتحديد السلاسل والرسومات والألوان وأنواع الموارد الأخرى،
لذلك لا يمكن لأدوات الفحص معرفة ما إذا كنت قد حدّدت مورد سلسلة في المكان الذي كان يجب فيه تحديد لون. يعني هذا الموقف أنّه قد يتم عرض تطبيقك بشكل غير صحيح أو قد يتعذّر تشغيله على الإطلاق،
حتى إذا كنت تستخدم ميزة فحص الرموز البرمجية.
تتيح لك التعليقات التوضيحية تقديم نصائح لأدوات فحص الرموز البرمجية، مثل 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
:
Kotlin
dependencies { implementation("androidx.annotation:annotation:1.9.1") }
رائع
dependencies { implementation 'androidx.annotation:annotation:1.9.1' }
إذا كنت تستخدم تعليقات توضيحية في وحدة مكتبتك، يتم تضمين التعليقات التوضيحية كجزء من ملف annotations.zip
بتنسيق XML ضمن ملف ملف أرشيف Android (AAR). لا تؤدي إضافة تبعية
androidx.annotation
إلى إدخال تبعية لأي مستخدمين تابعين
لمكتبتك.
ملاحظة: إذا كنت تستخدم مكتبات Jetpack أخرى،
قد لا تحتاج إلى إضافة التبعية androidx.annotation
. بما أنّ العديد من مكتبات
Jetpack الأخرى تعتمد على مكتبة التعليقات التوضيحية، قد يكون بإمكانك الوصول إلى التعليقات
التوضيحية.
للحصول على قائمة كاملة بالتعليقات التوضيحية المضمّنة في مستودع Jetpack، يمكنك الاطّلاع على
مرجع مكتبة التعليقات التوضيحية في Jetpack أو استخدام ميزة الإكمال التلقائي لعرض الخيارات المتاحة لعبارة
import androidx.annotation.
.
تنفيذ عمليات فحص الرموز البرمجية
لبدء فحص الرمز من Android Studio، والذي يتضمّن التحقّق من التعليقات التوضيحية وفحص lint التلقائي، اختَر تحليل > فحص الرمز من الجدول. يعرض Android Studio رسائل تعارض لرصد المشاكل المحتمَلة التي يتعارض فيها الرمز البرمجي مع التعليقات التوضيحية واقتراح حلول محتملة.
يمكنك أيضًا فرض التعليقات التوضيحية من خلال تنفيذ مهمة
lint
باستخدام سطر الأوامر. على الرغم من أنّ هذا قد يكون مفيدًا للإبلاغ عن المشاكل
باستخدام خادم دمج مستمر، لا تفرض مهمة lint
استخدام التعليقات التوضيحية
للقيمة الخالية (الموضَّحة في القسم التالي)، بل ينفّذ Android Studio ذلك فقط. لمزيد من
المعلومات عن تفعيل عمليات فحص lint
وتنفيذها، اطّلِع على مقالة تحسين الرمز البرمجي باستخدام عمليات فحص lint.
على الرغم من أنّ تعارضات التعليقات التوضيحية تؤدي إلى ظهور تحذيرات، لا تمنع هذه التحذيرات compilingتطبيقك.
التعليقات التوضيحية للقيمة الخالية
يمكن أن تكون التعليقات التوضيحية حول القيمة الخالية مفيدة في رمز Java لفرض ما إذا كان يمكن أن تكون القيم خالية. وهي أقل فائدة في رمز Kotlin، لأنّ Kotlin تتضمّن قواعد إمكانية قبول القيم الفارغة التي يتم فرضها في وقت الترجمة.أضِف التعليقَين التوضيحيَين @Nullable
و
@NonNull
للتحقّق من قيمة فارغة لمتغيّر أو مَعلمة أو قيمة معروضة. يشير التعليق التوضيحي @Nullable
إلى متغيّر أو مَعلمة أو قيمة معروضة يمكن أن تكون فارغة.
يشير الرمز @NonNull
إلى متغيّر أو مَعلمة أو قيمة معروضة لا يمكن أن تكون فارغة.
على سبيل المثال، إذا تم تمرير متغيّر محلي يحتوي على قيمة فارغة كمَعلمة إلى طريقة
مع إرفاق التعليق التوضيحي @NonNull
بهذه المَعلمة، يؤدي إنشاء الرمز إلى توليد
تحذير يشير إلى تعارض غير فارغ. بالإضافة إلى ذلك، يؤدي محاولة الإشارة إلى نتيجة
طريقة تم وضع علامة @Nullable
عليها بدون التحقّق أولاً مما إذا كانت النتيجة فارغة إلى توليد
تحذير فارغ. لا تستخدِم @Nullable
إلا على قيمة الإرجاع الخاصة بطريقة ما
إذا كان يجب التحقّق صراحةً من عدم تساوي كل استخدام للطريقة مع القيمة الخالية.
يوضّح المثال التالي حالة عدم السماح بالقيمة الخالية. لا يستفيد نموذج رمز Kotlin من
التعليق التوضيحي @NonNull
لأنّه تتم إضافته تلقائيًا إلى الرمز الثنائي الذي تم إنشاؤه
عند تحديد نوع غير قابل للقيمة الخالية. يستفيد مثال Java من التعليق التوضيحي @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 Studio إجراء تحليل للقيمة الخالية من القيمة من أجل الاستنتاج تلقائيًا وإدراج التعليقات التوضيحية للقيمة الخالية من القيمة في الرمز البرمجي. يفحص تحليل قابلية العدم العقود في جميع التسلسلات الهرمية للطرق في الرمز البرمجي لرصد ما يلي:
- استدعاء طرق يمكنها عرض قيمة فارغة
- الطرق التي يجب ألا تُعرِض قيمة فارغة
- المتغيّرات، مثل الحقول والمتغيّرات المحلية والمَعلمات، التي يمكن أن تكون فارغة
- المتغيّرات، مثل الحقول والمتغيّرات المحلية والمَعلمات، التي لا يمكنها احتواء قيمة فارغة
بعد ذلك، يُدرج التحليل تلقائيًا التعليقات التوضيحية المناسبة للقيم الخالية في المواقع الجغرافية التي تم رصدها.
لإجراء تحليل للقيمة الخالية في "استوديو Android"، اختَر تحليل >
استنتاج القيمة الخالية. يُدرج Android Studio التعليقَين التوضيحيَين @Nullable
و@NonNull
في Android في
المواقع التي تم رصدها في الرمز البرمجي. بعد إجراء تحليل للقيم الخالية، من الممارسات الجيدة التحقّق من
التعليقات التوضيحية المُدرَجة.
ملاحظة: عند إضافة تعليقات توضيحية عن القيم الخالية، قد يقترح خيار الإكمال التلقائي
تعليقات توضيحية IntelliJ
@Nullable
و
@NotNull
بدلاً من تعليقات توضيحية Android عن القيم الخالية
وقد يستورد تلقائيًا المكتبة المقابلة. ومع ذلك، لا يبحث مدقّق الأخطاء lint في "استوديو Android" سوى عن التعليقات التوضيحية للقيم الخالية في Android. عند التحقّق من التعليقات التوضيحية
، تأكَّد من أنّ مشروعك يستخدم التعليقات التوضيحية للقيم الخالية في Android حتى يتمكّن فحص lint من إعلامك بشكل صحيح أثناء فحص الرمز.
التعليقات التوضيحية للموارد
يمكن أن يكون التحقّق من أنواع الموارد مفيدًا لأنّ نظام التشغيل Android يُحيل إلى الموارد، مثل موارد drawable وstring، ويتم تمريرها كأرقام صحيحة.
يمكن تمرير الرمز الذي يتوقّع أن تشير المَعلمة إلى نوع معيّن من الموارد، مثل String
،
إلى نوع المرجع المتوقّع int
، ولكنّه يشير في الواقع إلى نوع مختلف
من الموارد، مثل مورد R.string
.
على سبيل المثال، أضِف تعليقات توضيحية @StringRes
لمحاولة معرفة ما إذا كانت مَعلمة المورد تحتوي على مرجع R.string
، كما هو موضّح هنا:
Kotlin
abstract fun setTitle(@StringRes resId: Int)
Java
public abstract void setTitle(@StringRes int resId)
أثناء فحص الرمز، يُنشئ التعليق التوضيحي تحذيرًا في حال عدم تمرير مرجع R.string
في المَعلمة.
يمكن
إضافة تعليقات توضيحية لأنواع الموارد الأخرى، مثل @DrawableRes
و@DimenRes
و@ColorRes
و@InterpolatorRes
، باستخدام تنسيق التعليق التوضيحي نفسه وتشغيلها أثناء فحص الرمز.
إذا كانت المَعلمة
تتوافق مع أنواع موارد متعدّدة، يمكنك وضع أكثر من تعليق توضيحي لنوع واحد من الموارد على مَعلمة معيّنة. استخدِم @AnyRes
للإشارة إلى أنّ المَعلمة المُشارَك فيها تعليقات توضيحية يمكن أن تكون أيّ نوع من موارد R
.
على الرغم من أنّه يمكنك استخدام @ColorRes
لتحديد أنّ المَعلمة повинна تكون موردًا للألوان، لا يتم التعرّف على عدد صحيح للألوان (بتنسيق RRGGBB
أو
AARRGGBB
) كمورد ألوان. بدلاً من ذلك، استخدِم التعليق التوضيحي @ColorInt
لتحديد أنّ المَعلمة يجب أن تكون عددًا صحيحًا للون. ستُبلغ أدوات الإنشاء عن الرمز غير الصحيح الذي
يُمرِّر معرّف مورد لون مثل android.R.color.black
بدلاً من عدد صحيح للّون
إلى الطرق المُشارَك فيها تعليقات توضيحية.
التعليقات التوضيحية لسلسلة المحادثات
تتحقّق التعليقات التوضيحية لسلسلة المحادثات ممّا إذا تم استدعاء طريقة من نوع معيّن من سلسلة محادثات. يمكن استخدام التعليقات التوضيحية التالية في السلسلة:
تتعامل أدوات الإنشاء مع التعليقات التوضيحية @MainThread
و
@UiThread
على أنّها قابلة للتبديل، لذا يمكنك استدعاء طرق @UiThread
من طرق @MainThread
والعكس صحيح. ومع ذلك، من الممكن أن يختلف مؤشر تسلسل واجهة المستخدم عن مؤشر التسلسل الرئيسي، في حال تطبيقات النظام التي تتضمّن طرق عرض متعددة
على مؤشرات تسلسل مختلفة. لذلك، عليك إضافة تعليقات توضيحية إلى الطرق المرتبطة بالعرض الهرمي لعرض التطبيق
باستخدام @UiThread
وإضافة تعليقات توضيحية إلى الطرق المرتبطة بدورة حياة التطبيق فقط باستخدام
@MainThread
.
إذا كانت جميع الطرق في فئة تتشارك متطلبات المعالجة المتعدّدة ال threads نفسها، يمكنك إضافة تعليق توضيحي واحد لسلسلة رسائل إلى الفئة للتحقّق من أنّه يتم استدعاء جميع الطرق في الفئة من النوع نفسه من سلسلة الرسائل.
من الاستخدامات الشائعة للتعليقات التوضيحية للخيوط هي التحقّق من أنّ الطرق أو الفئات التي تمّت إضافة تعليقات توضيحية إليها باستخدام @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.
تنشئ أدوات الإنشاء التحذير بشأن 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
إلى كل @CheckResult
طريقة غير فارغة، أضِف التعليق التوضيحي لتوضيح نتائج @CheckResult
الطرق التي قد تكون مربكة.
على سبيل المثال، غالبًا ما يظن مطوّرو Java الجدد عن طريق الخطأ أنّ <String>.trim()
يزيل المسافات البيضاء من السلسلة الأصلية. عند وضع تعليق توضيحي
على الطريقة باستخدام @CheckResult
، يتم وضع علامة على استخدامات <String>.trim()
حيث لا ينفّذ المُرسِل أي إجراء مع القيمة المعروضة في الطريقة.
يوضّح المثال التالي تعليقًا توضيحيًا على الطريقة checkPermissions()
للتحقّق مما إذا كان يتمّ إشارة
فعليًا إلى القيمة المعروضة في طريقة الإخراج. ويُحدِّد أيضًا enforcePermission()
method كطريقة يمكن أن نقترحها على المطوِّر كبديل:
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
لتأكيد أنّ الطريقة التي تلغي طريقة أخرى تستدعي تنفيذ super للطريقة.
يُعلِق المثال التالي onCreate()
تعليقًا توضيحيًا لضمان أنّ أي تنفيذات لطريقة super.onCreate()
تُطلِق super.onCreate()
:
Kotlin
@CallSuper override fun onCreate(savedInstanceState: Bundle?) { }
Java
@CallSuper protected void onCreate(Bundle savedInstanceState) { }
التعليقات التوضيحية لأنواع البيانات
تتحقّق التعليقات التوضيحية لنوع البيانات من ما إذا كانت مَعلمة معيّنة أو قيمة معروضة أو حقل معيّن يشير إلى مجموعة معيّنة من الثوابت. وتتيح هذه العناصر أيضًا ميزة "إكمال الرموز البرمجية" لتلقائيًا عرض الثوابت المسموح بها.
استخدِم التعليقَين التوضيحيَين @IntDef
و
@StringDef
لإنشاء تعليقات توضيحية مُدرَجة لمجموعات الأعداد الصحيحة والسلاسل من أجل التحقّق من صحة
أنواع أخرى من مراجع الرموز البرمجية.
تستخدِم التعليقات التوضيحية لأنواع البيانات @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، مع تحديد الفئة
التي تُجري طلبات الاستدلال.
لمزيد من المعلومات حول كيفية تصغير الرمز البرمجي وتحديد الرمز الذي لا تتم إزالته، اطّلِع على مقالة تصغير حجم تطبيقك وإخفاء مفاتيح فك التشفير وتحسينه.
التعليقات التوضيحية لمستوى عرض الرمز
استخدِم التعليقات التوضيحية التالية للإشارة إلى مستوى ظهور أجزاء معيّنة من الرمز البرمجي، مثل methods أو classes أو fields أو packages.
إظهار الرمز البرمجي للاختبار
يشير التعليق التوضيحي
@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)
لتقييد
إمكانية وصول واجهة برمجة التطبيقات إلى الفئات الفرعية فقط.
لا يمكن الوصول إلى واجهة برمجة التطبيقات هذه إلا من خلال الصفوف التي تمديدها من الصف المُشارَك. لا يكون معدِّل Java
protected
تقييديًا بما يكفي، لأنّه يسمح بالوصول
من فئات غير ذات صلة ضمن الحزمة نفسها. هناك أيضًا حالات تريد فيها ترك public
public
لتوفير المرونة في المستقبل، لأنّه لا يمكنك أبدًا إنشاء public
protected
تم تجاوزه سابقًا، ولكنك تريد تقديم تلميح مفاده أنّ الفئة مخصّصة للاستخدامات داخل الفئة أو من الفئات الفرعية فقط.
المكتبات
استخدِم نموذج التعليق التوضيحي @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
لمحاولة
الحد من إمكانية وصول واجهة برمجة التطبيقات إلى مكتباتك فقط.
لا يمكن سوى لرمز مكتبتك الوصول إلى واجهة برمجة التطبيقات المُشارَك عليها تعليقات توضيحية. يتيح لك ذلك ليس فقط تنظيم رموذك
في أي تسلسل هرمي للحزمة تريده، بل يتيح لك أيضًا مشاركة
الرمز بين مجموعة من المكتبات ذات الصلة. يتوفّر هذا الخيار حاليًا لمكتبات
Jetpack التي تحتوي على الكثير من رموز التنفيذ غير المخصّصة للاستخدام الخارجي، ولكن يجب أن تكون
public
لمشاركتها في مكتبات Jetpack التكميلية المختلفة.
الاختبار
استخدِم نموذج التعليق التوضيحي @RestrictTo(RestrictTo.Scope.TESTS)
لمنع المطوّرين الآخرين
من الوصول إلى واجهات برمجة التطبيقات الخاصة بالاختبار.
لا يمكن الوصول إلى واجهة برمجة التطبيقات المُشارَك فيها تعليقات توضيحية إلا من خلال رمز الاختبار. ويمنع ذلك المطوّرين الآخرين من استخدام واجهات برمجة التطبيقات المخصّصة للتطوير والتي تريد استخدامها لأغراض الاختبار فقط.