تعرض هذه الصفحة العديد من أفضل الممارسات والاقتراحات المتعلّقة بالبنية. ويمكنك استخدامها لتحسين جودة تطبيقك وثباته وقابليته للتوسع. وتسهِّل هذه الميزة أيضًا صيانة تطبيقك واختباره.
تم تجميع أفضل الممارسات أدناه حسب الموضوع. ولكلّ منها أولوية تعكس مدى اقتراح الفريق له. في ما يلي قائمة الأولويات:
- يُنصح به بشدة: يجب تنفيذ هذه الممارسة ما لم تتعارض بشكل أساسي مع نهجك.
- إجراء مقترَح: من المرجّح أن يؤدي هذا الإجراء إلى تحسين تطبيقك.
- اختياري: يمكن أن تؤدي هذه الممارسة إلى تحسين تطبيقك في ظروف معيّنة.
التصميم المتعدّد الطبقات
تفضّل البنية الطبقية التي ننصح بها فصل المهام. وهو يقود واجهة المستخدم من نماذج البيانات، ويلتزم بالمصدر الواحد لمبدأ الحقيقة، ويتّبِع مبادئ تدفق البيانات أحادي الاتجاه. في ما يلي بعض أفضل الممارسات المتعلّقة بالبنية المتعدّدة الطبقات:
مقترَح | الوصف |
---|---|
استخدِم طبقة بيانات محدّدة بوضوح.
يُنصح بشدة باستخدامه |
تعرِض طبقة البيانات بيانات التطبيق لبقية أقسام التطبيق، كما تحتوي على الغالبية العظمى من منطق النشاط التجاري لتطبيقك.
|
استخدِم طبقة واجهة مستخدم محدّدة بوضوح.
يُنصح به بشدة |
تعرِض طبقة واجهة المستخدم بيانات التطبيق على الشاشة وتشكّل نقطة التفاعل الأساسية للمستخدم.
|
يجب أن تعرض طبقة البيانات بيانات التطبيق باستخدام مستودع.
يُنصح بشدة باستخدامه |
يجب ألا تتفاعل المكوّنات في طبقة واجهة المستخدم، مثل العناصر القابلة للتجميع أو الأنشطة أو نماذج العرض، مباشرةً مع مصدر بيانات. أمثلة على مصادر البيانات:
|
استخدِم عمليات التشغيل المتعدّد والمهام.
يُنصح بشدة باستخدامه |
استخدام الكوروتينات والتدفقات للتواصل بين الطبقات |
استخدِم طبقة نطاق.
مُقترَح في التطبيقات الكبيرة |
استخدِم طبقة النطاق، وحالات الاستخدام، إذا كنت بحاجة إلى إعادة استخدام منطق النشاط التجاري الذي يتفاعل مع طبقة البيانات في نماذج عرض متعددة، أو إذا كنت تريد تبسيط تعقيد منطق النشاط التجاري لنموذج عرض معيّن. |
طبقة واجهة المستخدم
ودور طبقة واجهة المستخدم هو عرض بيانات التطبيق على الشاشة وتكون بمثابة النقطة الأساسية لتفاعل المستخدم. وفي ما يلي بعض أفضل الممارسات لطبقة واجهة المستخدم:
مقترَح | الوصف |
---|---|
اتّبِع التدفق أحادي الاتجاه للبيانات (UDF).
يُنصح بشدة باستخدامه |
اتّبِع مبادئ تدفق البيانات أحادي الاتجاه (UDF)، حيث تعرض نماذج ViewModel حالة واجهة المستخدم باستخدام نمط المراقب وتتلقّى إجراءات من واجهة المستخدم من خلال طلبات الاتصال بالطريقة. |
استخدِم AAC ViewModels إذا كانت مزاياها تنطبق على تطبيقك.
يُنصح بشدة باستخدامه |
استخدِم ViewModels في تنسيق AAC لمعالجة منطق النشاط التجاري، واسترِجِع بيانات التطبيق لعرض حالة واجهة المستخدم على واجهة المستخدم (Compose أو Android Views).
يمكنك الاطّلاع على مزيد من أفضل ممارسات ViewModel هنا. اطّلِع على مزايا ViewModels هنا. |
استخدِم مجموعة حالات واجهة المستخدم المراعية لرحلة المستخدِم.
يُنصح بشدة باستخدامه |
جمع حالة واجهة المستخدم من واجهة المستخدم باستخدام أداة إنشاء وظائف التشغيل المتعدّد المتوافقة مع دورة الحياة: repeatOnLifecycle في نظام View وcollectAsStateWithLifecycle في Jetpack Compose
اطّلِع على مزيد من المعلومات عن اطّلِع على مزيد من المعلومات عن |
لا تُرسِل الأحداث من ViewModel إلى واجهة المستخدِم.
يُنصح بشدة باستخدامه |
معالجة الحدث فورًا في ViewModel وإجراء تعديل على الحالة نتيجةً لمعالجة الحدث. يمكنك الاطّلاع على مزيد من المعلومات عن أحداث واجهة المستخدِم هنا. |
استخدِم تطبيقًا لنشاط واحد.
مُقترَح |
استخدِم أجزاء التنقّل أو إنشاء مسار التنقّل للتنقّل بين الشاشات وإنشاء رابط لصفحة معيّنة في تطبيقك إذا كان تطبيقك يتضمّن أكثر من شاشة واحدة. |
استخدِم Jetpack Compose.
مُقترَح |
استخدِم Jetpack Compose لإنشاء تطبيقات جديدة للهواتف والأجهزة اللوحية والأجهزة القابلة للطي ونظام التشغيل Wear OS. |
يوضّح المقتطف التالي كيفية جمع حالة واجهة المستخدم بطريقة تراعي دورة الحياة:
المشاهدات
class MyFragment : Fragment() {
private val viewModel: MyViewModel by viewModel()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect {
// Process item
}
}
}
}
}
إنشاء
@Composable
fun MyScreen(
viewModel: MyViewModel = viewModel()
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
}
ViewModel
تتحمّل ViewModels مسؤولية توفير حالة واجهة المستخدم والوصول إلى طبقة البيانات. في ما يلي بعض أفضل الممارسات المتعلّقة بـ ViewModels:
مقترَح | الوصف |
---|---|
يجب أن تكون نماذج العرض مستقلة عن دورة حياة Android.
يُنصح بشدة باستخدامه |
يجب ألا تتضمن ViewModels إشارة إلى أي نوع مرتبط بدورة الحياة. لا تُمرِّر Activity, Fragment, Context أو Resources كعنصر تابع.
وإذا احتاج أحد العناصر إلى Context في ViewModel، عليك تقييم ما إذا كان ذلك في الطبقة الصحيحة. |
استخدِم عمليات التشغيل المتعدّد والمهام.
يُنصح بشدة باستخدامه |
يتفاعل ViewModel مع طبقات البيانات أو النطاقات باستخدام:
|
استخدِم ViewModels على مستوى الشاشة.
يُنصح به بشدة |
لا تستخدم ViewModels في الأجزاء القابلة لإعادة الاستخدام من واجهة المستخدم. عليك استخدام ViewModels في:
|
استخدِم فئات حاملي الحالة العادية في مكونات واجهة المستخدم القابلة لإعادة الاستخدام.
يُنصح به بشدة |
استخدِم فئات حاملي الحالة البسيطة للتعامل مع التعقيد في مكونات واجهة المستخدم القابلة لإعادة الاستخدام. من خلال إجراء ذلك، يمكن رفع الحالة والتحكّم فيها خارجيًا. |
لا تستخدِم AndroidViewModel .
إجراءات ننصح بها |
استخدِم فئة ViewModel ، وليس AndroidViewModel . يجب عدم استخدام فئة Application في ViewModel. بدلاً من ذلك، انقل التبعية إلى واجهة المستخدم أو طبقة البيانات. |
اعرض حالة واجهة المستخدم.
إجراء ننصح به |
يجب أن تعرض نماذج العرض البيانات لواجهة المستخدم من خلال سمة واحدة تُسمى uiState . إذا كانت واجهة المستخدم تعرض أجزاء متعددة وغير مرتبطة من البيانات، يمكن للجهاز الافتراضي عرض خصائص متعددة لحالة واجهة المستخدم.
|
يوضّح المقتطف التالي كيفية عرض حالة واجهة المستخدم من ViewModel:
@HiltViewModel
class BookmarksViewModel @Inject constructor(
newsRepository: NewsRepository
) : ViewModel() {
val feedState: StateFlow<NewsFeedUiState> =
newsRepository
.getNewsResourcesStream()
.mapToFeedState(savedNewsResourcesState)
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = NewsFeedUiState.Loading
)
// ...
}
مراحل النشاط
وفي ما يلي بعض أفضل الممارسات للتعامل مع دورة حياة Android:
مقترَح | الوصف |
---|---|
لا تلغي طرق دورة الحياة في الأنشطة أو الأجزاء.
يُنصح بشدة باستخدامه |
لا تلغي طرق دورة الحياة، مثل onResume في الأنشطة أو الأجزاء. استخدِم LifecycleObserver بدلاً من ذلك. إذا كان التطبيق بحاجة إلى تنفيذ عمل عند وصول مسار النشاط إلى Lifecycle.State معيّن، استخدِم واجهة برمجة التطبيقات repeatOnLifecycle . |
يوضّح المقتطف التالي كيفية تنفيذ العمليات استنادًا إلى حالة Lifecycle معيّنة:
المشاهدات
class MyFragment: Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
// ...
}
override fun onPause(owner: LifecycleOwner) {
// ...
}
}
}
}
إنشاء
@Composable
fun MyApp() {
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(lifecycleOwner, ...) {
val lifecycleObserver = object : DefaultLifecycleObserver {
override fun onStop(owner: LifecycleOwner) {
// ...
}
}
lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
onDispose {
lifecycleOwner.lifecycle.removeObserver(lifecycleObserver)
}
}
}
التعامل مع التبعيات
هناك العديد من أفضل الممارسات التي يجب ملاحظتها عند إدارة التبعيات بين المكونات:
مقترَح | الوصف |
---|---|
استخدِم حقن التبعية.
يُنصح به بشدة |
استخدِم أفضل الممارسات المتعلّقة بحقن التبعيات، وبشكل أساسي حقن المُنشئ متى أمكن. |
يمكنك حصر النطاق في مكوّن عند الضرورة.
يُنصح بشدة باستخدامه |
الوصول إلى حاوية تبعية عندما يحتوي النوع على بيانات قابلة للتغيير يجب مشاركتها أو يكون النوع إعدادًا مكلفًا ويُستخدَم على نطاق واسع في التطبيق |
استخدِم Hilt.
إجراءات ننصح بها |
استخدِم Hilt أو الحقن اليدوي للتبعيات في التطبيقات البسيطة. استخدِم دالة Hilt إذا كان مشروعك معقّدًا بدرجة كافية. على سبيل المثال، إذا كان لديك:
|
الاختبار
في ما يلي بعض أفضل الممارسات المتعلّقة بعمليات الاختبار:
مقترَح | الوصف |
---|---|
تحديد ما يجب اختباره
يُنصح بشدة باستخدامه |
ما لم يكن المشروع بسيطًا تقريبًا مثل تطبيق "مرحبًا"، يجب اختباره على الأقل باستخدام:
|
يُفضّل استخدام النماذج المزيّفة بدلاً من النماذج الاختبارية.
يُنصح بشدة باستخدامه |
يمكنك الاطّلاع على مزيد من المعلومات في استخدام أدوات الاختبار المزدوجة في مستندات Android. |
اختبِر StateFlows.
يُنصح بشدة باستخدامه |
عند اختبار StateFlow :
|
لمزيد من المعلومات، يمكنك الاطّلاع على الدليل حول ما يجب اختباره في أداة Android DAC.
نماذج
يجب اتّباع أفضل الممارسات التالية عند تطوير النماذج في تطبيقاتك:
مقترَح | الوصف |
---|---|
أنشئ نموذجًا لكل طبقة في التطبيقات المعقدة.
مُقترَح |
في التطبيقات المعقدة، أنشئ نماذج جديدة في طبقات أو مكوّنات مختلفة عندما يكون ذلك منطقيًا. راجِع الأمثلة التالية:
|
اصطلاحات التسمية
عند تسمية قاعدة بياناتك البرمجية، يجب مراعاة أفضل الممارسات التالية:
مقترَح | الوصف |
---|---|
طرق التسمية
اختيارية |
يجب أن تكون الطرق عبارة عن عبارة فعل. مثلاً: makePayment() |
خصائص التسمية
اختيارية |
يجب أن تكون السمات عبارة اسمية. مثلاً: inProgressTopicSelection |
تسمية مصادر البيانات.
اختياري |
عندما تعرض فئة بث Flow أو LiveData أو أي بث آخر، يكون أسلوب التسمية هو get{model}Stream() . على سبيل المثال، getAuthorStream(): Flow<Author>
إذا كانت الدالة تعرض قائمة بطرز، يجب أن يكون اسم الطراز جمعيًا: getAuthorsStream(): Flow<List<Author>> |
عمليات تنفيذ واجهات التسمية
اختياري |
يجب أن تكون أسماء عمليات تنفيذ الواجهات ذات مغزى. استخدِم Default كبادئة إذا تعذّر العثور على اسم أفضل. على سبيل المثال، بالنسبة إلى واجهة NewsRepository ، يمكنك استخدام OfflineFirstNewsRepository أو InMemoryNewsRepository . إذا لم تتمكّن من العثور على اسم مناسب، استخدِم DefaultNewsRepository .
يجب أن تسبق البادئة Fake عمليات التنفيذ المزيّفة، كما هو الحال في FakeAuthorsRepository . |