در Compose رابط کاربری تغییرناپذیر است—هیچ راهی برای به روز رسانی آن پس از ترسیم وجود ندارد. آنچه شما می توانید کنترل کنید وضعیت رابط کاربری شما است. هر بار که وضعیت رابط کاربری تغییر میکند، Compose بخشهایی از درخت UI را که تغییر کردهاند دوباره ایجاد میکند . Composable ها می توانند حالت را بپذیرند و رویدادها را در معرض نمایش قرار دهند - به عنوان مثال، یک TextField
یک مقدار را می پذیرد و یک callback onValueChange
را نشان می دهد که از کنترل کننده تماس درخواست می کند تا مقدار را تغییر دهد.
var name by remember { mutableStateOf("") } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") } )
از آنجایی که composable ها حالت را می پذیرند و رویدادها را در معرض نمایش قرار می دهند، الگوی جریان داده یک طرفه به خوبی با Jetpack Compose مطابقت دارد. این راهنما بر نحوه پیادهسازی الگوی جریان داده یکطرفه در Compose، نحوه پیادهسازی رویدادها و دارندگان حالت، و نحوه کار با ViewModels در Compose تمرکز دارد.
جریان داده های یک طرفه
یک جریان داده یک طرفه (UDF) یک الگوی طراحی است که در آن حالت به پایین و رویدادها به سمت بالا جریان می یابد. با دنبال کردن جریان دادههای یکطرفه، میتوانید ترکیبپذیرهایی را که حالت نمایش در رابط کاربری را نشان میدهند از بخشهایی از برنامه خود که ذخیره میکنند و حالت را تغییر میدهند جدا کنید.
حلقه بهروزرسانی رابط کاربری برای برنامهای که از جریان دادههای یک طرفه استفاده میکند به این صورت است:
- رویداد : بخشی از رابط کاربری یک رویداد تولید میکند و آن را به سمت بالا ارسال میکند، مانند یک کلیک دکمهای که برای مدیریت به ViewModel ارسال میشود. یا رویدادی از لایههای دیگر برنامه شما ارسال میشود، مثلاً نشان میدهد که جلسه کاربر منقضی شده است.
- وضعیت به روز رسانی : یک کنترل کننده رویداد ممکن است وضعیت را تغییر دهد.
- حالت نمایش : دارنده وضعیت وضعیت را پایین میآورد و رابط کاربری آن را نمایش میدهد.
پیروی از این الگو هنگام استفاده از Jetpack Compose چندین مزیت دارد:
- آزمایش پذیری : جدا کردن حالت از رابط کاربری که آن را نمایش می دهد، آزمایش هر دو را به صورت مجزا آسان تر می کند.
- کپسولهسازی حالت : از آنجایی که حالت فقط در یک مکان بهروزرسانی میشود و تنها یک منبع حقیقت برای حالت یک ترکیب وجود دارد، احتمال اینکه به دلیل وضعیتهای ناسازگار باگ ایجاد کنید، کمتر است.
- سازگاری رابط کاربری : همه بهروزرسانیهای حالت بلافاصله با استفاده از دارندگان وضعیت قابل مشاهده، مانند
StateFlow
یاLiveData
، در UI منعکس میشوند.
جریان داده های یک طرفه در Jetpack Compose
Composable ها بر اساس حالت و رویدادها کار می کنند. برای مثال، یک TextField
تنها زمانی بهروزرسانی میشود که پارامتر value
آن بهروزرسانی شود و یک فراخوانی onValueChange
را نمایش میدهد - رویدادی که درخواست میکند مقدار به یک مقدار جدید تغییر کند. Compose آبجکت State
را به عنوان یک دارنده مقدار تعریف می کند و تغییر در مقدار حالت باعث ترکیب مجدد می شود. بسته به مدت زمانی که میخواهید مقدار را به خاطر بسپارید، میتوانید وضعیت را در یک remember { mutableStateOf(value) }
یا یک rememberSaveable { mutableStateOf(value)
نگه دارید.
نوع مقدار TextField
composable String
است، بنابراین این مقدار میتواند از هرجایی باشد—از یک مقدار کدگذاریشده، از ViewModel یا ارسال شده از Composable والد. شما مجبور نیستید آن را در یک شیء State
نگه دارید، اما زمانی که onValueChange
فراخوانی می شود، باید مقدار را به روز کنید.
پارامترهای قابل ترکیب را تعریف کنید
هنگام تعریف پارامترهای حالت یک composable باید سوالات زیر را در نظر داشته باشید:
- چقدر قابل استفاده مجدد یا انعطاف پذیر است؟
- چگونه پارامترهای حالت بر عملکرد این ترکیب اثر میگذارند؟
برای تشویق جداسازی و استفاده مجدد، هر محصول ترکیبی باید حداقل اطلاعات ممکن را داشته باشد. بهعنوان مثال، هنگام ساخت یک کامپوزیت برای نگهداشتن سرصفحه یک مقاله خبری، ترجیح میدهید فقط اطلاعاتی را که باید نمایش داده شود، به جای کل مقاله ارسال کنید:
@Composable fun Header(title: String, subtitle: String) { // Recomposes when title or subtitle have changed. } @Composable fun Header(news: News) { // Recomposes when a new instance of News is passed in. }
گاهی اوقات، استفاده از پارامترهای جداگانه عملکرد را نیز بهبود میبخشد - برای مثال، اگر News
حاوی اطلاعات بیشتری از title
و subtitle
، هر زمان که یک نمونه جدید از News
به Header(news)
منتقل میشود، قابل ترکیب مجدداً ترکیب میشود، حتی اگر title
و subtitle
وجود نداشته باشد. تغییر کرد.
تعداد پارامترهایی را که وارد می کنید به دقت در نظر بگیرید. داشتن یک تابع با پارامترهای زیاد، ارگونومی عملکرد را کاهش می دهد، بنابراین در این مورد، گروه بندی آنها در یک کلاس ترجیح داده می شود.
رویدادها در Compose
هر ورودی به برنامه شما باید به عنوان یک رویداد نمایش داده شود: ضربه ها، تغییرات متن، و حتی تایمرها یا به روز رسانی های دیگر. از آنجایی که این رویدادها وضعیت رابط کاربری شما را تغییر میدهند، ViewModel
باید آنها را مدیریت کرده و وضعیت رابط کاربری را بهروزرسانی کند.
لایه UI هرگز نباید خارج از کنترل کننده رویداد تغییر حالت دهد زیرا این می تواند ناسازگاری ها و اشکالات را در برنامه شما ایجاد کند.
ترجیح دادن مقادیر تغییرناپذیر برای لامبداهای کنترل کننده حالت و رویداد. این رویکرد دارای مزایای زیر است:
- شما قابلیت استفاده مجدد را بهبود می بخشید.
- اطمینان حاصل می کنید که رابط کاربری شما ارزش حالت را مستقیماً تغییر نمی دهد.
- شما از مسائل همزمانی اجتناب می کنید زیرا مطمئن می شوید که وضعیت از رشته دیگری جهش پیدا نمی کند.
- اغلب، پیچیدگی کد را کاهش می دهید.
به عنوان مثال، یک Composable که یک String
و یک lambda را به عنوان پارامتر می پذیرد، می تواند از زمینه های زیادی فراخوانی شود و بسیار قابل استفاده مجدد است. فرض کنید نوار برنامه بالای برنامه شما همیشه متن را نمایش می دهد و یک دکمه بازگشت دارد. می توانید یک MyAppTopAppBar
عمومی تر را تعریف کنید که متن و دسته دکمه برگشت را به عنوان پارامتر دریافت می کند:
@Composable fun MyAppTopAppBar(topAppBarText: String, onBackPressed: () -> Unit) { TopAppBar( title = { Text( text = topAppBarText, textAlign = TextAlign.Center, modifier = Modifier .fillMaxSize() .wrapContentSize(Alignment.Center) ) }, navigationIcon = { IconButton(onClick = onBackPressed) { Icon( Icons.AutoMirrored.Filled.ArrowBack, contentDescription = localizedString ) } }, // ... ) }
ViewModels، وضعیت ها و رویدادها: یک مثال
با استفاده از ViewModel
و mutableStateOf
، میتوانید در صورتی که یکی از موارد زیر درست باشد، جریان داده یک طرفه را در برنامه خود معرفی کنید:
- وضعیت رابط کاربری شما از طریق دارندگان وضعیت قابل مشاهده، مانند
StateFlow
یاLiveData
در معرض دید قرار میگیرد. -
ViewModel
رویدادهایی را که از رابط کاربری یا لایههای دیگر برنامه شما میآیند مدیریت میکند و دارنده حالت را بر اساس رویدادها بهروزرسانی میکند.
به عنوان مثال، هنگام اجرای یک صفحه ورود به سیستم، ضربه زدن روی دکمه ورود باید باعث شود برنامه شما یک چرخش پیشرفت و یک تماس شبکه را نمایش دهد. اگر ورود موفقیت آمیز بود، برنامه شما به صفحه دیگری هدایت می شود. در صورت بروز خطا، برنامه Snackbar را نشان می دهد. در اینجا نحوه مدل سازی حالت صفحه نمایش و رویداد آمده است:
صفحه نمایش چهار حالت دارد:
- از سیستم خارج شده : زمانی که کاربر هنوز وارد سیستم نشده است.
- در حال پیشرفت : زمانی که برنامه شما در حال حاضر سعی دارد با انجام یک تماس شبکه، کاربر را وارد سیستم کند.
- خطا : زمانی که هنگام ورود به سیستم خطایی رخ داد.
- Signed in : زمانی که کاربر وارد سیستم شده است.
شما می توانید این حالت ها را به عنوان یک کلاس مهر و موم شده مدل کنید. ViewModel
وضعیت را به عنوان یک State
نشان می دهد، وضعیت اولیه را تنظیم می کند و وضعیت را در صورت نیاز به روز می کند. ViewModel
همچنین با افشای متد onSignIn()
رویداد ورود به سیستم را مدیریت می کند.
class MyViewModel : ViewModel() { private val _uiState = mutableStateOf<UiState>(UiState.SignedOut) val uiState: State<UiState> get() = _uiState // ... }
علاوه بر mutableStateOf
API، Compose پسوندهایی را برای LiveData
، Flow
و Observable
فراهم می کند تا به عنوان شنونده ثبت شود و مقدار را به عنوان یک حالت نمایش دهد.
class MyViewModel : ViewModel() { private val _uiState = MutableLiveData<UiState>(UiState.SignedOut) val uiState: LiveData<UiState> get() = _uiState // ... } @Composable fun MyComposable(viewModel: MyViewModel) { val uiState = viewModel.uiState.observeAsState() // ... }
بیشتر بدانید
برای کسب اطلاعات بیشتر در مورد معماری در Jetpack Compose، به منابع زیر مراجعه کنید:
نمونه ها
برای شما توصیه می شود
- توجه: وقتی جاوا اسکریپت خاموش است، متن پیوند نمایش داده می شود
- State و Jetpack Compose
- حالت رابط کاربری را در Compose ذخیره کنید
- کنترل ورودی کاربر