রাজ্য ধারক এবং UI রাজ্য

UI লেয়ার গাইড ইউআই লেয়ারের জন্য UI স্টেট তৈরি ও পরিচালনার একটি উপায় হিসাবে ইউনিডাইরেকশনাল ডেটা ফ্লো (UDF) নিয়ে আলোচনা করে।

ডেটা ডাটা স্তর থেকে UI এ একমুখীভাবে প্রবাহিত হয়।
চিত্র 1 : একমুখী তথ্য প্রবাহ

এটি রাষ্ট্র ধারক নামে একটি বিশেষ শ্রেণীর কাছে UDF ব্যবস্থাপনা অর্পণ করার সুবিধাগুলিও তুলে ধরে। আপনি একটি ViewModel বা একটি প্লেইন ক্লাসের মাধ্যমে একটি স্টেট হোল্ডার বাস্তবায়ন করতে পারেন। এই ডকুমেন্টটি স্টেট হোল্ডারদের এবং UI লেয়ারে তারা যে ভূমিকা পালন করে তার উপর ঘনিষ্ঠভাবে নজর দেয়।

এই ডকুমেন্টের শেষে, ইউআই লেয়ারে অ্যাপ্লিকেশানের অবস্থা কীভাবে পরিচালনা করতে হয় সে সম্পর্কে আপনার ধারণা থাকা উচিত; এটি UI রাজ্য উত্পাদন পাইপলাইন। আপনি নিম্নলিখিত বুঝতে এবং জানতে সক্ষম হওয়া উচিত:

  • UI স্তরে বিদ্যমান UI অবস্থার প্রকারগুলি বুঝুন৷
  • UI স্তরে সেই UI স্টেটে কাজ করে এমন যুক্তির ধরনগুলি বুঝুন।
  • ViewModel বা একটি সাধারণ ক্লাসের মতো একটি স্টেট হোল্ডারের যথাযথ বাস্তবায়ন কীভাবে চয়ন করবেন তা জানুন।

UI স্টেট প্রোডাকশন পাইপলাইনের উপাদান

UI অবস্থা এবং যুক্তি যা এটি তৈরি করে তা UI স্তরকে সংজ্ঞায়িত করে।

UI অবস্থা

UI স্টেট হল সেই সম্পত্তি যা UI বর্ণনা করে। দুই ধরনের UI অবস্থা আছে:

  • স্ক্রীন UI অবস্থা হল যা আপনাকে স্ক্রিনে প্রদর্শন করতে হবে। উদাহরণস্বরূপ, একটি NewsUiState ক্লাসে UI রেন্ডার করার জন্য প্রয়োজনীয় সংবাদ নিবন্ধ এবং অন্যান্য তথ্য থাকতে পারে। এই অবস্থাটি সাধারণত অনুক্রমের অন্যান্য স্তরগুলির সাথে সংযুক্ত থাকে কারণ এতে অ্যাপ ডেটা থাকে৷
  • UI এলিমেন্ট স্টেট বলতে বোঝায় UI এলিমেন্টের অন্তর্নিহিত বৈশিষ্ট্য যা তাদের রেন্ডার করার পদ্ধতিকে প্রভাবিত করে। একটি UI উপাদান দেখানো বা লুকানো হতে পারে এবং একটি নির্দিষ্ট ফন্ট, ফন্টের আকার বা ফন্টের রঙ থাকতে পারে। অ্যান্ড্রয়েড ভিউ-এ, ভিউ এই স্টেটটিকে নিজেই পরিচালনা করে কারণ এটি সহজাতভাবে স্টেটফুল, এটির অবস্থা পরিবর্তন বা অনুসন্ধান করার পদ্ধতিগুলি প্রকাশ করে৷ এর একটি উদাহরণ হল TextView ক্লাসের পাঠ্যের জন্য get এবং set পদ্ধতি। জেটপ্যাক কম্পোজে, স্টেট কম্পোজেবলের বাহ্যিক, এবং আপনি এটিকে কম্পোজেবলের আশেপাশে থেকে কলিং কম্পোজেবল ফাংশন বা স্টেট হোল্ডারে উত্তোলন করতে পারেন। এর একটি উদাহরণ হল Scaffold কম্পোজেবলের জন্য ScaffoldState

যুক্তিবিদ্যা

UI স্টেট একটি স্ট্যাটিক প্রপার্টি নয়, কারণ অ্যাপ্লিকেশন ডেটা এবং ইউজার ইভেন্ট সময়ের সাথে সাথে UI স্টেট পরিবর্তন করে। লজিক পরিবর্তনের সুনির্দিষ্ট বৈশিষ্ট্য নির্ধারণ করে, যার মধ্যে UI স্টেটের কোন অংশগুলি পরিবর্তিত হয়েছে, কেন এটি পরিবর্তিত হয়েছে এবং কখন এটি পরিবর্তন করা উচিত।

যুক্তি UI অবস্থা তৈরি করে
চিত্র 2 : UI রাজ্যের প্রযোজক হিসাবে যুক্তি

