توصیه هایی برای معماری اندروید

این صفحه چندین روش و توصیه های برتر معماری را ارائه می دهد. آنها را برای بهبود کیفیت، استحکام و مقیاس پذیری برنامه خود بپذیرید. آنها همچنین نگهداری و آزمایش برنامه شما را آسان تر می کنند.

بهترین شیوه های زیر بر اساس موضوع گروه بندی شده اند. هر کدام یک اولویت دارند که نشان می دهد تیم چقدر قوی آن را توصیه می کند. لیست اولویت ها به شرح زیر است:

  • اکیداً توصیه می شود: باید این عمل را اجرا کنید مگر اینکه اساساً با رویکرد شما در تضاد باشد.
  • توصیه می شود: این عمل احتمالاً برنامه شما را بهبود می بخشد.
  • اختیاری: این عمل می تواند برنامه شما را در شرایط خاص بهبود بخشد.

معماری لایه ای

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

توصیه توضیحات
از یک لایه داده به وضوح تعریف شده استفاده کنید.
به شدت توصیه می شود
لایه داده داده های برنامه را در معرض بقیه برنامه قرار می دهد و اکثریت قریب به اتفاق منطق تجاری برنامه شما را شامل می شود.
  • شما باید مخازن ایجاد کنید حتی اگر آنها فقط حاوی یک منبع داده واحد باشند.
  • در برنامه‌های کوچک، می‌توانید انواع لایه داده را در بسته یا ماژول data قرار دهید.
از یک لایه رابط کاربری کاملاً تعریف شده استفاده کنید.
به شدت توصیه می شود
لایه UI داده های برنامه را روی صفحه نمایش می دهد و به عنوان نقطه اصلی تعامل کاربر عمل می کند.
  • در برنامه‌های کوچک، می‌توانید انواع لایه داده را در بسته یا ماژول ui قرار دهید.
بهترین شیوه های لایه UI بیشتر در اینجا .
لایه داده باید داده های برنامه را با استفاده از یک مخزن نمایش دهد.
به شدت توصیه می شود

اجزای لایه UI مانند composable ها، فعالیت ها یا ViewModels نباید مستقیماً با منبع داده تعامل داشته باشند. نمونه هایی از منابع داده عبارتند از:

  • پایگاه های داده، DataStore، SharedPreferences، API های Firebase.
  • ارائه دهندگان موقعیت مکانی GPS
  • ارائه دهندگان داده بلوتوث
  • ارائه دهنده وضعیت اتصال شبکه
از کوروتین ها و جریان ها استفاده کنید.
به شدت توصیه می شود
از کوروتین ها و جریان ها برای برقراری ارتباط بین لایه ها استفاده کنید.

در اینجا بهترین روش‌های روتین بیشتر را در نظر بگیرید .

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

لایه رابط کاربری

نقش لایه UI این است که داده های برنامه را روی صفحه نمایش دهد و به عنوان نقطه اصلی تعامل کاربر عمل کند. در اینجا برخی از بهترین روش ها برای لایه UI آورده شده است:

توصیه توضیحات
جریان داده یک جهته (UDF) را دنبال کنید.
به شدت توصیه می شود
از اصول جریان داده های یک جهته (UDF) پیروی کنید، که در آن ViewModels حالت رابط کاربری را با استفاده از الگوی مشاهدهگر نشان می دهد و اقدامات را از طریق فراخوانی متد از UI دریافت می کند.
اگر مزایای AAC ViewModels برای برنامه شما اعمال می شود، استفاده کنید.
به شدت توصیه می شود
از AAC ViewModels برای مدیریت منطق کسب‌وکار استفاده کنید و داده‌های برنامه را واکشی کنید تا وضعیت UI را در معرض UI قرار دهید (Compose یا Android Views).

بهترین شیوه های ViewModel را اینجا ببینید.

مزایای ViewModels را اینجا ببینید.

