توصیه‌هایی برای معماری اندروید (Views)

مفاهیم و پیاده‌سازی Jetpack Compose

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

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

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

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

توصیه

توضیحات

جریان داده یک‌طرفه (UDF) را دنبال کنید.

اکیداً توصیه می‌شود

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

اگر مزایای AAC ViewModels در برنامه شما صدق می‌کند، از آنها استفاده کنید.

اکیداً توصیه می‌شود

از AAC ViewModels برای مدیریت منطق کسب و کار و واکشی داده‌های برنامه برای نمایش وضعیت رابط کاربری به رابط کاربری استفاده کنید.

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

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

از مجموعه وضعیت رابط کاربری آگاه از چرخه حیات استفاده کنید.

اکیداً توصیه می‌شود

با استفاده از سازنده‌ی کوروتینِ آگاه از چرخه‌ی حیاتِ مناسب، repeatOnLifecycle ، وضعیت رابط کاربری را از رابط کاربری جمع‌آوری کنید.

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

رویدادها را از ViewModel به UI ارسال نکنید.

اکیداً توصیه می‌شود

رویداد را فوراً در ViewModel پردازش کنید و باعث به‌روزرسانی وضعیت با نتیجه‌ی مدیریت رویداد شوید. اطلاعات بیشتر در مورد رویدادهای رابط کاربری را اینجا ببینید .

از یک برنامه تک فعالیتی استفاده کنید.

توصیه شده

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

قطعه کد زیر نحوه جمع‌آوری وضعیت رابط کاربری را به شیوه‌ای آگاه از چرخه حیات (lifecycle-aware) شرح می‌دهد:

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

ویو مدل

ViewModelها مسئول ارائه وضعیت رابط کاربری و دسترسی به لایه داده هستند. در اینجا چند نمونه از بهترین شیوه‌ها برای ViewModelها آورده شده است:

توصیه

توضیحات

ViewModelها باید از چرخه حیات اندروید مستقل باشند.

اکیداً توصیه می‌شود

ViewModelها نباید هیچ ارجاعی به هیچ نوع داده مرتبط با چرخه حیات (Lifecycle) داشته باشند. Activity ، Fragment ، Context یا Resources را به عنوان وابستگی ارسال نکنید. اگر چیزی به Context در ViewModel نیاز دارد، باید به شدت ارزیابی کنید که آیا در لایه مناسب قرار دارد یا خیر.

از کوروتین‌ها و جریان‌ها استفاده کنید.

اکیداً توصیه می‌شود

ViewModel با استفاده از موارد زیر با لایه‌های داده یا دامنه تعامل می‌کند:

  • جریان‌های کاتلین برای دریافت داده‌های برنامه،
  • توابع را برای انجام اقدامات با استفاده از viewModelScope suspend .

از ViewModelها در سطح صفحه نمایش استفاده کنید.

اکیداً توصیه می‌شود

از ViewModelها در بخش‌های قابل استفاده مجدد رابط کاربری استفاده نکنید. شما باید از ViewModelها در موارد زیر استفاده کنید:

  • فعالیت‌ها/قطعات در نماها
  • مقصدها یا نمودارها هنگام استفاده از ناوبری Jetpack .

AndroidViewModel استفاده نکنید.

اکیداً توصیه می‌شود

از کلاس ViewModel استفاده کنید، نه AndroidViewModel . کلاس Application نباید در ViewModel استفاده شود. در عوض، وابستگی را به رابط کاربری یا لایه داده منتقل کنید.

نمایش وضعیت رابط کاربری (UI).

توصیه شده

ViewModelها باید داده‌ها را از طریق یک ویژگی واحد به نام uiState در اختیار رابط کاربری (UI) قرار دهند. اگر رابط کاربری چندین قطعه داده نامرتبط را نشان دهد، ViewModel می‌تواند چندین ویژگی حالت رابط کاربری را در معرض نمایش قرار دهد .

  • شما باید uiState به یک StateFlow تبدیل کنید.
  • اگر داده‌ها به صورت جریانی از داده‌ها از لایه‌های دیگر سلسله مراتب می‌آیند، باید uiState با استفاده از عملگر stateIn و با استفاده از سیاست WhileSubscribed(5000) ( مثال ) ایجاد کنید.
  • برای موارد ساده‌تر که هیچ جریان داده‌ای از لایه داده نمی‌آید، استفاده از یک MutableStateFlow که به عنوان یک StateFlow تغییرناپذیر در معرض نمایش قرار گرفته است، قابل قبول است.
  • شما می‌توانید ${Screen}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
            )

    // ...
}

چرخه حیات

در ادامه به برخی از بهترین شیوه‌ها برای کار با چرخه حیات اندروید اشاره شده است:

توصیه

توضیحات

متدهای چرخه حیات را در اکتیویتی‌ها یا فرگمنت‌ها override نکنید.

اکیداً توصیه می‌شود

متدهای چرخه حیات مانند onResume در Activityها یا 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) {
                // ...
            }
        }
    }
}