একটি অ্যাপ্লিকেশনে যুক্তি ব্যবসায়িক যুক্তি বা UI যুক্তি হতে পারে:

  • ব্যবসায়িক যুক্তি হল অ্যাপ ডেটার জন্য পণ্যের প্রয়োজনীয়তা বাস্তবায়ন। উদাহরণস্বরূপ, ব্যবহারকারী যখন বোতামটি ট্যাপ করে তখন একটি নিউজ রিডার অ্যাপে একটি নিবন্ধ বুকমার্ক করা। একটি ফাইল বা ডাটাবেসে বুকমার্ক সংরক্ষণ করার এই যুক্তিটি সাধারণত ডোমেন বা ডেটা স্তরগুলিতে স্থাপন করা হয়। রাষ্ট্র ধারক সাধারণত এই যুক্তিগুলিকে সেই স্তরগুলিতে অর্পণ করে যে পদ্ধতিগুলিকে তারা প্রকাশ করে।
  • UI লজিক কীভাবে স্ক্রিনে UI অবস্থা প্রদর্শন করতে হয় তার সাথে সম্পর্কিত। উদাহরণস্বরূপ, যখন ব্যবহারকারী একটি বিভাগ নির্বাচন করেন তখন সঠিক অনুসন্ধান বার ইঙ্গিত পাওয়া, একটি তালিকার একটি নির্দিষ্ট আইটেমে স্ক্রোল করা, বা ব্যবহারকারী যখন একটি বোতামে ক্লিক করে তখন একটি নির্দিষ্ট স্ক্রিনে নেভিগেশন লজিক।

অ্যান্ড্রয়েড লাইফসাইকেল এবং ইউআই স্টেট এবং লজিকের ধরন

UI স্তরের দুটি অংশ রয়েছে: একটি নির্ভরশীল এবং অন্যটি UI জীবনচক্র থেকে স্বাধীন। এই বিচ্ছেদ প্রতিটি অংশের জন্য উপলব্ধ ডেটা উত্স নির্ধারণ করে, এবং সেইজন্য বিভিন্ন ধরনের UI অবস্থা এবং যুক্তি প্রয়োজন।

  • UI জীবনচক্র স্বাধীন : UI স্তরের এই অংশটি অ্যাপের ডেটা উত্পাদনকারী স্তরগুলির সাথে কাজ করে (ডেটা বা ডোমেন স্তর) এবং ব্যবসায়িক যুক্তি দ্বারা সংজ্ঞায়িত করা হয়। UI স্টেট প্রোডাকশন পাইপলাইন সক্রিয় থাকলে জীবনচক্র, কনফিগারেশন পরিবর্তন এবং UI-তে Activity বিনোদন প্রভাবিত করতে পারে, কিন্তু উত্পাদিত ডেটার বৈধতাকে প্রভাবিত করে না।
  • UI জীবনচক্র নির্ভর : UI স্তরের এই অংশটি UI লজিকের সাথে কাজ করে এবং সরাসরি জীবনচক্র বা কনফিগারেশন পরিবর্তন দ্বারা প্রভাবিত হয়। এই পরিবর্তনগুলি সরাসরি এটির মধ্যে পড়া ডেটার উত্সগুলির বৈধতাকে প্রভাবিত করে এবং ফলস্বরূপ এটির জীবনচক্র সক্রিয় থাকলেই এর অবস্থা পরিবর্তন হতে পারে। এর উদাহরণগুলির মধ্যে রানটাইম অনুমতি এবং স্থানীয় স্ট্রিংগুলির মতো কনফিগারেশন নির্ভর সংস্থানগুলি অন্তর্ভুক্ত রয়েছে।

উপরের সারণীগুলির সাথে সংক্ষিপ্ত করা যেতে পারে:

UI লাইফসাইকেল স্বাধীন UI জীবনচক্র নির্ভরশীল
ব্যবসায়িক যুক্তি UI লজিক
স্ক্রীন UI অবস্থা

UI রাজ্য উত্পাদন পাইপলাইন

UI স্টেট প্রোডাকশন পাইপলাইন UI স্টেট তৈরির জন্য গৃহীত পদক্ষেপগুলিকে বোঝায়। এই পদক্ষেপগুলি আগে সংজ্ঞায়িত যুক্তির ধরনগুলির প্রয়োগকে অন্তর্ভুক্ত করে এবং সম্পূর্ণরূপে আপনার UI এর চাহিদার উপর নির্ভরশীল৷ কিছু UI পাইপলাইনের UI লাইফসাইকেল স্বাধীন এবং UI লাইফসাইকেল নির্ভরশীল উভয় অংশ থেকে উপকৃত হতে পারে, হয় না হয়।