از مجموعه وضعیت رابط کاربری آگاه از چرخه حیات استفاده کنید.
به شدت توصیه می شود
با استفاده از سازنده کوروتین آگاه از چرخه حیات مناسب، وضعیت رابط کاربری را از UI جمع آوری کنید: repeatOnLifecycle در سیستم View و collectAsStateWithLifecycle در Jetpack Compose.

درباره repeatOnLifecycle بیشتر بخوانید.

درباره collectAsStateWithLifecycle بیشتر بخوانید.

رویدادها را از ViewModel به UI ارسال نکنید.
به شدت توصیه می شود
رویداد را فوراً در 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 مسئول ارائه وضعیت UI و دسترسی به لایه داده است. در اینجا برخی از بهترین روش ها برای ViewModels آورده شده است:

توصیه توضیحات
ViewModels باید نسبت به چرخه حیات اندروید ناشناس باشد.
به شدت توصیه می شود
ViewModels نباید ارجاعی به هر نوع مربوط به چرخه حیات داشته باشد. Activity, Fragment, Context یا Resources به عنوان یک وابستگی در نظر نگیرید. اگر چیزی در ViewModel به یک Context نیاز دارد، باید به شدت ارزیابی کنید که آیا آن در لایه مناسب است یا خیر.
از کوروتین ها و جریان ها استفاده کنید.
به شدت توصیه می شود

ViewModel با داده ها یا لایه های دامنه با استفاده از:

  • کاتلین برای دریافت داده های برنامه جریان دارد،
  • suspend توابع برای انجام اقدامات با استفاده از viewModelScope .
از ViewModels در سطح صفحه استفاده کنید.
به شدت توصیه می شود

از ViewModels در قطعات قابل استفاده مجدد از UI استفاده نکنید. شما باید از ViewModels در موارد زیر استفاده کنید:

  • ترکیبات در سطح صفحه نمایش،
  • فعالیت‌ها/قطعه‌ها در نماها،
  • هنگام استفاده از Jetpack Navigation، مقاصد یا نمودارها.
از کلاس های دارنده حالت ساده در اجزای رابط کاربری قابل استفاده مجدد استفاده کنید.
به شدت توصیه می شود
از کلاس های نگهدارنده حالت ساده برای مدیریت پیچیدگی در اجزای رابط کاربری قابل استفاده مجدد استفاده کنید. با انجام این کار، می توان حالت را به صورت خارجی بالا برد و کنترل کرد.
از AndroidViewModel استفاده نکنید.
توصیه می شود
از کلاس ViewModel استفاده کنید، نه AndroidViewModel . کلاس Application نباید در ViewModel استفاده شود. در عوض، وابستگی را به UI یا لایه داده منتقل کنید.
یک وضعیت رابط کاربری را در معرض نمایش قرار دهید.
توصیه می شود
ViewModels باید داده ها را از طریق یک ویژگی به نام uiState در معرض UI قرار دهد. اگر UI داده های متعدد و نامرتبط را نشان دهد، VM می تواند چندین ویژگی حالت UI را نشان دهد .
  • شما باید uiState را یک StateFlow کنید.
  • اگر داده ها به صورت جریانی از داده ها از لایه های دیگر سلسله مراتب می آیند ، باید uiState با استفاده از عملگر stateIn با خط مشی WhileSubscribed(5000) ایجاد کنید.
  • برای موارد ساده‌تر بدون جریان داده‌ای که از لایه داده می‌آید، استفاده از MutableStateFlow که به‌عنوان StateFlow غیرقابل تغییر در معرض نمایش قرار می‌گیرد (مثال) قابل قبول است.
  • شما می توانید انتخاب کنید که ${Screen}UiState به عنوان یک کلاس داده باشد که می تواند حاوی داده ها، خطاها و سیگنال های بارگیری باشد. این کلاس همچنین می تواند یک کلاس مهر و موم شده باشد اگر حالت های مختلف انحصاری باشند.

قطعه زیر نحوه نمایش حالت UI از 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 آورده شده است:

