কম্পোজে UI অপরিবর্তনীয়—ড্র করার পর এটি আপডেট করার কোন উপায় নেই। আপনি যা নিয়ন্ত্রণ করতে পারেন তা হল আপনার UI এর অবস্থা। প্রতিবার UI এর অবস্থা পরিবর্তন হলে, Compose UI গাছের পরিবর্তিত অংশগুলি পুনরায় তৈরি করে । Composables state গ্রহণ করতে পারে এবং ইভেন্টগুলি প্রকাশ করতে পারে—উদাহরণস্বরূপ, একটি TextField একটি মান গ্রহণ করে এবং একটি কলব্যাক onValueChange প্রকাশ করে যা কলব্যাক হ্যান্ডলারকে মান পরিবর্তন করার জন্য অনুরোধ করে।
var name by remember { mutableStateOf("") } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") } )
যেহেতু কম্পোজেবলগুলি স্টেট গ্রহণ করে এবং ইভেন্টগুলি প্রকাশ করে, তাই ইউনিডাইরেকশনাল ডেটা ফ্লো প্যাটার্ন জেটপ্যাক কম্পোজের সাথে ভালোভাবে খাপ খায়। এই নির্দেশিকাটি কম্পোজে ইউনিডাইরেকশনাল ডেটা ফ্লো প্যাটার্ন কীভাবে বাস্তবায়ন করতে হয়, ইভেন্ট এবং স্টেট হোল্ডার কীভাবে বাস্তবায়ন করতে হয় এবং কম্পোজে ভিউমডেলের সাথে কীভাবে কাজ করতে হয় তার উপর আলোকপাত করে।
একমুখী তথ্য প্রবাহ
একটি ইউনিডাইরেকশনাল ডেটা ফ্লো (UDF) হল একটি ডিজাইন প্যাটার্ন যেখানে স্টেট নিচে প্রবাহিত হয় এবং ইভেন্টগুলি উপরে প্রবাহিত হয়। ইউনিডাইরেকশনাল ডেটা ফ্লো অনুসরণ করে, আপনি আপনার অ্যাপের সেই অংশগুলি থেকে UI-তে স্টেট প্রদর্শনকারী কম্পোজেবলগুলিকে আলাদা করতে পারেন যা স্টেট সংরক্ষণ করে এবং পরিবর্তন করে।
ইউনিডাইরেকশনাল ডেটা ফ্লো ব্যবহার করে এমন একটি অ্যাপের UI আপডেট লুপটি এরকম দেখাচ্ছে:
- ইভেন্ট : UI এর একটি অংশ একটি ইভেন্ট তৈরি করে এবং এটিকে উপরের দিকে প্রেরণ করে, যেমন একটি বোতাম ক্লিক হ্যান্ডেল করার জন্য ViewModel-এ প্রেরণ করা হয়; অথবা আপনার অ্যাপের অন্যান্য স্তর থেকে একটি ইভেন্ট পাস করা হয়, যেমন ব্যবহারকারীর সেশনের মেয়াদ শেষ হয়ে গেছে তা নির্দেশ করে।
- আপডেট অবস্থা : একটি ইভেন্ট হ্যান্ডলার অবস্থা পরিবর্তন করতে পারে।
- প্রদর্শন অবস্থা : অবস্থা ধারক অবস্থাটি প্রেরণ করে এবং UI এটি প্রদর্শন করে।