অর্থাৎ, UI স্তর পাইপলাইনের নিম্নোক্ত স্থানান্তরগুলি বৈধ:

  • UI অবস্থা UI নিজেই দ্বারা উত্পাদিত এবং পরিচালিত। উদাহরণস্বরূপ, একটি সহজ, পুনরায় ব্যবহারযোগ্য মৌলিক কাউন্টার:

    @Composable
    fun Counter() {
        // The UI state is managed by the UI itself
        var count by remember { mutableStateOf(0) }
        Row {
            Button(onClick = { ++count }) {
                Text(text = "Increment")
            }
            Button(onClick = { --count }) {
                Text(text = "Decrement")
            }
        }
    }
    
  • UI যুক্তি → UI। উদাহরণস্বরূপ, একটি বোতাম দেখানো বা লুকানো যা একজন ব্যবহারকারীকে একটি তালিকার শীর্ষে যেতে দেয়।

    @Composable
    fun ContactsList(contacts: List<Contact>) {
        val listState = rememberLazyListState()
        val isAtTopOfList by remember {
            derivedStateOf {
                listState.firstVisibleItemIndex < 3
            }
        }
    
        // Create the LazyColumn with the lazyListState
        ...
    
        // Show or hide the button (UI logic) based on the list scroll position
        AnimatedVisibility(visible = !isAtTopOfList) {
            ScrollToTopButton()
        }
    }
    
  • ব্যবসায়িক যুক্তি → UI। একটি UI উপাদান স্ক্রিনে বর্তমান ব্যবহারকারীর ফটো প্রদর্শন করছে।

    @Composable
    fun UserProfileScreen(viewModel: UserProfileViewModel = hiltViewModel()) {
        // Read screen UI state from the business logic state holder
        val uiState by viewModel.uiState.collectAsStateWithLifecycle()
    
        // Call on the UserAvatar Composable to display the photo
        UserAvatar(picture = uiState.profilePicture)
    }
    
  • ব্যবসায়িক যুক্তি → UI যুক্তি → UI। একটি UI উপাদান যা একটি প্রদত্ত UI অবস্থার জন্য স্ক্রিনে সঠিক তথ্য প্রদর্শন করতে স্ক্রোল করে।

    @Composable
    fun ContactsList(viewModel: ContactsViewModel = hiltViewModel()) {
        // Read screen UI state from the business logic state holder
        val uiState by viewModel.uiState.collectAsStateWithLifecycle()
        val contacts = uiState.contacts
        val deepLinkedContact = uiState.deepLinkedContact
    
        val listState = rememberLazyListState()
    
        // Create the LazyColumn with the lazyListState
        ...
    
        // Perform UI logic that depends on information from business logic
        if (deepLinkedContact != null && contacts.isNotEmpty()) {
            LaunchedEffect(listState, deepLinkedContact, contacts) {
                val deepLinkedContactIndex = contacts.indexOf(deepLinkedContact)
                if (deepLinkedContactIndex >= 0) {
                  // Scroll to deep linked item
                  listState.animateScrollToItem(deepLinkedContactIndex)
                }
            }
        }
    }
    

যে ক্ষেত্রে উভয় ধরনের যুক্তিই UI স্টেট প্রোডাকশন পাইপলাইনে প্রয়োগ করা হয়, ব্যবসায়িক যুক্তি সর্বদা UI লজিকের আগে প্রয়োগ করা আবশ্যক । UI লজিকের পরে ব্যবসায়িক যুক্তি প্রয়োগ করার চেষ্টা করা বোঝায় যে ব্যবসায়িক যুক্তি UI যুক্তির উপর নির্ভর করে। নিম্নলিখিত বিভাগগুলি বিভিন্ন যুক্তির ধরন এবং তাদের রাষ্ট্র ধারকদের গভীরভাবে দেখার মাধ্যমে কেন এটি একটি সমস্যা তা কভার করে।

ডেটা উত্পাদনকারী স্তর থেকে UI এ ডেটা প্রবাহিত হয়
চিত্র 3 : UI স্তরে যুক্তির প্রয়োগ

রাষ্ট্র ধারক এবং তাদের দায়িত্ব

একটি রাষ্ট্র ধারকের দায়িত্ব হল রাজ্য সংরক্ষণ করা যাতে অ্যাপটি এটি পড়তে পারে। যে ক্ষেত্রে যুক্তির প্রয়োজন হয়, এটি একটি মধ্যস্থতাকারী হিসাবে কাজ করে এবং প্রয়োজনীয় যুক্তিগুলি হোস্ট করে এমন ডেটা উত্সগুলিতে অ্যাক্সেস সরবরাহ করে। এইভাবে, রাষ্ট্র ধারক উপযুক্ত ডেটা উৎসের কাছে যুক্তি অর্পণ করে।

এটি নিম্নলিখিত সুবিধাগুলি তৈরি করে:

  • সরল UI : UI কেবল তার অবস্থাকে আবদ্ধ করে।
  • রক্ষণাবেক্ষণযোগ্যতা : স্টেট হোল্ডারে সংজ্ঞায়িত যুক্তি UI নিজেই পরিবর্তন না করেই পুনরাবৃত্তি করা যেতে পারে।
  • পরীক্ষাযোগ্যতা : UI এবং এর রাষ্ট্রীয় উত্পাদন যুক্তি স্বাধীনভাবে পরীক্ষা করা যেতে পারে।
  • পাঠযোগ্যতা : কোডের পাঠকরা স্পষ্টভাবে UI উপস্থাপনা কোড এবং UI রাজ্য উত্পাদন কোডের মধ্যে পার্থক্য দেখতে পারেন।