توصیه توضیحات
روش‌های چرخه حیات را در Activities یا Fragments نادیده نگیرید.
به شدت توصیه می شود
روش‌های چرخه حیات مانند onResume را در Activities یا Fragments نادیده نگیرید. به جای آن از LifecycleObserver استفاده کنید. اگر برنامه باید زمانی که چرخه حیات به یک Lifecycle.State خاص می‌رسد، کار کند، از repeatOnLifecycle API استفاده کنید.

قطعه زیر نحوه انجام عملیات را با توجه به یک وضعیت چرخه حیات مشخص می کند:

بازدیدها

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 استفاده کنید. برای مثال، اگر دارید:
  • چند صفحه نمایش با ViewModels—ادغام
  • استفاده از WorkManager-ادغام
  • استفاده پیشرفته از Navigation، مانند ViewModels در محدوده نمودار ناوبری - یکپارچه سازی.

تست کردن

در زیر برخی از بهترین روش ها برای آزمایش آورده شده است:

توصیه توضیحات
بدانید چه چیزی را تست کنید .
به شدت توصیه می شود

مگر اینکه پروژه تقریباً به سادگی یک برنامه hello world باشد، باید آن را حداقل با:

  • واحد آزمایش ViewModels، از جمله جریان.
  • واحدهای لایه داده تست. یعنی مخازن و منابع داده.
  • تست های ناوبری UI که به عنوان تست های رگرسیون در CI مفید هستند.
تقلبی را به مسخره ترجیح دهید.
به شدت توصیه می شود
در مستندات اندروید استفاده از دو برابر بیشتر بخوانید.
تست StateFlows
به شدت توصیه می شود
هنگام آزمایش StateFlow :

برای اطلاعات بیشتر، راهنمای آنچه در Android DAC باید تست شود را بررسی کنید.

مدل ها

هنگام توسعه مدل‌ها در برنامه‌های خود باید این بهترین روش‌ها را رعایت کنید:

توصیه توضیحات
یک مدل در هر لایه در برنامه های پیچیده ایجاد کنید.
توصیه می شود

در برنامه های پیچیده، در صورت نیاز، مدل های جدید را در لایه ها یا اجزای مختلف ایجاد کنید. به مثال های زیر توجه کنید:

  • یک منبع داده از راه دور می‌تواند مدلی را که از طریق شبکه دریافت می‌کند به یک کلاس ساده‌تر تنها با داده‌های مورد نیاز برنامه ترسیم کند.
  • مخازن می‌توانند مدل‌های DAO را به کلاس‌های داده ساده‌تر تنها با اطلاعاتی که لایه UI نیاز دارد، نگاشت کنند.
  • ViewModel می تواند مدل های لایه داده را در کلاس های UiState قرار دهد.

قراردادهای نامگذاری

هنگام نام‌گذاری پایگاه کد خود، باید از بهترین روش‌های زیر آگاه باشید:

توصیه توضیحات
روش های نامگذاری
اختیاری
متدها باید یک عبارت فعل باشند. برای مثال makePayment() .
نام گذاری خواص
اختیاری
ویژگی ها باید یک عبارت اسمی باشند. به عنوان مثال، inProgressTopicSelection .
نامگذاری جریان های داده
اختیاری
هنگامی که یک کلاس یک جریان جریان، LiveData یا هر جریان دیگری را در معرض دید قرار می دهد، قرارداد نامگذاری get{model}Stream() است. برای مثال getAuthorStream(): Flow<Author> اگر تابع لیستی از مدل ها را برمی گرداند، نام مدل باید به صورت جمع باشد: getAuthorsStream(): Flow<List<Author>>
نامگذاری پیاده سازی رابط ها
اختیاری
نام‌های پیاده‌سازی رابط‌ها باید معنادار باشند. اگر نام بهتری پیدا نشد، Default را داشته باشید. به عنوان مثال، برای یک رابط NewsRepository ، می‌توانید یک OfflineFirstNewsRepository یا InMemoryNewsRepository داشته باشید. اگر نمی توانید نام خوبی پیدا کنید، از DefaultNewsRepository استفاده کنید. پیاده سازی های جعلی باید مانند FakeAuthorsRepository با Fake پیشوند شوند.