জেটপ্যাক কম্পোজ ব্যবহার করার সময় এই প্যাটার্ন অনুসরণ করলে বেশ কিছু সুবিধা পাওয়া যায়:
- টেস্টেবিলিটি : UI থেকে ডিকাপলিং অবস্থা যা এটি প্রদর্শন করে, বিচ্ছিন্নভাবে উভয় পরীক্ষা করা সহজ করে তোলে।
- স্টেট এনক্যাপসুলেশন : যেহেতু স্টেট শুধুমাত্র এক জায়গায় আপডেট করা যায় এবং কম্পোজেবলের স্টেটের সত্যতার উৎস মাত্র একটি, তাই অসামঞ্জস্যপূর্ণ স্টেটের কারণে বাগ তৈরির সম্ভাবনা কম।
- UI সামঞ্জস্য :
StateFlowবাLiveDataমতো পর্যবেক্ষণযোগ্য স্টেট হোল্ডার ব্যবহার করে সমস্ত স্টেট আপডেট অবিলম্বে UI তে প্রতিফলিত হয়।
জেটপ্যাক কম্পোজে একমুখী ডেটা প্রবাহ
কম্পোজেবলগুলি স্টেট এবং ইভেন্টের উপর ভিত্তি করে কাজ করে। উদাহরণস্বরূপ, একটি TextField শুধুমাত্র তখনই আপডেট হয় যখন এর value প্যারামিটার আপডেট করা হয় এবং এটি একটি onValueChange কলব্যাক প্রকাশ করে—একটি ইভেন্ট যা মানটিকে একটি নতুনতে পরিবর্তন করার অনুরোধ করে। কম্পোজ State অবজেক্টকে একটি ভ্যালু হোল্ডার হিসাবে সংজ্ঞায়িত করে এবং স্টেট ভ্যালুতে পরিবর্তন একটি রিকম্পোজিশন ট্রিগার করে। আপনি কতক্ষণ ধরে মানটি মনে রাখতে হবে তার উপর নির্ভর করে আপনি স্টেটটিকে একটি remember { mutableStateOf(value) } অথবা একটি rememberSaveable { mutableStateOf(value) এ ধরে রাখতে পারেন।
TextField composable এর মান হল String , তাই এটি যেকোনো জায়গা থেকে আসতে পারে—হার্ডকোডেড মান থেকে, ViewModel থেকে, অথবা প্যারেন্ট composable থেকে পাস করা। আপনাকে এটিকে State অবজেক্টে ধরে রাখতে হবে না, তবে onValueChange কল করার সময় আপনাকে মানটি আপডেট করতে হবে।
কম্পোজেবল প্যারামিটার নির্ধারণ করুন
একটি কম্পোজেবলের অবস্থা পরামিতি নির্ধারণ করার সময়, নিম্নলিখিত প্রশ্নগুলি মনে রাখবেন:
- কম্পোজেবল কতটা পুনর্ব্যবহারযোগ্য বা নমনীয়?
- এই কম্পোজেবলের কর্মক্ষমতাকে রাষ্ট্রীয় পরামিতিগুলি কীভাবে প্রভাবিত করে?
ডিকপলিং এবং পুনঃব্যবহারকে উৎসাহিত করার জন্য, প্রতিটি কম্পোজেবলে যতটা সম্ভব কম পরিমাণে তথ্য ধারণ করা উচিত। উদাহরণস্বরূপ, একটি সংবাদ নিবন্ধের শিরোনাম ধারণ করার জন্য একটি কম্পোজেবল তৈরি করার সময়, সম্পূর্ণ সংবাদ নিবন্ধের পরিবর্তে কেবল সেই তথ্যই প্রদান করা উচিত যা প্রদর্শন করা প্রয়োজন:
@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) এ পাঠানো হয়, তখন composable পুনরায় কম্পোজ হবে, এমনকি title এবং subtitle পরিবর্তন না হলেও।
আপনি কতগুলি প্যারামিটার পাস করবেন তা সাবধানতার সাথে বিবেচনা করুন। অনেকগুলি প্যারামিটার সহ একটি ফাংশন থাকা ফাংশনের এরগনোমিক্সকে হ্রাস করে, তাই এই ক্ষেত্রে তাদের একটি ক্লাসে গোষ্ঠীবদ্ধ করা পছন্দনীয়।
কম্পোজে ইভেন্ট
আপনার অ্যাপের প্রতিটি ইনপুট একটি ইভেন্ট হিসেবে উপস্থাপন করা উচিত: ট্যাপ, টেক্সট পরিবর্তন, এমনকি টাইমার বা অন্যান্য আপডেট। যেহেতু এই ইভেন্টগুলি আপনার UI এর অবস্থা পরিবর্তন করে, ViewModel তাদের পরিচালনা করবে এবং UI অবস্থা আপডেট করবে।
ইভেন্ট হ্যান্ডলারের বাইরে UI লেয়ারের অবস্থা কখনই পরিবর্তন করা উচিত নয় কারণ এটি আপনার অ্যাপ্লিকেশনে অসঙ্গতি এবং বাগ তৈরি করতে পারে।
স্টেট এবং ইভেন্ট হ্যান্ডলার ল্যাম্বডাসের জন্য অপরিবর্তনীয় মান পাস করা পছন্দ করুন। এই পদ্ধতির নিম্নলিখিত সুবিধা রয়েছে:
- আপনি পুনর্ব্যবহারযোগ্যতা উন্নত করেন।
- আপনি যাচাই করেন যে আপনার UI সরাসরি অবস্থার মান পরিবর্তন করে না।
- আপনি কনকারেন্সি সমস্যাগুলি এড়ান কারণ আপনি নিশ্চিত করেন যে স্টেটটি অন্য থ্রেড থেকে পরিবর্তিত না হয়।
- প্রায়শই, আপনি কোড জটিলতা হ্রাস করেন।
উদাহরণস্বরূপ, একটি কম্পোজেবল যা একটি String এবং একটি ল্যাম্বডাকে প্যারামিটার হিসেবে গ্রহণ করে, তাকে অনেক প্রসঙ্গ থেকে কল করা যেতে পারে এবং এটি অত্যন্ত পুনঃব্যবহারযোগ্য। ধরুন আপনার অ্যাপের উপরের অ্যাপ বারটি সর্বদা টেক্সট প্রদর্শন করে এবং একটি ব্যাক বোতাম থাকে। আপনি আরও সাধারণ 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 ) } }, // ... ) }
ভিউমডেল, অবস্থা এবং ইভেন্ট: একটি উদাহরণ
ViewModel এবং mutableStateOf ব্যবহার করে, আপনি আপনার অ্যাপে একমুখী ডেটা প্রবাহও চালু করতে পারেন যদি নিম্নলিখিতগুলির মধ্যে একটি সত্য হয়:
- আপনার UI এর অবস্থা পর্যবেক্ষণযোগ্য স্টেট হোল্ডার, যেমন
StateFlowবাLiveDataব্যবহার করে প্রকাশ করা হয়। -
ViewModelআপনার অ্যাপের UI বা অন্যান্য স্তর থেকে আসা ইভেন্টগুলি পরিচালনা করে এবং ইভেন্টগুলির উপর ভিত্তি করে স্টেট হোল্ডার আপডেট করে।
উদাহরণস্বরূপ, সাইন-ইন স্ক্রিন বাস্তবায়নের সময়, সাইন ইন বোতামে ট্যাপ করলে আপনার অ্যাপটি একটি অগ্রগতি স্পিনার এবং একটি নেটওয়ার্ক কল প্রদর্শন করবে। যদি লগইন সফল হয়, তাহলে আপনার অ্যাপটি একটি ভিন্ন স্ক্রিনে নেভিগেট করবে; কোনও ত্রুটির ক্ষেত্রে অ্যাপটি একটি স্ন্যাকবার দেখায়। আপনি কীভাবে স্ক্রিনের অবস্থা এবং ইভেন্টটি মডেল করবেন তা এখানে দেওয়া হল:
স্ক্রিনটির চারটি অবস্থা রয়েছে:
- সাইন আউট : যখন ব্যবহারকারী এখনও সাইন ইন করেননি।
- চলমান : যখন আপনার অ্যাপটি নেটওয়ার্ক কল করে ব্যবহারকারীকে সাইন ইন করার চেষ্টা করছে।
- ত্রুটি : যখন সাইন ইন করার সময় একটি ত্রুটি ঘটে।
- সাইন ইন : যখন ব্যবহারকারী সাইন ইন থাকে।
আপনি এই অবস্থাগুলিকে একটি সিলড ক্লাস হিসেবে মডেল করতে পারেন। 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() // ... }
আরও জানুন
জেটপ্যাক কম্পোজে স্থাপত্য সম্পর্কে আরও জানতে, নিম্নলিখিত সংস্থানগুলি দেখুন:
নমুনা
আপনার জন্য প্রস্তাবিত
- দ্রষ্টব্য: জাভাস্ক্রিপ্ট বন্ধ থাকলে লিঙ্ক টেক্সট প্রদর্শিত হয়।
- স্টেট এবং জেটপ্যাক কম্পোজ
- কম্পোজে UI অবস্থা সংরক্ষণ করুন
- ব্যবহারকারীর ইনপুট পরিচালনা করুন