এর আকার বা সুযোগ নির্বিশেষে, প্রতিটি UI উপাদানের সংশ্লিষ্ট স্টেট হোল্ডারের সাথে 1:1 সম্পর্ক রয়েছে। তদ্ব্যতীত, একজন রাষ্ট্র ধারক অবশ্যই ব্যবহারকারীর ক্রিয়াকলাপ গ্রহণ এবং প্রক্রিয়া করতে সক্ষম হবেন যার ফলে একটি UI অবস্থার পরিবর্তন হতে পারে এবং পরবর্তী রাষ্ট্র পরিবর্তন অবশ্যই করতে হবে।

রাষ্ট্র ধারকদের প্রকার

ইউআই স্টেট এবং লজিকের মতোই, ইউআই লেয়ারে দুই ধরনের স্টেট হোল্ডার রয়েছে যা UI জীবনচক্রের সাথে তাদের সম্পর্ক দ্বারা সংজ্ঞায়িত করা হয়েছে:

  • ব্যবসায়িক যুক্তি রাষ্ট্র ধারক.
  • UI লজিক স্টেট হোল্ডার।

নিম্নলিখিত বিভাগগুলি ব্যবসায়িক লজিক স্টেট হোল্ডার থেকে শুরু করে রাষ্ট্র ধারকদের ধরনগুলি ঘনিষ্ঠভাবে দেখে।

ব্যবসায়িক যুক্তি এবং এর রাষ্ট্র ধারক

বিজনেস লজিক স্টেট হোল্ডাররা ব্যবহারকারীর ইভেন্টগুলি প্রক্রিয়া করে এবং ডেটা বা ডোমেন স্তরগুলি থেকে স্ক্রীন UI স্টেটে ডেটা রূপান্তর করে। অ্যান্ড্রয়েড লাইফসাইকেল এবং অ্যাপ কনফিগারেশন পরিবর্তনগুলি বিবেচনা করার সময় একটি সর্বোত্তম ব্যবহারকারীর অভিজ্ঞতা প্রদান করার জন্য, ব্যবসায়িক যুক্তি ব্যবহার করে এমন রাষ্ট্র ধারকদের নিম্নলিখিত বৈশিষ্ট্যগুলি থাকা উচিত:

সম্পত্তি বিস্তারিত
UI স্টেট তৈরি করে বিজনেস লজিক স্টেট হোল্ডাররা তাদের UI এর জন্য UI স্টেট তৈরি করার জন্য দায়ী। এই UI অবস্থা প্রায়শই ব্যবহারকারীর ইভেন্ট প্রক্রিয়াকরণ এবং ডোমেন এবং ডেটা স্তর থেকে ডেটা পড়ার ফলাফল।
কার্যকলাপ বিনোদন মাধ্যমে বজায় রাখা বিজনেস লজিক স্টেট হোল্ডাররা তাদের স্টেট এবং স্টেট প্রসেসিং পাইপলাইনগুলিকে Activity রিক্রিয়েশন জুড়ে ধরে রাখে, একটি নিরবিচ্ছিন্ন ব্যবহারকারীর অভিজ্ঞতা প্রদানে সহায়তা করে। যে ক্ষেত্রে রাজ্য ধারককে ধরে রাখা যায় না এবং পুনরায় তৈরি করা হয় (সাধারণত প্রক্রিয়া মৃত্যুর পরে), রাজ্য ধারককে একটি সামঞ্জস্যপূর্ণ ব্যবহারকারীর অভিজ্ঞতা নিশ্চিত করতে সহজেই তার শেষ অবস্থা পুনরায় তৈরি করতে সক্ষম হতে হবে।
দীর্ঘজীবী রাষ্ট্রের অধিকারী বিজনেস লজিক স্টেট হোল্ডাররা প্রায়ই নেভিগেশন গন্তব্যের জন্য স্টেট পরিচালনা করতে ব্যবহৃত হয়। ফলস্বরূপ, নেভিগেশন গ্রাফ থেকে সরানো না হওয়া পর্যন্ত তারা প্রায়শই নেভিগেশন পরিবর্তন জুড়ে তাদের অবস্থা সংরক্ষণ করে।
এটির UI এর জন্য অনন্য এবং এটি পুনরায় ব্যবহারযোগ্য নয় বিজনেস লজিক স্টেট হোল্ডাররা সাধারণত একটি নির্দিষ্ট অ্যাপ ফাংশনের জন্য স্টেট তৈরি করে, উদাহরণস্বরূপ একটি TaskEditViewModel বা একটি TaskListViewModel , এবং সেইজন্য শুধুমাত্র সেই অ্যাপ ফাংশনের জন্য প্রযোজ্য। একই রাজ্য ধারক বিভিন্ন ফর্ম ফ্যাক্টর জুড়ে এই অ্যাপ্লিকেশন ফাংশন সমর্থন করতে পারেন. উদাহরণস্বরূপ, অ্যাপের মোবাইল, টিভি এবং ট্যাবলেট সংস্করণ একই ব্যবসায়িক লজিক স্টেট হোল্ডার পুনরায় ব্যবহার করতে পারে।

উদাহরণ স্বরূপ "Now in Android " অ্যাপে লেখক নেভিগেশন গন্তব্য বিবেচনা করুন:

নাও ইন অ্যান্ড্রয়েড অ্যাপ দেখায় যে কীভাবে একটি প্রধান অ্যাপ ফাংশনের প্রতিনিধিত্বকারী একটি নেভিগেশন গন্তব্যের নিজস্ব অনন্য ব্যবসায়িক লজিক স্টেট ধারক থাকা উচিত।
চিত্র 4 : দ্য নাউ ইন অ্যান্ড্রয়েড অ্যাপ

বিজনেস লজিক স্টেট হোল্ডার হিসেবে কাজ করে, AuthorViewModel এই ক্ষেত্রে UI স্টেট তৈরি করে:

@HiltViewModel
class AuthorViewModel @Inject constructor(
    savedStateHandle: SavedStateHandle,
    private val authorsRepository: AuthorsRepository,
    newsRepository: NewsRepository
) : ViewModel() {

    val uiState: StateFlow<AuthorScreenUiState> = 

    // Business logic
    fun followAuthor(followed: Boolean) {
      
    }
}

লক্ষ্য করুন যে AuthorViewModel বৈশিষ্ট্যগুলি পূর্বে বর্ণিত হয়েছে:

সম্পত্তি বিস্তারিত
AuthorScreenUiState তৈরি করে AuthorViewModel AuthorsRepository এবং NewsRepository থেকে ডেটা পড়ে এবং AuthorScreenUiState তৈরি করতে সেই ডেটা ব্যবহার করে। এটি ব্যবসায়িক যুক্তিও প্রয়োগ করে যখন ব্যবহারকারী AuthorsRepository এ অর্পণ করে একজন Author অনুসরণ করতে বা আনফলো করতে চায়।
ডেটা স্তরে অ্যাক্সেস আছে AuthorsRepository এবং NewsRepository এর একটি উদাহরণ এটির কনস্ট্রাক্টরে এটিকে পাস করা হয়, এটি একটি Author অনুসরণ করার ব্যবসায়িক যুক্তি বাস্তবায়নের অনুমতি দেয়।
Activity বিনোদন বেঁচে যেহেতু এটি একটি ViewModel এর সাথে প্রয়োগ করা হয়েছে, এটি দ্রুত Activity বিনোদন জুড়ে ধরে রাখা হবে। প্রক্রিয়া মৃত্যুর ক্ষেত্রে, ডেটা স্তর থেকে UI অবস্থা পুনরুদ্ধার করার জন্য প্রয়োজনীয় ন্যূনতম পরিমাণ তথ্য সরবরাহ করতে SavedStateHandle অবজেক্ট থেকে পড়া যেতে পারে।
দীর্ঘজীবী রাষ্ট্রের অধিকারী ViewModel নেভিগেশন গ্রাফে স্কোপ করা হয়েছে, তাই লেখক গন্তব্যটি নেভিগেশন গ্রাফ থেকে সরানো না হলে, uiState StateFlow এর UI অবস্থা মেমরিতে থাকবে। StateFlow -এর ব্যবহার ব্যবসায়িক যুক্তির প্রয়োগ করার সুবিধাও যোগ করে যা রাষ্ট্রকে অলস করে তোলে কারণ UI রাজ্যের একজন সংগ্রাহক থাকলেই রাষ্ট্র উৎপন্ন হয়।
এর UI এর জন্য অনন্য AuthorViewModel শুধুমাত্র লেখক নেভিগেশন গন্তব্যের জন্য প্রযোজ্য এবং অন্য কোথাও পুনরায় ব্যবহার করা যাবে না। যদি কোনো ব্যবসায়িক যুক্তি থাকে যা নেভিগেশন গন্তব্য জুড়ে পুনঃব্যবহৃত হয়, তাহলে সেই ব্যবসায়িক যুক্তিটিকে অবশ্যই একটি ডেটা- বা ডোমেন-লেয়ার-স্কোপড কম্পোনেন্টে এনক্যাপসুলেট করতে হবে।

একটি ব্যবসায়িক যুক্তি রাষ্ট্র ধারক হিসাবে ViewModel

অ্যান্ড্রয়েড ডেভেলপমেন্টে ViewModels-এর সুবিধাগুলি তাদের ব্যবসায়িক যুক্তিতে অ্যাক্সেস প্রদান এবং স্ক্রিনে উপস্থাপনের জন্য অ্যাপ্লিকেশন ডেটা প্রস্তুত করার জন্য উপযুক্ত করে তোলে। এই সুবিধাগুলির মধ্যে নিম্নলিখিতগুলি অন্তর্ভুক্ত রয়েছে:

  • ViewModels দ্বারা ট্রিগার করা অপারেশনগুলি কনফিগারেশন পরিবর্তন থেকে বেঁচে থাকে।
  • ন্যাভিগেশনের সাথে একীকরণ:
    • নেভিগেশন ViewModels কে ক্যাশে করে যখন স্ক্রীনটি ব্যাক স্ট্যাকের উপর থাকে। আপনি যখন আপনার গন্তব্যে ফিরে যাবেন তখন আপনার পূর্বে লোড করা ডেটা অবিলম্বে উপলব্ধ হওয়া গুরুত্বপূর্ণ। কম্পোজেবল স্ক্রিনের জীবনচক্র অনুসরণ করে এমন একটি রাষ্ট্র ধারকের সাথে এটি করা আরও কঠিন।
    • আপনার স্টেট স্বয়ংক্রিয়ভাবে পরিষ্কার করা নিশ্চিত করে, যখন গন্তব্যটি ব্যাক স্ট্যাকের থেকে পপ করা হয় তখন ViewModelটিও সাফ করা হয়। এটি সংমিশ্রণযোগ্য নিষ্পত্তির জন্য শোনার থেকে আলাদা যা একাধিক কারণে ঘটতে পারে যেমন একটি নতুন স্ক্রিনে যাওয়া, কনফিগারেশন পরিবর্তনের কারণে বা অন্যান্য কারণে।
  • অন্যান্য জেটপ্যাক লাইব্রেরির সাথে ইন্টিগ্রেশন যেমন হিল্ট

UI লজিক এবং এর স্টেট হোল্ডার

UI লজিক হল লজিক যা UI নিজেই সরবরাহ করে এমন ডেটার উপর কাজ করে। এটি UI উপাদানগুলির অবস্থাতে বা অনুমতি API বা Resources মতো UI ডেটা উত্সগুলিতে হতে পারে৷ স্টেট হোল্ডার যারা UI লজিক ব্যবহার করে তাদের সাধারণত নিম্নলিখিত বৈশিষ্ট্য থাকে:

  • UI অবস্থা তৈরি করে এবং UI উপাদানগুলির অবস্থা পরিচালনা করে
  • Activity রিক্রিয়েশনে টিকে থাকে না : UI লজিকে হোস্ট করা স্টেট হোল্ডাররা প্রায়শই UI থেকে ডেটা সোর্সের উপর নির্ভর করে এবং কনফিগারেশন জুড়ে এই তথ্যটি ধরে রাখার চেষ্টা করার ফলে মেমরি লিক হয় না। যদি স্টেট হোল্ডারদের কনফিগারেশন পরিবর্তনগুলি জুড়ে থাকার জন্য ডেটার প্রয়োজন হয়, তবে তাদের বেঁচে থাকা Activity বিনোদনের জন্য আরও উপযুক্ত অন্য উপাদানে অর্পণ করতে হবে। উদাহরণ স্বরূপ জেটপ্যাক কম্পোজে, remembered ফাংশনগুলির সাথে তৈরি কম্পোজেবল UI এলিমেন্ট স্টেটগুলি প্রায়ই Activity রিক্রিয়েশন জুড়ে স্টেট সংরক্ষণের জন্য rememberSaveable করার জন্য অর্পণ করে। এই ধরনের ফাংশনগুলির উদাহরণের মধ্যে রয়েছে rememberScaffoldState() এবং rememberLazyListState()
  • ডেটার UI স্কোপযুক্ত উত্সগুলির উল্লেখ রয়েছে : লাইফসাইকেল API এবং সংস্থানগুলির মতো ডেটার উত্সগুলি নিরাপদে উল্লেখ করা যেতে পারে এবং পড়া যেতে পারে কারণ UI লজিক স্টেট হোল্ডারের UI-এর মতো একই জীবনচক্র রয়েছে৷
  • একাধিক UI জুড়ে পুনরায় ব্যবহারযোগ্য : একই UI লজিক স্টেট ধারকের বিভিন্ন উদাহরণ অ্যাপের বিভিন্ন অংশে পুনরায় ব্যবহার করা যেতে পারে। উদাহরণস্বরূপ, একটি চিপ গোষ্ঠীর জন্য ব্যবহারকারীর ইনপুট ইভেন্টগুলি পরিচালনা করার জন্য একটি রাষ্ট্র ধারক ফিল্টার চিপগুলির জন্য একটি অনুসন্ধান পৃষ্ঠায় এবং একটি ইমেল গ্রহণকারীদের জন্য "টু" ক্ষেত্রের জন্য ব্যবহার করা যেতে পারে।

UI লজিক স্টেট হোল্ডার সাধারণত একটি প্লেইন ক্লাসের সাথে প্রয়োগ করা হয়। এর কারণ হল UI নিজেই UI লজিক স্টেট হোল্ডার তৈরির জন্য দায়ী এবং UI লজিক স্টেট হোল্ডারের UI এর মতোই একই জীবনচক্র রয়েছে। উদাহরণ স্বরূপ জেটপ্যাক কম্পোজে, স্টেট হোল্ডার কম্পোজিশনের অংশ এবং কম্পোজিশনের জীবনচক্র অনুসরণ করে।

উপরোক্ত নমুনা এন্ড্রয়েড নমুনায় নিম্নলিখিত উদাহরণে এটি চিত্রিত করা যেতে পারে:

এখন অ্যান্ড্রয়েডে ইউআই লজিক পরিচালনা করতে একটি প্লেইন ক্লাস স্টেট হোল্ডার ব্যবহার করে
চিত্র 5 : দ্য নাউ ইন অ্যান্ড্রয়েড নমুনা অ্যাপ

Now in Android নমুনা ডিভাইসের স্ক্রিনের আকারের উপর নির্ভর করে এর নেভিগেশনের জন্য একটি নীচের অ্যাপ বার বা একটি নেভিগেশন রেল দেখায়৷ ছোট স্ক্রীনগুলি নীচের অ্যাপ বার এবং বড় স্ক্রীনগুলি নেভিগেশন রেল ব্যবহার করে৷

যেহেতু NiaApp কম্পোজেবল ফাংশনে ব্যবহৃত উপযুক্ত নেভিগেশন UI উপাদানের সিদ্ধান্ত নেওয়ার যুক্তি ব্যবসায়িক যুক্তির উপর নির্ভর করে না, তাই এটি NiaAppState নামক একটি প্লেইন ক্লাস স্টেট হোল্ডার দ্বারা পরিচালিত হতে পারে:

@Stable
class NiaAppState(
    val navController: NavHostController,
    val windowSizeClass: WindowSizeClass
) {

    // UI logic
    val shouldShowBottomBar: Boolean
        get() = windowSizeClass.widthSizeClass == WindowWidthSizeClass.Compact ||
            windowSizeClass.heightSizeClass == WindowHeightSizeClass.Compact

    // UI logic
    val shouldShowNavRail: Boolean
        get() = !shouldShowBottomBar

   // UI State
    val currentDestination: NavDestination?
        @Composable get() = navController
            .currentBackStackEntryAsState().value?.destination

    // UI logic
    fun navigate(destination: NiaNavigationDestination, route: String? = null) { /* ... */ }

     /* ... */
}

উপরের উদাহরণে, NiaAppState সম্পর্কিত নিম্নলিখিত বিবরণগুলি উল্লেখযোগ্য:

  • Activity রিক্রিয়েশনে টিকে না : NiaAppState কম্পোজেবল ফাংশন rememberNiaAppState দিয়ে কম্পোজ নামকরণের নিয়ম অনুসরণ করে কম্পোজিশনে remembered হয়। Activity পুনরায় তৈরি করার পরে, পূর্বের দৃষ্টান্তটি হারিয়ে যায় এবং একটি নতুন দৃষ্টান্ত তৈরি করা হয় যার সমস্ত নির্ভরতা পাস করা হয়, যা পুনরায় তৈরি করা Activity নতুন কনফিগারেশনের জন্য উপযুক্ত৷ এই নির্ভরতাগুলি নতুন বা পূর্ববর্তী কনফিগারেশন থেকে পুনরুদ্ধার করা হতে পারে। উদাহরণ স্বরূপ, NiaAppState কনস্ট্রাক্টরে rememberNavController() ব্যবহার করা হয় এবং এটি Activity রিক্রিয়েশন জুড়ে স্টেট সংরক্ষণ করার জন্য rememberSaveable জন্য ডেলিগেট করে।
  • ডেটার UI স্কোপযুক্ত উত্সগুলির রেফারেন্স রয়েছে : navigationController , Resources এবং অন্যান্য অনুরূপ লাইফসাইকেল স্কোপড প্রকারের উল্লেখগুলি NiaAppState এ নিরাপদে রাখা যেতে পারে কারণ তারা একই জীবনচক্রের সুযোগ ভাগ করে নেয়৷

একটি স্টেট হোল্ডারের জন্য একটি ViewModel এবং প্লেইন ক্লাসের মধ্যে বেছে নিন

উপরের বিভাগগুলি থেকে, একটি ViewModel এবং একটি প্লেইন ক্লাস স্টেট হোল্ডারের মধ্যে নির্বাচন করা UI স্টেটে প্রয়োগ করা যুক্তি এবং লজিকটি কাজ করে এমন ডেটার উত্সগুলিতে নেমে আসে৷

সংক্ষেপে, নীচের চিত্রটি UI রাজ্য উত্পাদন পাইপলাইনে রাজ্য ধারকদের অবস্থান দেখায়:

ডেটা উৎপাদনকারী স্তর থেকে UI স্তরে ডেটা প্রবাহিত হয়
চিত্র 6 : UI রাজ্য উত্পাদন পাইপলাইনে রাজ্য ধারক৷ তীর মানে ডেটা প্রবাহ।

শেষ পর্যন্ত, যেখানে এটি খাওয়া হয় তার নিকটতম রাষ্ট্র ধারকদের ব্যবহার করে আপনার UI অবস্থা তৈরি করা উচিত । কম আনুষ্ঠানিকভাবে, যথাযথ মালিকানা বজায় রেখে আপনার রাষ্ট্রকে যতটা সম্ভব কম রাখা উচিত। আপনার যদি ব্যবসায়িক যুক্তিতে অ্যাক্সেসের প্রয়োজন হয় এবং যতক্ষণ পর্যন্ত একটি স্ক্রীন নেভিগেট করা যেতে পারে ততক্ষণ পর্যন্ত UI অবস্থার প্রয়োজন হয়, এমনকি Activity রিক্রিয়েশন জুড়ে, একটি ViewModel আপনার ব্যবসার লজিক স্টেট ধারক বাস্তবায়নের জন্য একটি দুর্দান্ত পছন্দ। স্বল্পস্থায়ী UI অবস্থা এবং UI লজিকের জন্য, একটি সাধারণ শ্রেণি যার জীবনচক্র শুধুমাত্র UI-এর উপর নির্ভরশীল।

রাষ্ট্রের ধারক চক্রবৃদ্ধিযোগ্য

রাষ্ট্র ধারক অন্যান্য রাষ্ট্র ধারকদের উপর নির্ভর করতে পারেন যতক্ষণ না নির্ভরতাগুলির সমান বা ছোট জীবনকাল থাকে। এর উদাহরণ হল:

  • একটি UI লজিক স্টেট হোল্ডার অন্য UI লজিক স্টেট হোল্ডারের উপর নির্ভর করতে পারে।
  • একটি স্ক্রীন লেভেল স্টেট হোল্ডার একটি UI লজিক স্টেট হোল্ডারের উপর নির্ভর করতে পারে।

নিম্নোক্ত কোড স্নিপেট দেখায় যে কীভাবে কম্পোজের DrawerState অন্য অভ্যন্তরীণ স্টেট হোল্ডার, SwipeableState এর উপর নির্ভর করে এবং কীভাবে একটি অ্যাপের UI লজিক স্টেট ধারক DrawerState উপর নির্ভর করতে পারে:

@Stable
class DrawerState(/* ... */) {
  internal val swipeableState = SwipeableState(/* ... */)
  // ...
}

@Stable
class MyAppState(
  private val drawerState: DrawerState,
  private val navController: NavHostController
) { /* ... */ }

@Composable
fun rememberMyAppState(
  drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed),
  navController: NavHostController = rememberNavController()
): MyAppState = remember(drawerState, navController) {
  MyAppState(drawerState, navController)
}

স্ক্রীন লেভেল স্টেট হোল্ডারের উপর নির্ভর করে একটি নির্ভরশীলতার উদাহরণ যা একজন স্টেট হোল্ডারকে UI লজিক স্টেট হোল্ডার হতে পারে। এটি স্বল্পকালীন রাষ্ট্র ধারকের পুনঃব্যবহারযোগ্যতা হ্রাস করবে এবং এটিকে প্রকৃতপক্ষে প্রয়োজনের চেয়ে আরও বেশি যুক্তি এবং রাষ্ট্রে অ্যাক্সেস দেবে।

যদি স্বল্পকালীন রাষ্ট্র ধারকের একটি উচ্চ-স্কোপযুক্ত রাষ্ট্র ধারকের কাছ থেকে নির্দিষ্ট তথ্যের প্রয়োজন হয়, তবে রাষ্ট্র ধারকের উদাহরণটি পাস করার পরিবর্তে একটি প্যারামিটার হিসাবে তার প্রয়োজনীয় তথ্যগুলি পাস করুন। উদাহরণস্বরূপ, নিম্নলিখিত কোড স্নিপেটে, UI লজিক স্টেট হোল্ডার ক্লাস নির্ভরতা হিসাবে পুরো ViewModel ইন্সট্যান্সকে পাস করার পরিবর্তে ViewModel থেকে প্যারামিটার হিসাবে যা প্রয়োজন তা পায়।

class MyScreenViewModel(/* ... */) {
  val uiState: StateFlow<MyScreenUiState> = /* ... */
  fun doSomething() { /* ... */ }
  fun doAnotherThing() { /* ... */ }
  // ...
}

@Stable
class MyScreenState(
  // DO NOT pass a ViewModel instance to a plain state holder class
  // private val viewModel: MyScreenViewModel,

  // Instead, pass only what it needs as a dependency
  private val someState: StateFlow<SomeState>,
  private val doSomething: () -> Unit,

  // Other UI-scoped types
  private val scaffoldState: ScaffoldState
) {
  /* ... */
}

@Composable
fun rememberMyScreenState(
  someState: StateFlow<SomeState>,
  doSomething: () -> Unit,
  scaffoldState: ScaffoldState = rememberScaffoldState()
): MyScreenState = remember(someState, doSomething, scaffoldState) {
  MyScreenState(someState, doSomething, scaffoldState)
}

@Composable
fun MyScreen(
  modifier: Modifier = Modifier,
  viewModel: MyScreenViewModel = viewModel(),
  state: MyScreenState = rememberMyScreenState(
    someState = viewModel.uiState.map { it.toSomeState() },
    doSomething = viewModel::doSomething
  ),
  // ...
) {
  /* ... */
}

নিম্নলিখিত চিত্রটি UI এবং পূর্ববর্তী কোড স্নিপেটের বিভিন্ন রাজ্য ধারকদের মধ্যে নির্ভরতা উপস্থাপন করে:

UI লজিক স্টেট হোল্ডার এবং স্ক্রীন লেভেল স্টেট হোল্ডার উভয়ের উপর নির্ভর করে
চিত্র 7 : UI বিভিন্ন রাজ্য ধারকদের উপর নির্ভর করে। তীর মানে নির্ভরতা।

নমুনা

নিম্নলিখিত Google নমুনাগুলি UI স্তরে রাষ্ট্র ধারকদের ব্যবহার প্রদর্শন করে৷ অনুশীলনে এই নির্দেশিকা দেখতে তাদের অন্বেষণ করুন:

{% শব্দার্থে %} {% endverbatim %} {% শব্দার্থে %} {% endverbatim %}