রাজ্য এবং জেটপ্যাক রচনা

একটি অ্যাপ্লিকেশানের অবস্থা হল যেকোনো মান যা সময়ের সাথে সাথে পরিবর্তিত হতে পারে। এটি একটি খুব বিস্তৃত সংজ্ঞা এবং এটি একটি রুম ডাটাবেস থেকে শুরু করে একটি ক্লাসের একটি পরিবর্তনশীল পর্যন্ত সবকিছুকে অন্তর্ভুক্ত করে।

সমস্ত অ্যান্ড্রয়েড অ্যাপ ব্যবহারকারীর কাছে স্থিতি প্রদর্শন করে। অ্যান্ড্রয়েড অ্যাপে রাজ্যের কয়েকটি উদাহরণ:

  • একটি স্ন্যাকবার যা দেখায় কখন একটি নেটওয়ার্ক সংযোগ স্থাপন করা যায় না৷
  • একটি ব্লগ পোস্ট এবং সংশ্লিষ্ট মন্তব্য.
  • বোতামে রিপল অ্যানিমেশন যা একজন ব্যবহারকারী ক্লিক করলে প্লে হয়।
  • স্টিকার যা একজন ব্যবহারকারী একটি ছবির উপরে আঁকতে পারেন।

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

রাষ্ট্র এবং রচনা

রচনাটি ঘোষণামূলক এবং এটি আপডেট করার একমাত্র উপায় হল নতুন আর্গুমেন্টের সাথে একই কম্পোজযোগ্য কল করা। এই আর্গুমেন্ট হল UI রাজ্যের প্রতিনিধিত্ব। যে কোন সময় একটি রাষ্ট্র আপডেট করা হয় একটি পুনর্গঠন সঞ্চালিত হয়. ফলস্বরূপ, TextField মতো জিনিসগুলি স্বয়ংক্রিয়ভাবে আপডেট হয় না যেমন তারা অপরিহার্য XML ভিত্তিক ভিউতে করে। সেই অনুযায়ী আপডেট করার জন্য একটি কম্পোজেবলকে স্পষ্টভাবে নতুন অবস্থা বলতে হবে।

@Composable
private fun HelloContent() {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello!",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.bodyMedium
        )
        OutlinedTextField(
            value = "",
            onValueChange = { },
            label = { Text("Name") }
        )
    }
}

আপনি যদি এটি চালান এবং পাঠ্য প্রবেশ করার চেষ্টা করেন, আপনি দেখতে পাবেন যে কিছুই হবে না। এর কারণ TextField নিজেকে আপডেট করে না - এটি আপডেট হয় যখন এর value প্যারামিটার পরিবর্তন হয়। এটি কম্পোজে কম্পোজিশন এবং রিকম্পোজিশন কিভাবে কাজ করে তার কারণে।

প্রাথমিক রচনা এবং পুনর্গঠন সম্পর্কে আরও জানতে, রচনায় চিন্তাভাবনা দেখুন।

কম্পোজেবল রাজ্য

কম্পোজেবল ফাংশন মেমরিতে একটি বস্তু সংরক্ষণ করতে remember API ব্যবহার করতে পারে। remember দ্বারা গণনা করা একটি মান প্রাথমিক রচনার সময় কম্পোজিশনে সংরক্ষণ করা হয় এবং সংরক্ষিত মানটি পুনর্গঠনের সময় ফেরত দেওয়া হয়। remember পরিবর্তনযোগ্য এবং অপরিবর্তনীয় উভয় বস্তু সংরক্ষণ করতে ব্যবহার করা যেতে পারে।

mutableStateOf একটি পর্যবেক্ষণযোগ্য MutableState<T> তৈরি করে, যা কম্পোজ রানটাইমের সাথে একত্রিত একটি পর্যবেক্ষণযোগ্য প্রকার।

interface MutableState<T> : State<T> {
    override var value: T
}

value পড়া যে কোনো কম্পোজযোগ্য ফাংশন এর value সময়সূচী পুনর্গঠন কোনো পরিবর্তন.

একটি কম্পোজেবলে একটি MutableState অবজেক্ট ঘোষণা করার তিনটি উপায় রয়েছে:

  • val mutableState = remember { mutableStateOf(default) }
  • var value by remember { mutableStateOf(default) }
  • val (value, setValue) = remember { mutableStateOf(default) }

এই ঘোষণাগুলি সমতুল্য, এবং রাষ্ট্রের বিভিন্ন ব্যবহারের জন্য সিনট্যাক্স চিনি হিসাবে সরবরাহ করা হয়। আপনি যে কম্পোজেবল লিখছেন তাতে সবচেয়ে সহজে পড়ার কোড তৈরি করে এমন একটি বেছে নেওয়া উচিত।

by ডেলিগেট সিনট্যাক্সের জন্য নিম্নলিখিত আমদানি প্রয়োজন:

import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

কোন কম্পোজেবলগুলি প্রদর্শিত হবে তা পরিবর্তন করতে আপনি অন্যান্য কম্পোজেবলের প্যারামিটার বা এমনকি বিবৃতিতে যুক্তি হিসাবে মনে রাখা মান ব্যবহার করতে পারেন। উদাহরণস্বরূপ, নামটি খালি থাকলে আপনি যদি অভিবাদনটি প্রদর্শন করতে না চান তবে একটি if বিবৃতিতে রাষ্ট্রটি ব্যবহার করুন:

@Composable
fun HelloContent() {
    Column(modifier = Modifier.padding(16.dp)) {
        var name by remember { mutableStateOf("") }
        if (name.isNotEmpty()) {
            Text(
                text = "Hello, $name!",
                modifier = Modifier.padding(bottom = 8.dp),
                style = MaterialTheme.typography.bodyMedium
            )
        }
        OutlinedTextField(
            value = name,
            onValueChange = { name = it },
            label = { Text("Name") }
        )
    }
}

যদিও remember আপনাকে পুনর্গঠন জুড়ে স্থিতি বজায় রাখতে সহায়তা করে, তবে কনফিগারেশন পরিবর্তনগুলির মধ্যে রাজ্যটি বজায় রাখা হয় না। এর জন্য, আপনাকে rememberSaveable ব্যবহার করতে হবে। rememberSaveable স্বয়ংক্রিয়ভাবে যে কোনও মান সংরক্ষণ করে যা একটি Bundle সংরক্ষণ করা যেতে পারে। অন্যান্য মানগুলির জন্য, আপনি একটি কাস্টম সেভার অবজেক্টে পাস করতে পারেন।

রাষ্ট্রের অন্যান্য সমর্থিত প্রকার

রচনার প্রয়োজন নেই যে আপনি স্থিতি ধরে রাখতে MutableState<T> ব্যবহার করবেন; এটি অন্যান্য পর্যবেক্ষণযোগ্য ধরনের সমর্থন করে। কম্পোজে আরেকটি পর্যবেক্ষণযোগ্য টাইপ পড়ার আগে, আপনাকে অবশ্যই এটিকে একটি State<T> এ রূপান্তর করতে হবে যাতে কম্পোজেবলগুলি স্বয়ংক্রিয়ভাবে কম্পোজ করতে পারে যখন স্টেট পরিবর্তন হয়।

Android অ্যাপ্লিকেশানগুলিতে ব্যবহৃত সাধারণ পর্যবেক্ষণযোগ্য প্রকারগুলি থেকে State<T> তৈরি করতে ফাংশন সহ জাহাজগুলি রচনা করুন৷ এই ইন্টিগ্রেশনগুলি ব্যবহার করার আগে, নীচের রূপরেখা অনুযায়ী উপযুক্ত নিদর্শন (গুলি) যোগ করুন:

  • Flow : collectAsStateWithLifecycle()

    collectAsStateWithLifecycle() একটি লাইফসাইকেল-সচেতন পদ্ধতিতে একটি Flow থেকে মান সংগ্রহ করে, যা আপনার অ্যাপকে অ্যাপ সংস্থান সংরক্ষণ করতে দেয়। এটি কম্পোজ State থেকে সর্বশেষ নির্গত মান উপস্থাপন করে। Android অ্যাপ্লিকেশানগুলিতে ফ্লো সংগ্রহ করার প্রস্তাবিত উপায় হিসাবে এই APIটি ব্যবহার করুন৷

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন (এটি 2.6.0-beta01 বা নতুন হওয়া উচিত):

কোটলিন

dependencies {
      ...
      implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.7")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.7"
}
  • Flow : collectAsState()

    collectAsState হল collectAsStateWithLifecycle এর অনুরূপ, কারণ এটি একটি Flow থেকে মান সংগ্রহ করে এবং কম্পোজ State রূপান্তরিত করে।

    প্ল্যাটফর্ম-অজ্ঞেয়বাদী কোডের জন্য collectAsStateWithLifecycle এর পরিবর্তে collectAsState ব্যবহার করুন, যা শুধুমাত্র Android-এর জন্য।

    collectAsState জন্য অতিরিক্ত নির্ভরতার প্রয়োজন নেই, কারণ এটি compose-runtime উপলব্ধ।

  • LiveData : observeAsState()

    observeAsState() এই LiveData পর্যবেক্ষণ করা শুরু করে এবং State মাধ্যমে এর মানগুলিকে উপস্থাপন করে।

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন:

কোটলিন

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-livedata:1.8.1")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-livedata:1.8.1"
}
  • RxJava2 : subscribeAsState()

    subscribeAsState() হল এক্সটেনশন ফাংশন যা RxJava2 এর প্রতিক্রিয়াশীল স্ট্রীমগুলিকে (যেমন Single , Observable , Completable ) কম্পোজ State রূপান্তরিত করে।

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন:

কোটলিন

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-rxjava2:1.8.1")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-rxjava2:1.8.1"
}
  • RxJava3 : subscribeAsState()

    subscribeAsState() হল এক্সটেনশন ফাংশন যা RxJava3 এর প্রতিক্রিয়াশীল স্ট্রীমগুলিকে (যেমন Single , Observable , Completable ) কম্পোজ State রূপান্তরিত করে।

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন:

কোটলিন

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-rxjava3:1.8.1")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-rxjava3:1.8.1"
}

রাষ্ট্রীয় বনাম রাষ্ট্রহীন

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

একটি স্টেটলেস কম্পোজেবল হল একটি কম্পোজেবল যা কোনো স্টেট ধরে না। রাষ্ট্রহীনতা অর্জনের একটি সহজ উপায় হল রাষ্ট্র উত্তোলন ব্যবহার করা।

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

রাজ্য উত্তোলন

কম্পোজে স্টেট হোস্টিং হল একটি কম্পোজেবল স্টেটলেস করার জন্য কম্পোজেবলের কলারে স্টেট সরানোর একটি প্যাটার্ন। জেটপ্যাক কম্পোজে স্টেট হোস্টিং এর সাধারণ প্যাটার্ন হল স্টেট ভেরিয়েবলকে দুটি প্যারামিটার দিয়ে প্রতিস্থাপন করা:

  • value: T : প্রদর্শনের জন্য বর্তমান মান
  • onValueChange: (T) -> Unit : একটি ইভেন্ট যা মান পরিবর্তনের অনুরোধ করে, যেখানে T হল প্রস্তাবিত নতুন মান

যাইহোক, আপনি onValueChange এ সীমাবদ্ধ নন। যদি আরও নির্দিষ্ট ঘটনাগুলি কম্পোজেবলের জন্য উপযুক্ত হয়, তাহলে আপনাকে ল্যাম্বডাস ব্যবহার করে সেগুলি সংজ্ঞায়িত করা উচিত।

এইভাবে উত্তোলিত রাজ্যের কিছু গুরুত্বপূর্ণ বৈশিষ্ট্য রয়েছে:

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

উদাহরণের ক্ষেত্রে, আপনি HelloContent থেকে name এবং onValueChange বের করুন এবং সেগুলিকে একটি HelloScreen কম্পোজেবলে নিয়ে যান যেটিকে HelloContent বলে।

@Composable
fun HelloScreen() {
    var name by rememberSaveable { mutableStateOf("") }

    HelloContent(name = name, onNameChange = { name = it })
}

@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello, $name",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.bodyMedium
        )
        OutlinedTextField(value = name, onValueChange = onNameChange, label = { Text("Name") })
    }
}

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

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

আরও জানতে রাজ্যের পৃষ্ঠাটি কোথায় উত্তোলন করবেন তা দেখুন।

রচনায় স্থিতি পুনরুদ্ধার করা হচ্ছে

rememberSaveable এপিআই remember মতো আচরণ করে কারণ এটি সংরক্ষিত ইনস্ট্যান্স স্টেট মেকানিজম ব্যবহার করে পুনর্গঠন জুড়ে এবং কার্যকলাপ বা প্রক্রিয়া বিনোদন জুড়ে অবস্থা বজায় রাখে। উদাহরণস্বরূপ, এটি ঘটে, যখন স্ক্রিনটি ঘোরানো হয়।

রাষ্ট্র সংরক্ষণের উপায়

Bundle যোগ করা সমস্ত ডেটা প্রকার স্বয়ংক্রিয়ভাবে সংরক্ষিত হয়। আপনি যদি এমন কিছু সংরক্ষণ করতে চান যা Bundle যোগ করা যায় না, সেখানে বেশ কয়েকটি বিকল্প রয়েছে।

পার্সেলাইজ করুন

সহজ সমাধান হল অবজেক্টে @Parcelize টীকা যোগ করা। বস্তুটি parcelable হয়ে যায়, এবং বান্ডিল করা যায়। উদাহরণস্বরূপ, এই কোডটি একটি পার্সেলযোগ্য City ডেটা টাইপ তৈরি করে এবং এটি রাজ্যে সংরক্ষণ করে।

@Parcelize
data class City(val name: String, val country: String) : Parcelable

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

ম্যাপসেভার

যদি কোনো কারণে @Parcelize উপযুক্ত না হয়, তাহলে আপনি একটি বস্তুকে মানগুলির একটি সেটে রূপান্তর করার জন্য আপনার নিজস্ব নিয়ম সংজ্ঞায়িত করতে mapSaver ব্যবহার করতে পারেন যা সিস্টেম Bundle সংরক্ষণ করতে পারে।

data class City(val name: String, val country: String)

val CitySaver = run {
    val nameKey = "Name"
    val countryKey = "Country"
    mapSaver(
        save = { mapOf(nameKey to it.name, countryKey to it.country) },
        restore = { City(it[nameKey] as String, it[countryKey] as String) }
    )
}

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable(stateSaver = CitySaver) {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

লিস্টসেভার

মানচিত্রের জন্য কীগুলি সংজ্ঞায়িত করার প্রয়োজন এড়াতে, আপনি listSaver ব্যবহার করতে পারেন এবং কী হিসাবে এর সূচকগুলি ব্যবহার করতে পারেন:

data class City(val name: String, val country: String)

val CitySaver = listSaver<City, Any>(
    save = { listOf(it.name, it.country) },
    restore = { City(it[0] as String, it[1] as String) }
)

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable(stateSaver = CitySaver) {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

কম্পোজ রাষ্ট্র ধারক

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

আরও জানতে আর্কিটেকচার গাইডে কম্পোজ ডকুমেন্টেশনে স্টেট হোস্টিং দেখুন বা, আরও সাধারণভাবে, স্টেট হোল্ডার এবং ইউআই স্টেট পৃষ্ঠা দেখুন।

কী পরিবর্তন হলে রিট্রিগার গণনা মনে রাখবেন

remember API প্রায়শই MutableState সাথে একসাথে ব্যবহার করা হয়:

var name by remember { mutableStateOf("") }

এখানে, remember ফাংশন ব্যবহার করে MutableState মানকে পুনর্গঠন করে।

সাধারণভাবে, remember একটি calculation ল্যাম্বডা প্যারামিটার লাগে। যখন remember প্রথম চালানো হয়, এটি calculation ল্যাম্বডাকে আহ্বান করে এবং এর ফলাফল সংরক্ষণ করে। পুনর্গঠনের সময়, remember যে মানটি শেষ সংরক্ষিত ছিল।

ক্যাশিং স্টেট ছাড়াও, আপনি কম্পোজিশনে যেকোন বস্তু বা অপারেশনের ফলাফল সংরক্ষণ করতে remember ব্যবহার করতে পারেন যা শুরু বা গণনা করা ব্যয়বহুল। আপনি হয়ত প্রতিটি পুনর্গঠনে এই গণনার পুনরাবৃত্তি করতে চান না। একটি উদাহরণ এই ShaderBrush অবজেক্ট তৈরি করছে, যা একটি ব্যয়বহুল অপারেশন:

val brush = remember {
    ShaderBrush(
        BitmapShader(
            ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(),
            Shader.TileMode.REPEAT,
            Shader.TileMode.REPEAT
        )
    )
}

remember মান সংরক্ষণ করে যতক্ষণ না এটি রচনাটি ছেড়ে যায়। যাইহোক, ক্যাশে মান অবৈধ করার একটি উপায় আছে। remember API একটি key বা keys প্যারামিটারও নেয়। যদি এই কীগুলির যেকোনও পরিবর্তন হয়, পরের বার ফাংশনটি পুনর্গঠিত হলে , remember ক্যাশে অকার্যকর করে এবং গণনা ল্যাম্বডা ব্লক আবার চালায় । এই প্রক্রিয়াটি আপনাকে কম্পোজিশনের একটি বস্তুর জীবনকালের উপর নিয়ন্ত্রণ দেয়। ইনপুট পরিবর্তন না হওয়া পর্যন্ত গণনা বৈধ থাকে, যতক্ষণ না মনে রাখা মান রচনাটি ছেড়ে যায়।

নিম্নলিখিত উদাহরণগুলি দেখায় যে এই প্রক্রিয়াটি কীভাবে কাজ করে।

এই স্নিপেটে, একটি ShaderBrush তৈরি করা হয় এবং একটি Box কম্পোজেবলের ব্যাকগ্রাউন্ড পেইন্ট হিসাবে ব্যবহার করা হয়। remember ShaderBrush দৃষ্টান্ত সংরক্ষণ করুন কারণ এটি পুনরায় তৈরি করা ব্যয়বহুল, যেমনটি আগে ব্যাখ্যা করা হয়েছে। remember avatarRes key1 প্যারামিটার হিসেবে নেয়, যা নির্বাচিত ব্যাকগ্রাউন্ড ইমেজ। যদি avatarRes পরিবর্তিত হয়, ব্রাশটি নতুন চিত্রের সাথে পুনরায় সংমিশ্রিত হয় এবং Box পুনরায় প্রয়োগ করা হয়। এটি ঘটতে পারে যখন ব্যবহারকারী একটি পিকার থেকে ব্যাকগ্রাউন্ড হতে অন্য একটি ছবি নির্বাচন করেন।

@Composable
private fun BackgroundBanner(
    @DrawableRes avatarRes: Int,
    modifier: Modifier = Modifier,
    res: Resources = LocalContext.current.resources
) {
    val brush = remember(key1 = avatarRes) {
        ShaderBrush(
            BitmapShader(
                ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(),
                Shader.TileMode.REPEAT,
                Shader.TileMode.REPEAT
            )
        )
    }

    Box(
        modifier = modifier.background(brush)
    ) {
        /* ... */
    }
}

পরবর্তী স্নিপেটে, স্টেটকে একটি প্লেইন স্টেট হোল্ডার ক্লাস MyAppState এ উত্তোলন করা হয়। এটি remember ব্যবহার করে ক্লাসের একটি ইন্সট্যান্স আরম্ভ করার জন্য একটি rememberMyAppState ফাংশন প্রকাশ করে। কম্পোজে টিকে থাকা একটি দৃষ্টান্ত তৈরি করতে এই ধরনের ফাংশনগুলিকে প্রকাশ করা কম্পোজের একটি সাধারণ প্যাটার্ন। rememberMyAppState ফাংশন windowSizeClass পায়, যা remember key প্যারামিটার হিসেবে কাজ করে। যদি এই প্যারামিটারটি পরিবর্তিত হয়, অ্যাপটিকে সাম্প্রতিক মান সহ প্লেইন স্টেট হোল্ডার ক্লাস পুনরায় তৈরি করতে হবে। এটি ঘটতে পারে যদি, উদাহরণস্বরূপ, ব্যবহারকারী ডিভাইসটি ঘোরান।

@Composable
private fun rememberMyAppState(
    windowSizeClass: WindowSizeClass
): MyAppState {
    return remember(windowSizeClass) {
        MyAppState(windowSizeClass)
    }
}

@Stable
class MyAppState(
    private val windowSizeClass: WindowSizeClass
) { /* ... */ }

একটি কী পরিবর্তিত হয়েছে কিনা তা নির্ধারণ করতে এবং সঞ্চিত মানটিকে অবৈধ করে কিনা তা নির্ধারণ করতে কম্পোজ ক্লাসের সমান বাস্তবায়ন ব্যবহার করে।

পুনঃগঠনের বাইরে কী সহ স্টেট স্টোর করুন

rememberSaveable এপিআই হল remember চারপাশে একটি মোড়ক যা একটি Bundle ডেটা সংরক্ষণ করতে পারে। এই এপিআই রাষ্ট্রকে শুধুমাত্র পুনর্গঠনই নয়, ক্রিয়াকলাপ বিনোদন এবং সিস্টেম-প্রবর্তিত প্রক্রিয়ার মৃত্যুতেও বেঁচে থাকতে দেয়। rememberSaveable একই উদ্দেশ্যে input পরামিতি গ্রহণ করে যা remember keys গ্রহণ করে। কোনো ইনপুট পরিবর্তন হলে ক্যাশে অবৈধ হয়ে যায় । পরের বার যখন ফাংশনটি পুনরায় কম্পোজ করা হয়, rememberSaveable গণনা ল্যাম্বডা ব্লকটিকে পুনরায় কার্যকর করে।

নিম্নলিখিত উদাহরণে, typedQuery পরিবর্তন না হওয়া পর্যন্ত rememberSaveable userTypedQuery সংরক্ষণ করে:

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

আরও জানুন

রাজ্য এবং জেটপ্যাক রচনা সম্পর্কে আরও জানতে, নিম্নলিখিত অতিরিক্ত সংস্থানগুলি দেখুন৷

নমুনা

কোডল্যাব

ভিডিও

ব্লগ

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

একটি অ্যাপ্লিকেশানের অবস্থা হল যেকোনো মান যা সময়ের সাথে সাথে পরিবর্তিত হতে পারে। এটি একটি খুব বিস্তৃত সংজ্ঞা এবং এটি একটি রুম ডাটাবেস থেকে শুরু করে একটি ক্লাসের একটি পরিবর্তনশীল পর্যন্ত সবকিছুকে অন্তর্ভুক্ত করে।

সমস্ত অ্যান্ড্রয়েড অ্যাপ ব্যবহারকারীর কাছে স্থিতি প্রদর্শন করে। অ্যান্ড্রয়েড অ্যাপে রাজ্যের কয়েকটি উদাহরণ:

  • একটি স্ন্যাকবার যা দেখায় কখন একটি নেটওয়ার্ক সংযোগ স্থাপন করা যায় না৷
  • একটি ব্লগ পোস্ট এবং সংশ্লিষ্ট মন্তব্য.
  • বোতামে রিপল অ্যানিমেশন যা একজন ব্যবহারকারী ক্লিক করলে প্লে হয়।
  • স্টিকার যা একজন ব্যবহারকারী একটি ছবির উপরে আঁকতে পারেন।

জেটপ্যাক রচনা আপনাকে অ্যান্ড্রয়েড অ্যাপে কোথায় এবং কীভাবে সঞ্চয় এবং ব্যবহার করে সে সম্পর্কে স্পষ্ট হতে সাহায্য করে। এই গাইডটি স্টেট এবং কম্পোজেবলের মধ্যে সংযোগের উপর এবং জেটপ্যাক কম্পোজ যে APIগুলিকে আরও সহজে রাজ্যের সাথে কাজ করার প্রস্তাব দেয় তার উপর ফোকাস করে।

রাষ্ট্র এবং রচনা

রচনাটি ঘোষণামূলক এবং এটি আপডেট করার একমাত্র উপায় হল নতুন আর্গুমেন্টের সাথে একই কম্পোজযোগ্য কল করা। এই আর্গুমেন্ট হল UI রাজ্যের প্রতিনিধিত্ব। যে কোন সময় একটি রাষ্ট্র আপডেট করা হয় একটি পুনর্গঠন সঞ্চালিত হয়. ফলস্বরূপ, TextField মতো জিনিসগুলি স্বয়ংক্রিয়ভাবে আপডেট হয় না যেমন তারা অপরিহার্য XML ভিত্তিক ভিউতে করে। সেই অনুযায়ী আপডেট করার জন্য একটি কম্পোজেবলকে স্পষ্টভাবে নতুন অবস্থা বলতে হবে।

@Composable
private fun HelloContent() {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello!",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.bodyMedium
        )
        OutlinedTextField(
            value = "",
            onValueChange = { },
            label = { Text("Name") }
        )
    }
}

আপনি যদি এটি চালান এবং পাঠ্য প্রবেশ করার চেষ্টা করেন, আপনি দেখতে পাবেন যে কিছুই হবে না। এর কারণ TextField নিজেকে আপডেট করে না - এটি আপডেট হয় যখন এর value প্যারামিটার পরিবর্তন হয়। এটি কম্পোজে কম্পোজিশন এবং রিকম্পোজিশন কিভাবে কাজ করে তার কারণে।

প্রাথমিক রচনা এবং পুনর্গঠন সম্পর্কে আরও জানতে, রচনায় চিন্তাভাবনা দেখুন।

কম্পোজেবল রাজ্য

কম্পোজেবল ফাংশন মেমরিতে একটি বস্তু সংরক্ষণ করতে remember API ব্যবহার করতে পারে। remember দ্বারা গণনা করা একটি মান প্রাথমিক রচনার সময় কম্পোজিশনে সংরক্ষণ করা হয় এবং সংরক্ষিত মানটি পুনর্গঠনের সময় ফেরত দেওয়া হয়। remember পরিবর্তনযোগ্য এবং অপরিবর্তনীয় উভয় বস্তু সংরক্ষণ করতে ব্যবহার করা যেতে পারে।

mutableStateOf একটি পর্যবেক্ষণযোগ্য MutableState<T> তৈরি করে, যা কম্পোজ রানটাইমের সাথে একত্রিত একটি পর্যবেক্ষণযোগ্য প্রকার।

interface MutableState<T> : State<T> {
    override var value: T
}

value পড়ার সময়সূচীতে কোনো পরিবর্তন যে কোনো কম্পোজযোগ্য ফাংশনের পুনর্গঠন value

একটি কম্পোজেবলে একটি MutableState অবজেক্ট ঘোষণা করার তিনটি উপায় রয়েছে:

  • val mutableState = remember { mutableStateOf(default) }
  • var value by remember { mutableStateOf(default) }
  • val (value, setValue) = remember { mutableStateOf(default) }

এই ঘোষণাগুলি সমতুল্য, এবং রাষ্ট্রের বিভিন্ন ব্যবহারের জন্য সিনট্যাক্স চিনি হিসাবে সরবরাহ করা হয়। আপনি যে কম্পোজেবল লিখছেন তাতে সবচেয়ে সহজে পড়ার কোড তৈরি করে এমন একটি বেছে নেওয়া উচিত।

by ডেলিগেট সিনট্যাক্সের জন্য নিম্নলিখিত আমদানি প্রয়োজন:

import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

কোন কম্পোজেবলগুলি প্রদর্শিত হবে তা পরিবর্তন করতে আপনি অন্যান্য কম্পোজেবলের প্যারামিটার বা এমনকি বিবৃতিতে যুক্তি হিসাবে মনে রাখা মান ব্যবহার করতে পারেন। উদাহরণস্বরূপ, নামটি খালি থাকলে আপনি যদি অভিবাদনটি প্রদর্শন করতে না চান তবে একটি if বিবৃতিতে রাষ্ট্রটি ব্যবহার করুন:

@Composable
fun HelloContent() {
    Column(modifier = Modifier.padding(16.dp)) {
        var name by remember { mutableStateOf("") }
        if (name.isNotEmpty()) {
            Text(
                text = "Hello, $name!",
                modifier = Modifier.padding(bottom = 8.dp),
                style = MaterialTheme.typography.bodyMedium
            )
        }
        OutlinedTextField(
            value = name,
            onValueChange = { name = it },
            label = { Text("Name") }
        )
    }
}

যদিও remember আপনাকে পুনর্গঠন জুড়ে স্থিতি বজায় রাখতে সহায়তা করে, তবে কনফিগারেশন পরিবর্তনগুলির মধ্যে রাজ্যটি বজায় রাখা হয় না। এর জন্য, আপনাকে rememberSaveable ব্যবহার করতে হবে। rememberSaveable স্বয়ংক্রিয়ভাবে যে কোনও মান সংরক্ষণ করে যা একটি Bundle সংরক্ষণ করা যেতে পারে। অন্যান্য মানগুলির জন্য, আপনি একটি কাস্টম সেভার অবজেক্টে পাস করতে পারেন।

রাষ্ট্রের অন্যান্য সমর্থিত প্রকার

রচনার প্রয়োজন নেই যে আপনি স্থিতি ধরে রাখতে MutableState<T> ব্যবহার করবেন; এটি অন্যান্য পর্যবেক্ষণযোগ্য ধরনের সমর্থন করে। কম্পোজে আরেকটি পর্যবেক্ষণযোগ্য টাইপ পড়ার আগে, আপনাকে অবশ্যই এটিকে একটি State<T> এ রূপান্তর করতে হবে যাতে কম্পোজেবলগুলি স্বয়ংক্রিয়ভাবে কম্পোজ করতে পারে যখন স্টেট পরিবর্তন হয়।

Android অ্যাপ্লিকেশানগুলিতে ব্যবহৃত সাধারণ পর্যবেক্ষণযোগ্য প্রকারগুলি থেকে State<T> তৈরি করতে ফাংশন সহ জাহাজগুলি রচনা করুন৷ এই ইন্টিগ্রেশনগুলি ব্যবহার করার আগে, নীচের রূপরেখা অনুযায়ী উপযুক্ত নিদর্শন (গুলি) যোগ করুন:

  • Flow : collectAsStateWithLifecycle()

    collectAsStateWithLifecycle() একটি লাইফসাইকেল-সচেতন পদ্ধতিতে একটি Flow থেকে মান সংগ্রহ করে, যা আপনার অ্যাপকে অ্যাপ সংস্থান সংরক্ষণ করতে দেয়। এটি কম্পোজ State থেকে সর্বশেষ নির্গত মান উপস্থাপন করে। Android অ্যাপ্লিকেশানগুলিতে ফ্লো সংগ্রহ করার প্রস্তাবিত উপায় হিসাবে এই APIটি ব্যবহার করুন৷

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন (এটি 2.6.0-beta01 বা নতুন হওয়া উচিত):

কোটলিন

dependencies {
      ...
      implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.7")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.7"
}
  • Flow : collectAsState()

    collectAsState হল collectAsStateWithLifecycle এর অনুরূপ, কারণ এটি একটি Flow থেকে মান সংগ্রহ করে এবং কম্পোজ State রূপান্তরিত করে।

    প্ল্যাটফর্ম-অজ্ঞেয়বাদী কোডের জন্য collectAsStateWithLifecycle এর পরিবর্তে collectAsState ব্যবহার করুন, যা শুধুমাত্র Android-এর জন্য।

    collectAsState জন্য অতিরিক্ত নির্ভরতার প্রয়োজন নেই, কারণ এটি compose-runtime উপলব্ধ।

  • LiveData : observeAsState()

    observeAsState() এই LiveData পর্যবেক্ষণ করা শুরু করে এবং State মাধ্যমে এর মানগুলিকে উপস্থাপন করে।

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন:

কোটলিন

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-livedata:1.8.1")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-livedata:1.8.1"
}
  • RxJava2 : subscribeAsState()

    subscribeAsState() হল এক্সটেনশন ফাংশন যা RxJava2 এর প্রতিক্রিয়াশীল স্ট্রীমগুলিকে (যেমন Single , Observable , Completable ) কম্পোজ State রূপান্তরিত করে।

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন:

কোটলিন

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-rxjava2:1.8.1")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-rxjava2:1.8.1"
}
  • RxJava3 : subscribeAsState()

    subscribeAsState() হল এক্সটেনশন ফাংশন যা RxJava3 এর প্রতিক্রিয়াশীল স্ট্রীমগুলিকে (যেমন Single , Observable , Completable ) কম্পোজ State রূপান্তরিত করে।

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন:

কোটলিন

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-rxjava3:1.8.1")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-rxjava3:1.8.1"
}

রাষ্ট্রীয় বনাম রাষ্ট্রহীন

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

একটি স্টেটলেস কম্পোজেবল হল একটি কম্পোজেবল যা কোনো স্টেট ধরে না। রাষ্ট্রহীনতা অর্জনের একটি সহজ উপায় হল রাষ্ট্র উত্তোলন ব্যবহার করা।

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

রাজ্য উত্তোলন

কম্পোজে স্টেট হোস্টিং হল একটি কম্পোজেবল স্টেটলেস করার জন্য কম্পোজেবলের কলারে স্টেট সরানোর একটি প্যাটার্ন। জেটপ্যাক কম্পোজে স্টেট হোস্টিং এর সাধারণ প্যাটার্ন হল স্টেট ভেরিয়েবলকে দুটি প্যারামিটার দিয়ে প্রতিস্থাপন করা:

  • value: T : প্রদর্শনের জন্য বর্তমান মান
  • onValueChange: (T) -> Unit : একটি ইভেন্ট যা মান পরিবর্তনের অনুরোধ করে, যেখানে T হল প্রস্তাবিত নতুন মান

যাইহোক, আপনি onValueChange এ সীমাবদ্ধ নন। যদি আরও নির্দিষ্ট ঘটনাগুলি কম্পোজেবলের জন্য উপযুক্ত হয়, তাহলে আপনাকে ল্যাম্বডাস ব্যবহার করে সেগুলি সংজ্ঞায়িত করা উচিত।

এইভাবে উত্তোলিত রাজ্যের কিছু গুরুত্বপূর্ণ বৈশিষ্ট্য রয়েছে:

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

উদাহরণের ক্ষেত্রে, আপনি HelloContent থেকে name এবং onValueChange বের করুন এবং সেগুলিকে একটি HelloScreen কম্পোজেবলে নিয়ে যান যেটিকে HelloContent বলে।

@Composable
fun HelloScreen() {
    var name by rememberSaveable { mutableStateOf("") }

    HelloContent(name = name, onNameChange = { name = it })
}

@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello, $name",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.bodyMedium
        )
        OutlinedTextField(value = name, onValueChange = onNameChange, label = { Text("Name") })
    }
}

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

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

আরও জানতে রাজ্যের পৃষ্ঠাটি কোথায় উত্তোলন করবেন তা দেখুন।

রচনায় স্থিতি পুনরুদ্ধার করা হচ্ছে

rememberSaveable এপিআই remember মতো আচরণ করে কারণ এটি সংরক্ষিত ইনস্ট্যান্স স্টেট মেকানিজম ব্যবহার করে পুনর্গঠন জুড়ে এবং কার্যকলাপ বা প্রক্রিয়া বিনোদন জুড়ে অবস্থা বজায় রাখে। উদাহরণস্বরূপ, এটি ঘটে, যখন স্ক্রিনটি ঘোরানো হয়।

রাষ্ট্র সংরক্ষণের উপায়

Bundle যোগ করা সমস্ত ডেটা প্রকার স্বয়ংক্রিয়ভাবে সংরক্ষিত হয়। আপনি যদি এমন কিছু সংরক্ষণ করতে চান যা Bundle যোগ করা যায় না, সেখানে বেশ কয়েকটি বিকল্প রয়েছে।

পার্সেলাইজ করুন

সহজ সমাধান হল অবজেক্টে @Parcelize টীকা যোগ করা। বস্তুটি parcelable হয়ে যায়, এবং বান্ডিল করা যায়। উদাহরণস্বরূপ, এই কোডটি একটি পার্সেলযোগ্য City ডেটা টাইপ তৈরি করে এবং এটি রাজ্যে সংরক্ষণ করে।

@Parcelize
data class City(val name: String, val country: String) : Parcelable

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

ম্যাপসেভার

যদি কোনো কারণে @Parcelize উপযুক্ত না হয়, তাহলে আপনি একটি বস্তুকে মানগুলির একটি সেটে রূপান্তর করার জন্য আপনার নিজস্ব নিয়ম সংজ্ঞায়িত করতে mapSaver ব্যবহার করতে পারেন যা সিস্টেম Bundle সংরক্ষণ করতে পারে।

data class City(val name: String, val country: String)

val CitySaver = run {
    val nameKey = "Name"
    val countryKey = "Country"
    mapSaver(
        save = { mapOf(nameKey to it.name, countryKey to it.country) },
        restore = { City(it[nameKey] as String, it[countryKey] as String) }
    )
}

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable(stateSaver = CitySaver) {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

লিস্টসেভার

মানচিত্রের জন্য কীগুলি সংজ্ঞায়িত করার প্রয়োজন এড়াতে, আপনি listSaver ব্যবহার করতে পারেন এবং কী হিসাবে এর সূচকগুলি ব্যবহার করতে পারেন:

data class City(val name: String, val country: String)

val CitySaver = listSaver<City, Any>(
    save = { listOf(it.name, it.country) },
    restore = { City(it[0] as String, it[1] as String) }
)

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable(stateSaver = CitySaver) {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

কম্পোজ রাষ্ট্র ধারক

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

আরও জানতে আর্কিটেকচার গাইডে কম্পোজ ডকুমেন্টেশনে স্টেট হোস্টিং দেখুন বা, আরও সাধারণভাবে, স্টেট হোল্ডার এবং ইউআই স্টেট পৃষ্ঠা দেখুন।

কী পরিবর্তন হলে রিট্রিগার গণনা মনে রাখবেন

remember API প্রায়শই MutableState সাথে একসাথে ব্যবহার করা হয়:

var name by remember { mutableStateOf("") }

এখানে, remember ফাংশন ব্যবহার করে MutableState মানকে পুনর্গঠন করে।

সাধারণভাবে, remember একটি calculation ল্যাম্বডা প্যারামিটার লাগে। যখন remember প্রথম চালানো হয়, এটি calculation ল্যাম্বডাকে আহ্বান করে এবং এর ফলাফল সংরক্ষণ করে। পুনর্গঠনের সময়, remember যে মানটি শেষ সংরক্ষিত ছিল।

ক্যাশিং স্টেট ছাড়াও, আপনি কম্পোজিশনে যেকোন বস্তু বা অপারেশনের ফলাফল সংরক্ষণ করতে remember ব্যবহার করতে পারেন যা শুরু বা গণনা করা ব্যয়বহুল। আপনি হয়ত প্রতিটি পুনর্গঠনে এই গণনার পুনরাবৃত্তি করতে চান না। একটি উদাহরণ এই ShaderBrush অবজেক্ট তৈরি করছে, যা একটি ব্যয়বহুল অপারেশন:

val brush = remember {
    ShaderBrush(
        BitmapShader(
            ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(),
            Shader.TileMode.REPEAT,
            Shader.TileMode.REPEAT
        )
    )
}

remember মান সংরক্ষণ করে যতক্ষণ না এটি রচনাটি ছেড়ে যায়। যাইহোক, ক্যাশে মান অবৈধ করার একটি উপায় আছে। remember API একটি key বা keys প্যারামিটারও নেয়। যদি এই কীগুলির যেকোনও পরিবর্তন হয়, পরের বার ফাংশনটি পুনর্গঠিত হলে , remember ক্যাশে অকার্যকর করে এবং গণনা ল্যাম্বডা ব্লক আবার চালায় । এই প্রক্রিয়াটি আপনাকে কম্পোজিশনের একটি বস্তুর জীবনকালের উপর নিয়ন্ত্রণ দেয়। ইনপুট পরিবর্তন না হওয়া পর্যন্ত গণনা বৈধ থাকে, যতক্ষণ না মনে রাখা মান রচনাটি ছেড়ে যায়।

নিম্নলিখিত উদাহরণগুলি দেখায় যে এই প্রক্রিয়াটি কীভাবে কাজ করে।

এই স্নিপেটে, একটি ShaderBrush তৈরি করা হয় এবং একটি Box কম্পোজেবলের ব্যাকগ্রাউন্ড পেইন্ট হিসাবে ব্যবহার করা হয়। remember ShaderBrush দৃষ্টান্ত সংরক্ষণ করুন কারণ এটি পুনরায় তৈরি করা ব্যয়বহুল, যেমনটি আগে ব্যাখ্যা করা হয়েছে। remember avatarRes key1 প্যারামিটার হিসেবে নেয়, যা নির্বাচিত ব্যাকগ্রাউন্ড ইমেজ। যদি avatarRes পরিবর্তিত হয়, ব্রাশটি নতুন চিত্রের সাথে পুনরায় সংমিশ্রিত হয় এবং Box পুনরায় প্রয়োগ করা হয়। এটি ঘটতে পারে যখন ব্যবহারকারী একটি পিকার থেকে পটভূমি হতে অন্য একটি ছবি নির্বাচন করেন।

@Composable
private fun BackgroundBanner(
    @DrawableRes avatarRes: Int,
    modifier: Modifier = Modifier,
    res: Resources = LocalContext.current.resources
) {
    val brush = remember(key1 = avatarRes) {
        ShaderBrush(
            BitmapShader(
                ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(),
                Shader.TileMode.REPEAT,
                Shader.TileMode.REPEAT
            )
        )
    }

    Box(
        modifier = modifier.background(brush)
    ) {
        /* ... */
    }
}

পরবর্তী স্নিপেটে, স্টেটকে একটি প্লেইন স্টেট হোল্ডার ক্লাস MyAppState এ উত্তোলন করা হয়। এটি remember ব্যবহার করে ক্লাসের একটি ইন্সট্যান্স আরম্ভ করার জন্য একটি rememberMyAppState ফাংশন প্রকাশ করে। কম্পোজে টিকে থাকা একটি দৃষ্টান্ত তৈরি করতে এই ধরনের ফাংশনগুলিকে প্রকাশ করা কম্পোজের একটি সাধারণ প্যাটার্ন। rememberMyAppState ফাংশন windowSizeClass পায়, যা remember key প্যারামিটার হিসেবে কাজ করে। যদি এই প্যারামিটারটি পরিবর্তিত হয়, অ্যাপটিকে সাম্প্রতিক মান সহ প্লেইন স্টেট হোল্ডার ক্লাস পুনরায় তৈরি করতে হবে। এটি ঘটতে পারে যদি, উদাহরণস্বরূপ, ব্যবহারকারী ডিভাইসটি ঘোরান।

@Composable
private fun rememberMyAppState(
    windowSizeClass: WindowSizeClass
): MyAppState {
    return remember(windowSizeClass) {
        MyAppState(windowSizeClass)
    }
}

@Stable
class MyAppState(
    private val windowSizeClass: WindowSizeClass
) { /* ... */ }

একটি কী পরিবর্তিত হয়েছে কিনা তা নির্ধারণ করতে এবং সঞ্চিত মানটিকে অবৈধ করে কিনা তা নির্ধারণ করতে কম্পোজ ক্লাসের সমান বাস্তবায়ন ব্যবহার করে।

পুনঃগঠনের বাইরে কী সহ স্টেট স্টোর করুন

rememberSaveable এপিআই হল remember চারপাশে একটি মোড়ক যা একটি Bundle ডেটা সংরক্ষণ করতে পারে। এই এপিআই রাষ্ট্রকে শুধুমাত্র পুনর্গঠনই নয়, ক্রিয়াকলাপ বিনোদন এবং সিস্টেম-প্রবর্তিত প্রক্রিয়ার মৃত্যুতেও বেঁচে থাকতে দেয়। rememberSaveable একই উদ্দেশ্যে input প্যারামিটারগুলি রিসিভযোগ্য করে যা keys remember করে। কোনও ইনপুট পরিবর্তিত হলে ক্যাশে অবৈধ হয় । পরের বার যখন ফাংশনটি পুনরায় সংশোধন করে, rememberSaveable গণনা ল্যাম্বদা ব্লকটিকে পুনরায় এক্সিকিউট করে।

নিম্নলিখিত উদাহরণে, typedQuery পরিবর্তন না হওয়া পর্যন্ত userTypedQuery স্টোরগুলি ব্যবহারকারী স্টোরগুলি rememberSaveable :

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

আরও জানুন

রাষ্ট্র এবং জেটপ্যাক রচনা সম্পর্কে আরও জানতে, নিম্নলিখিত অতিরিক্ত সংস্থানগুলির সাথে পরামর্শ করুন।

নমুনা

কোডল্যাব

ভিডিও

ব্লগ

{ % ভারব্যাটিম %} { % endverbatim %} { % ভারব্যাটিম %} { % endverbatim %},

একটি অ্যাপ্লিকেশন মধ্যে রাষ্ট্র এমন কোনও মান যা সময়ের সাথে সাথে পরিবর্তিত হতে পারে। এটি একটি খুব বিস্তৃত সংজ্ঞা এবং একটি ঘরের ডাটাবেস থেকে শুরু করে একটি শ্রেণীর একটি ভেরিয়েবল পর্যন্ত সমস্ত কিছু অন্তর্ভুক্ত করে।

সমস্ত অ্যান্ড্রয়েড অ্যাপ্লিকেশন ব্যবহারকারীর কাছে রাষ্ট্র প্রদর্শন করে। অ্যান্ড্রয়েড অ্যাপ্লিকেশনগুলিতে রাষ্ট্রের কয়েকটি উদাহরণ:

  • একটি স্নাকবার যা দেখায় যে যখন কোনও নেটওয়ার্ক সংযোগ স্থাপন করা যায় না।
  • একটি ব্লগ পোস্ট এবং সম্পর্কিত মন্তব্য।
  • বোতামগুলিতে রিপল অ্যানিমেশনগুলি যখন কোনও ব্যবহারকারী তাদের ক্লিক করে।
  • স্টিকারগুলি যে কোনও ব্যবহারকারী কোনও চিত্রের শীর্ষে আঁকতে পারে।

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

রাষ্ট্র এবং রচনা

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

@Composable
private fun HelloContent() {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello!",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.bodyMedium
        )
        OutlinedTextField(
            value = "",
            onValueChange = { },
            label = { Text("Name") }
        )
    }
}

আপনি যদি এটি চালান এবং পাঠ্য প্রবেশের চেষ্টা করেন তবে আপনি দেখতে পাবেন যে কিছুই হয় না। কারণ TextField নিজেকে আপডেট করে না - যখন এর value প্যারামিটার পরিবর্তন হয় তখন এটি আপডেট হয়। এটি রচনা এবং পুনঃসংযোগ রচনা কীভাবে কাজ করে তার কারণে।

প্রাথমিক রচনা এবং পুনরুদ্ধার সম্পর্কে আরও জানতে, রচনাটিতে চিন্তাভাবনা দেখুন।

কমপোজেবলগুলিতে রাজ্য

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

mutableStateOf একটি পর্যবেক্ষণযোগ্য MutableState<T> তৈরি করে, যা রচনা রানটাইমের সাথে সংহত একটি পর্যবেক্ষণযোগ্য প্রকার।

interface MutableState<T> : State<T> {
    override var value: T
}

value পড়ার কোনও কমপোজেবল ফাংশনগুলির পুনরুদ্ধার করার সময়সূচিতে কোনও পরিবর্তন value

একটি কমপোজেবলের মধ্যে একটি MutableState অবজেক্ট ঘোষণা করার তিনটি উপায় রয়েছে:

  • val mutableState = remember { mutableStateOf(default) }
  • var value by remember { mutableStateOf(default) }
  • val (value, setValue) = remember { mutableStateOf(default) }

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

প্রতিনিধি সিনট্যাক্সের by নিম্নলিখিত আমদানি প্রয়োজন:

import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

আপনি অন্যান্য কমপোজেবলগুলির জন্য প্যারামিটার হিসাবে স্মরণীয় মানটি ব্যবহার করতে পারেন এমনকি কোন কম্পোজেবলগুলি প্রদর্শিত হয় তা পরিবর্তন করতে বিবৃতিগুলিতে যুক্তি হিসাবে। উদাহরণস্বরূপ, নামটি খালি থাকলে আপনি যদি শুভেচ্ছা প্রদর্শন করতে না চান তবে if বিবৃতিতে রাজ্যটি ব্যবহার করুন:

@Composable
fun HelloContent() {
    Column(modifier = Modifier.padding(16.dp)) {
        var name by remember { mutableStateOf("") }
        if (name.isNotEmpty()) {
            Text(
                text = "Hello, $name!",
                modifier = Modifier.padding(bottom = 8.dp),
                style = MaterialTheme.typography.bodyMedium
            )
        }
        OutlinedTextField(
            value = name,
            onValueChange = { name = it },
            label = { Text("Name") }
        )
    }
}

যদিও remember আপনাকে পুনরুদ্ধারগুলি জুড়ে রাষ্ট্র ধরে রাখতে সহায়তা করে, কনফিগারেশন পরিবর্তনগুলিতে রাজ্যটি ধরে রাখা হয় না। এর জন্য, আপনাকে অবশ্যই rememberSaveable ব্যবহার করতে হবে। rememberSaveable যায়যোগ্যভাবে স্বয়ংক্রিয়ভাবে যে কোনও মান সংরক্ষণ করে যা একটি Bundle সংরক্ষণ করা যায়। অন্যান্য মানগুলির জন্য, আপনি একটি কাস্টম সেভার অবজেক্টে পাস করতে পারেন।

রাষ্ট্রের অন্যান্য সমর্থিত প্রকার

রচনাটির প্রয়োজন হয় না যে আপনি রাষ্ট্র ধরে রাখতে MutableState<T> ব্যবহার করেন; এটি অন্যান্য পর্যবেক্ষণযোগ্য প্রকারকে সমর্থন করে। রচনাটিতে অন্য পর্যবেক্ষণযোগ্য প্রকারটি পড়ার আগে আপনাকে অবশ্যই এটিকে একটি State<T> এ রূপান্তর করতে হবে যাতে রাষ্ট্রীয় পরিবর্তন হওয়ার পরে কমপোজেবলগুলি স্বয়ংক্রিয়ভাবে পুনঃপ্রেরণ করতে পারে।

অ্যান্ড্রয়েড অ্যাপ্লিকেশনগুলিতে ব্যবহৃত সাধারণ পর্যবেক্ষণযোগ্য প্রকার থেকে State<T> তৈরি করতে ফাংশন সহ জাহাজগুলি রচনা করুন। এই সংহতকরণগুলি ব্যবহার করার আগে, নীচে বর্ণিত হিসাবে উপযুক্ত আর্টিফ্যাক্ট (গুলি) যুক্ত করুন:

  • Flow : collectAsStateWithLifecycle()

    collectAsStateWithLifecycle() আপনার অ্যাপ্লিকেশনটিকে অ্যাপ্লিকেশন সংস্থান সংরক্ষণের অনুমতি দেয়, লাইফসাইকেল-সচেতন পদ্ধতিতে একটি Flow থেকে মান সংগ্রহ করে। এটি রচনা State থেকে সর্বশেষ নির্গত মান উপস্থাপন করে। অ্যান্ড্রয়েড অ্যাপ্লিকেশনগুলিতে প্রবাহ সংগ্রহের জন্য প্রস্তাবিত উপায় হিসাবে এই এপিআই ব্যবহার করুন।

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন (এটি 2.6.0-BETA01 বা আরও নতুন হওয়া উচিত):

কোটলিন

dependencies {
      ...
      implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.7")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.7"
}
  • Flow : collectAsState()

    collectAsState collectAsStateWithLifecycle জন্য একই রকম, কারণ এটি একটি Flow থেকে মান সংগ্রহ করে এবং এটিকে রচনা State রূপান্তরিত করে।

    কেবলমাত্র অ্যান্ড্রয়েড-এর কেবল collectAsStateWithLifecycle প্ল্যাটফর্ম-অ্যাগনস্টিক কোডের জন্য সংগ্রহের জন্য collectAsState ব্যবহার করুন।

    collectAsState জন্য অতিরিক্ত নির্ভরতা প্রয়োজন হয় না, কারণ এটি compose-runtime এ উপলব্ধ।

  • LiveData : observeAsState()

    observeAsState() এই LiveData পর্যবেক্ষণ শুরু করে এবং State মাধ্যমে এর মানগুলি উপস্থাপন করে।

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন:

কোটলিন

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-livedata:1.8.1")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-livedata:1.8.1"
}
  • RxJava2 : subscribeAsState()

    subscribeAsState() হ'ল এক্সটেনশন ফাংশন যা আরএক্সজেএভিএ 2 এর প্রতিক্রিয়াশীল স্ট্রিমগুলিকে (যেমন Single , Observable , Completable ) কমপোজ State রূপান্তর করে।

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন:

কোটলিন

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-rxjava2:1.8.1")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-rxjava2:1.8.1"
}
  • RxJava3 : subscribeAsState()

    subscribeAsState() হ'ল এক্সটেনশন ফাংশন যা আরএক্সজেভিএ 3 এর প্রতিক্রিয়াশীল স্ট্রিমগুলিকে (যেমন Single , Observable , Completable ) কমপোজ State রূপান্তর করে।

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন:

কোটলিন

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-rxjava3:1.8.1")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-rxjava3:1.8.1"
}

রাষ্ট্রীয় বনাম রাষ্ট্রহীন

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

একটি রাষ্ট্রবিহীন কমপোজেবল একটি কম্পোজেবল যা কোনও রাষ্ট্রকে ধরে রাখে না। রাষ্ট্রবিহীন অর্জনের একটি সহজ উপায় হ'ল রাষ্ট্র উত্তোলন ব্যবহার করে।

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

রাষ্ট্র উত্তোলন

কমপোজে রাষ্ট্রীয় উত্তোলন একটি কমপোজেবল স্টেটলেস তৈরি করতে স্টেটকে একটি কমপোজেবলের কলারে স্থানান্তরিত করার একটি প্যাটার্ন। জেটপ্যাক রচনাটিতে রাষ্ট্র উত্তোলনের জন্য সাধারণ প্যাটার্নটি হ'ল দুটি পরামিতি দিয়ে রাষ্ট্রীয় পরিবর্তনশীলকে প্রতিস্থাপন করা:

  • value: T : প্রদর্শনের বর্তমান মান
  • onValueChange: (T) -> Unit : এমন একটি ইভেন্ট যা পরিবর্তনের মানকে অনুরোধ করে, যেখানে T প্রস্তাবিত নতুন মান

তবে আপনি onValueChange মধ্যে সীমাবদ্ধ নন। যদি আরও নির্দিষ্ট ইভেন্টগুলি কমপোজেবলের জন্য উপযুক্ত হয় তবে আপনার ল্যাম্বডাস ব্যবহার করে সেগুলি সংজ্ঞায়িত করা উচিত।

এইভাবে উত্তোলন করা রাষ্ট্রের কিছু গুরুত্বপূর্ণ বৈশিষ্ট্য রয়েছে:

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

উদাহরণস্বরূপ, আপনি HelloContent বাইরে name এবং onValueChange বের করেন এবং গাছটিকে একটি HelloScreen কমপোজেবলের কাছে নিয়ে যান যা HelloContent বলে।

@Composable
fun HelloScreen() {
    var name by rememberSaveable { mutableStateOf("") }

    HelloContent(name = name, onNameChange = { name = it })
}

@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello, $name",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.bodyMedium
        )
        OutlinedTextField(value = name, onValueChange = onNameChange, label = { Text("Name") })
    }
}

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

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

আরও শিখতে স্টেট পৃষ্ঠাটি কোথায় উত্তোলন করবেন তা দেখুন।

কমপোজে রাষ্ট্র পুনরুদ্ধার

rememberSaveable এপিআই একইভাবে remember জন্য আচরণ করে কারণ এটি সংরক্ষণগুলি জুড়ে রাজ্যকে ধরে রাখে এবং সংরক্ষিত উদাহরণ রাষ্ট্রীয় প্রক্রিয়াটি ব্যবহার করে ক্রিয়াকলাপ বা প্রক্রিয়া বিনোদন জুড়েও। উদাহরণস্বরূপ, এটি ঘটে যখন স্ক্রিনটি ঘোরানো হয়।

রাজ্য সঞ্চয় করার উপায়

Bundle যুক্ত হওয়া সমস্ত ডেটা প্রকারগুলি স্বয়ংক্রিয়ভাবে সংরক্ষণ করা হয়। আপনি যদি এমন কিছু সংরক্ষণ করতে চান যা Bundle যুক্ত করা যায় না তবে বেশ কয়েকটি বিকল্প রয়েছে।

পার্সেলাইজ করুন

সবচেয়ে সহজ সমাধান হ'ল অবজেক্টে @Parcelize টীকা যুক্ত করা। অবজেক্টটি পার্সেলেবল হয়ে যায় এবং বান্ডিল করা যায়। উদাহরণস্বরূপ, এই কোডটি একটি পার্সেলেবল City ডেটা টাইপ করে এবং এটি রাজ্যে সংরক্ষণ করে।

@Parcelize
data class City(val name: String, val country: String) : Parcelable

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

মানচিত্রের

যদি কোনও কারণে @Parcelize উপযুক্ত না হয় তবে আপনি কোনও বস্তুকে এমন মানগুলির সেটে রূপান্তর করার জন্য নিজের নিয়মটি সংজ্ঞায়িত করতে mapSaver ব্যবহার করতে পারেন যা সিস্টেমটি Bundle সংরক্ষণ করতে পারে।

data class City(val name: String, val country: String)

val CitySaver = run {
    val nameKey = "Name"
    val countryKey = "Country"
    mapSaver(
        save = { mapOf(nameKey to it.name, countryKey to it.country) },
        restore = { City(it[nameKey] as String, it[countryKey] as String) }
    )
}

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable(stateSaver = CitySaver) {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

তালিকাভুক্ত

মানচিত্রের কীগুলি সংজ্ঞায়িত করার প্রয়োজন এড়াতে, আপনি listSaver ব্যবহার করতে পারেন এবং এর সূচকগুলি কী হিসাবে ব্যবহার করতে পারেন:

data class City(val name: String, val country: String)

val CitySaver = listSaver<City, Any>(
    save = { listOf(it.name, it.country) },
    restore = { City(it[0] as String, it[1] as String) }
)

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable(stateSaver = CitySaver) {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

কমপোজে রাজ্য ধারক

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

কমপোজ ডকুমেন্টেশনে বা আরও সাধারণভাবে, আরও শিখতে আর্কিটেকচার গাইডে রাজ্যধারক এবং ইউআই রাজ্য পৃষ্ঠা দেখুন।

Retrigger গণনা মনে রাখবেন যখন কীগুলি পরিবর্তন হয়

remember এপিআই প্রায়শই MutableState সাথে একসাথে ব্যবহৃত হয়:

var name by remember { mutableStateOf("") }

এখানে, remember ফাংশনটি ব্যবহার করে MutableState মানকে পুনরুদ্ধার করে তোলে।

সাধারণভাবে, remember একটি calculation ল্যাম্বদা প্যারামিটার নেয়। যখন remember প্রথমটি চালানো হয়, এটি calculation ল্যাম্বডাকে অনুরোধ করে এবং এর ফলাফল সঞ্চয় করে। পুনরুদ্ধার করার সময়, remember যে সর্বশেষে সঞ্চিত মানটি ফেরত দেয়।

ক্যাচিং অবস্থা ছাড়াও, আপনি যে কোনও অবজেক্ট সংরক্ষণ করতে বা রচনাটিতে কোনও অপারেশনের ফলাফল সংরক্ষণ করতেও remember করতে পারেন যা আরম্ভ করা বা গণনা করা ব্যয়বহুল। আপনি প্রতিটি পুনঃনির্মাণে এই গণনাটি পুনরাবৃত্তি করতে চাইবেন না। একটি উদাহরণ এই ShaderBrush অবজেক্ট তৈরি করছে, যা একটি ব্যয়বহুল অপারেশন:

val brush = remember {
    ShaderBrush(
        BitmapShader(
            ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(),
            Shader.TileMode.REPEAT,
            Shader.TileMode.REPEAT
        )
    )
}

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

নিম্নলিখিত উদাহরণগুলি দেখায় যে এই প্রক্রিয়াটি কীভাবে কাজ করে।

এই স্নিপেটে, একটি ShaderBrush তৈরি করা হয় এবং একটি Box কম্পোজেবলের ব্যাকগ্রাউন্ড পেইন্ট হিসাবে ব্যবহৃত হয়। remember ShaderBrush উদাহরণটি সঞ্চয় করে কারণ এটি পুনরায় তৈরি করা ব্যয়বহুল, যেমনটি আগে ব্যাখ্যা করা হয়েছে। remember avatarRes key1 প্যারামিটার হিসাবে নেয়, যা নির্বাচিত ব্যাকগ্রাউন্ড চিত্র। যদি avatarRes পরিবর্তিত হয় তবে ব্রাশটি নতুন চিত্রের সাথে পুনঃনির্মাণ করে এবং Box পুনরায় প্রয়োগ হয়। এটি ঘটতে পারে যখন ব্যবহারকারী কোনও পিকার থেকে পটভূমি হতে অন্য চিত্র নির্বাচন করে।

@Composable
private fun BackgroundBanner(
    @DrawableRes avatarRes: Int,
    modifier: Modifier = Modifier,
    res: Resources = LocalContext.current.resources
) {
    val brush = remember(key1 = avatarRes) {
        ShaderBrush(
            BitmapShader(
                ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(),
                Shader.TileMode.REPEAT,
                Shader.TileMode.REPEAT
            )
        )
    }

    Box(
        modifier = modifier.background(brush)
    ) {
        /* ... */
    }
}

পরবর্তী স্নিপেটে, রাজ্যটি একটি সরল রাষ্ট্রধারার ক্লাস MyAppState উত্তোলন করা হয়। এটি remember ব্যবহার করে ক্লাসের একটি উদাহরণ সূচনা করতে এটি একটি rememberMyAppState ফাংশনটি প্রকাশ করে। পুনরুদ্ধারগুলি বেঁচে থাকা এমন একটি উদাহরণ তৈরি করতে এই জাতীয় ফাংশনগুলি প্রকাশ করা রচনাটি একটি সাধারণ প্যাটার্ন। rememberMyAppState ফাংশনটি windowSizeClass গ্রহণ করে, যা remember জন্য key প্যারামিটার হিসাবে কাজ করে। যদি এই প্যারামিটারটি পরিবর্তন হয় তবে অ্যাপ্লিকেশনটিকে সর্বশেষতম মান সহ প্লেইন স্টেট হোল্ডার ক্লাসটি পুনরায় তৈরি করতে হবে। এটি ঘটতে পারে যদি উদাহরণস্বরূপ, ব্যবহারকারী ডিভাইসটি ঘোরান।

@Composable
private fun rememberMyAppState(
    windowSizeClass: WindowSizeClass
): MyAppState {
    return remember(windowSizeClass) {
        MyAppState(windowSizeClass)
    }
}

@Stable
class MyAppState(
    private val windowSizeClass: WindowSizeClass
) { /* ... */ }

কোনও কী সঞ্চিত মান পরিবর্তন করেছে এবং অকার্যকর করেছে কিনা তা সিদ্ধান্ত নিতে কমপোজ ক্লাসের সমান বাস্তবায়ন ব্যবহার করে।

পুনরুদ্ধার করার বাইরে কীগুলি সহ স্টেট স্টোর করুন

rememberSaveable এপিআই হ'ল একটি মোড়ক যা remember যা একটি Bundle ডেটা সঞ্চয় করতে পারে। এই এপিআই রাষ্ট্রকে কেবল পুনরুদ্ধার করতে নয়, ক্রিয়াকলাপ বিনোদন এবং সিস্টেম-উদ্যোগী প্রক্রিয়া মৃত্যুরও বাঁচতে দেয়। rememberSaveable একই উদ্দেশ্যে input প্যারামিটারগুলি রিসিভযোগ্য করে যা keys remember করে। কোনও ইনপুট পরিবর্তিত হলে ক্যাশে অবৈধ হয় । পরের বার যখন ফাংশনটি পুনরায় সংশোধন করে, rememberSaveable গণনা ল্যাম্বদা ব্লকটিকে পুনরায় এক্সিকিউট করে।

নিম্নলিখিত উদাহরণে, typedQuery পরিবর্তন না হওয়া পর্যন্ত userTypedQuery স্টোরগুলি ব্যবহারকারী স্টোরগুলি rememberSaveable :

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

আরও জানুন

রাষ্ট্র এবং জেটপ্যাক রচনা সম্পর্কে আরও জানতে, নিম্নলিখিত অতিরিক্ত সংস্থানগুলির সাথে পরামর্শ করুন।

নমুনা

কোডল্যাব

ভিডিও

ব্লগ

{ % ভারব্যাটিম %} { % endverbatim %} { % ভারব্যাটিম %} { % endverbatim %},

একটি অ্যাপ্লিকেশন মধ্যে রাষ্ট্র এমন কোনও মান যা সময়ের সাথে সাথে পরিবর্তিত হতে পারে। এটি একটি খুব বিস্তৃত সংজ্ঞা এবং একটি ঘরের ডাটাবেস থেকে শুরু করে একটি শ্রেণীর একটি ভেরিয়েবল পর্যন্ত সমস্ত কিছু অন্তর্ভুক্ত করে।

সমস্ত অ্যান্ড্রয়েড অ্যাপ্লিকেশন ব্যবহারকারীর কাছে রাষ্ট্র প্রদর্শন করে। অ্যান্ড্রয়েড অ্যাপ্লিকেশনগুলিতে রাষ্ট্রের কয়েকটি উদাহরণ:

  • একটি স্নাকবার যা দেখায় যে যখন কোনও নেটওয়ার্ক সংযোগ স্থাপন করা যায় না।
  • একটি ব্লগ পোস্ট এবং সম্পর্কিত মন্তব্য।
  • বোতামগুলিতে রিপল অ্যানিমেশনগুলি যখন কোনও ব্যবহারকারী তাদের ক্লিক করে।
  • স্টিকারগুলি যে কোনও ব্যবহারকারী কোনও চিত্রের শীর্ষে আঁকতে পারে।

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

রাষ্ট্র এবং রচনা

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

@Composable
private fun HelloContent() {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello!",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.bodyMedium
        )
        OutlinedTextField(
            value = "",
            onValueChange = { },
            label = { Text("Name") }
        )
    }
}

আপনি যদি এটি চালান এবং পাঠ্য প্রবেশের চেষ্টা করেন তবে আপনি দেখতে পাবেন যে কিছুই হয় না। কারণ TextField নিজেকে আপডেট করে না - যখন এর value প্যারামিটার পরিবর্তন হয় তখন এটি আপডেট হয়। এটি রচনা এবং পুনঃসংযোগ রচনা কীভাবে কাজ করে তার কারণে।

প্রাথমিক রচনা এবং পুনরুদ্ধার সম্পর্কে আরও জানতে, রচনাটিতে চিন্তাভাবনা দেখুন।

কমপোজেবলগুলিতে রাজ্য

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

mutableStateOf একটি পর্যবেক্ষণযোগ্য MutableState<T> তৈরি করে, যা রচনা রানটাইমের সাথে সংহত একটি পর্যবেক্ষণযোগ্য প্রকার।

interface MutableState<T> : State<T> {
    override var value: T
}

value পড়ার কোনও কমপোজেবল ফাংশনগুলির পুনরুদ্ধার করার সময়সূচিতে কোনও পরিবর্তন value

একটি কমপোজেবলের মধ্যে একটি MutableState অবজেক্ট ঘোষণা করার তিনটি উপায় রয়েছে:

  • val mutableState = remember { mutableStateOf(default) }
  • var value by remember { mutableStateOf(default) }
  • val (value, setValue) = remember { mutableStateOf(default) }

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

প্রতিনিধি সিনট্যাক্সের by নিম্নলিখিত আমদানি প্রয়োজন:

import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

আপনি অন্যান্য কমপোজেবলগুলির জন্য প্যারামিটার হিসাবে স্মরণীয় মানটি ব্যবহার করতে পারেন এমনকি কোন কম্পোজেবলগুলি প্রদর্শিত হয় তা পরিবর্তন করতে বিবৃতিগুলিতে যুক্তি হিসাবে। উদাহরণস্বরূপ, নামটি খালি থাকলে আপনি যদি শুভেচ্ছা প্রদর্শন করতে না চান তবে if বিবৃতিতে রাজ্যটি ব্যবহার করুন:

@Composable
fun HelloContent() {
    Column(modifier = Modifier.padding(16.dp)) {
        var name by remember { mutableStateOf("") }
        if (name.isNotEmpty()) {
            Text(
                text = "Hello, $name!",
                modifier = Modifier.padding(bottom = 8.dp),
                style = MaterialTheme.typography.bodyMedium
            )
        }
        OutlinedTextField(
            value = name,
            onValueChange = { name = it },
            label = { Text("Name") }
        )
    }
}

যদিও remember আপনাকে পুনরুদ্ধারগুলি জুড়ে রাষ্ট্র ধরে রাখতে সহায়তা করে, কনফিগারেশন পরিবর্তনগুলিতে রাজ্যটি ধরে রাখা হয় না। এর জন্য, আপনাকে অবশ্যই rememberSaveable ব্যবহার করতে হবে। rememberSaveable যায়যোগ্যভাবে স্বয়ংক্রিয়ভাবে যে কোনও মান সংরক্ষণ করে যা একটি Bundle সংরক্ষণ করা যায়। অন্যান্য মানগুলির জন্য, আপনি একটি কাস্টম সেভার অবজেক্টে পাস করতে পারেন।

রাষ্ট্রের অন্যান্য সমর্থিত প্রকার

রচনাটির প্রয়োজন হয় না যে আপনি রাষ্ট্র ধরে রাখতে MutableState<T> ব্যবহার করেন; এটি অন্যান্য পর্যবেক্ষণযোগ্য প্রকারকে সমর্থন করে। রচনাটিতে অন্য পর্যবেক্ষণযোগ্য প্রকারটি পড়ার আগে আপনাকে অবশ্যই এটিকে একটি State<T> এ রূপান্তর করতে হবে যাতে রাষ্ট্রীয় পরিবর্তন হওয়ার পরে কমপোজেবলগুলি স্বয়ংক্রিয়ভাবে পুনঃপ্রেরণ করতে পারে।

অ্যান্ড্রয়েড অ্যাপ্লিকেশনগুলিতে ব্যবহৃত সাধারণ পর্যবেক্ষণযোগ্য প্রকার থেকে State<T> তৈরি করতে ফাংশন সহ জাহাজগুলি রচনা করুন। এই সংহতকরণগুলি ব্যবহার করার আগে, নীচে বর্ণিত হিসাবে উপযুক্ত আর্টিফ্যাক্ট (গুলি) যুক্ত করুন:

  • Flow : collectAsStateWithLifecycle()

    collectAsStateWithLifecycle() আপনার অ্যাপ্লিকেশনটিকে অ্যাপ্লিকেশন সংস্থান সংরক্ষণের অনুমতি দেয়, লাইফসাইকেল-সচেতন পদ্ধতিতে একটি Flow থেকে মান সংগ্রহ করে। এটি রচনা State থেকে সর্বশেষ নির্গত মান উপস্থাপন করে। অ্যান্ড্রয়েড অ্যাপ্লিকেশনগুলিতে প্রবাহ সংগ্রহের জন্য প্রস্তাবিত উপায় হিসাবে এই এপিআই ব্যবহার করুন।

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন (এটি 2.6.0-BETA01 বা আরও নতুন হওয়া উচিত):

কোটলিন

dependencies {
      ...
      implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.7")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.7"
}
  • Flow : collectAsState()

    collectAsState collectAsStateWithLifecycle জন্য একই রকম, কারণ এটি একটি Flow থেকে মান সংগ্রহ করে এবং এটিকে রচনা State রূপান্তরিত করে।

    কেবলমাত্র অ্যান্ড্রয়েড-এর কেবল collectAsStateWithLifecycle প্ল্যাটফর্ম-অ্যাগনস্টিক কোডের জন্য সংগ্রহের জন্য collectAsState ব্যবহার করুন।

    collectAsState জন্য অতিরিক্ত নির্ভরতা প্রয়োজন হয় না, কারণ এটি compose-runtime এ উপলব্ধ।

  • LiveData : observeAsState()

    observeAsState() এই LiveData পর্যবেক্ষণ শুরু করে এবং State মাধ্যমে এর মানগুলি উপস্থাপন করে।

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন:

কোটলিন

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-livedata:1.8.1")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-livedata:1.8.1"
}
  • RxJava2 : subscribeAsState()

    subscribeAsState() হ'ল এক্সটেনশন ফাংশন যা আরএক্সজেএভিএ 2 এর প্রতিক্রিয়াশীল স্ট্রিমগুলিকে (যেমন Single , Observable , Completable ) কমপোজ State রূপান্তর করে।

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন:

কোটলিন

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-rxjava2:1.8.1")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-rxjava2:1.8.1"
}
  • RxJava3 : subscribeAsState()

    subscribeAsState() হ'ল এক্সটেনশন ফাংশন যা আরএক্সজেভিএ 3 এর প্রতিক্রিয়াশীল স্ট্রিমগুলিকে (যেমন Single , Observable , Completable ) কমপোজ State রূপান্তর করে।

    build.gradle ফাইলে নিম্নলিখিত নির্ভরতা প্রয়োজন:

কোটলিন

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-rxjava3:1.8.1")
}

গ্রোভি

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-rxjava3:1.8.1"
}

রাষ্ট্রীয় বনাম রাষ্ট্রহীন

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

একটি রাষ্ট্রবিহীন কমপোজেবল একটি কম্পোজেবল যা কোনও রাষ্ট্রকে ধরে রাখে না। রাষ্ট্রবিহীন অর্জনের একটি সহজ উপায় হ'ল রাষ্ট্র উত্তোলন ব্যবহার করে।

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

রাষ্ট্র উত্তোলন

কমপোজে রাষ্ট্রীয় উত্তোলন একটি কমপোজেবল স্টেটলেস তৈরি করতে স্টেটকে একটি কমপোজেবলের কলারে স্থানান্তরিত করার একটি প্যাটার্ন। জেটপ্যাক রচনাটিতে রাষ্ট্র উত্তোলনের জন্য সাধারণ প্যাটার্নটি হ'ল দুটি পরামিতি দিয়ে রাষ্ট্রীয় পরিবর্তনশীলকে প্রতিস্থাপন করা:

  • value: T : প্রদর্শনের বর্তমান মান
  • onValueChange: (T) -> Unit : এমন একটি ইভেন্ট যা পরিবর্তনের মানকে অনুরোধ করে, যেখানে T প্রস্তাবিত নতুন মান

তবে আপনি onValueChange মধ্যে সীমাবদ্ধ নন। যদি আরও নির্দিষ্ট ইভেন্টগুলি কমপোজেবলের জন্য উপযুক্ত হয় তবে আপনার ল্যাম্বডাস ব্যবহার করে সেগুলি সংজ্ঞায়িত করা উচিত।

এইভাবে উত্তোলন করা রাষ্ট্রের কিছু গুরুত্বপূর্ণ বৈশিষ্ট্য রয়েছে:

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

উদাহরণস্বরূপ, আপনি HelloContent বাইরে name এবং onValueChange বের করেন এবং গাছটিকে একটি HelloScreen কমপোজেবলের কাছে নিয়ে যান যা HelloContent বলে।

@Composable
fun HelloScreen() {
    var name by rememberSaveable { mutableStateOf("") }

    HelloContent(name = name, onNameChange = { name = it })
}

@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello, $name",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.bodyMedium
        )
        OutlinedTextField(value = name, onValueChange = onNameChange, label = { Text("Name") })
    }
}

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

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

আরও শিখতে স্টেট পৃষ্ঠাটি কোথায় উত্তোলন করবেন তা দেখুন।

কমপোজে রাষ্ট্র পুনরুদ্ধার

rememberSaveable এপিআই একইভাবে remember জন্য আচরণ করে কারণ এটি সংরক্ষণগুলি জুড়ে রাজ্যকে ধরে রাখে এবং সংরক্ষিত উদাহরণ রাষ্ট্রীয় প্রক্রিয়াটি ব্যবহার করে ক্রিয়াকলাপ বা প্রক্রিয়া বিনোদন জুড়েও। উদাহরণস্বরূপ, এটি ঘটে যখন স্ক্রিনটি ঘোরানো হয়।

রাজ্য সঞ্চয় করার উপায়

Bundle যুক্ত হওয়া সমস্ত ডেটা প্রকারগুলি স্বয়ংক্রিয়ভাবে সংরক্ষণ করা হয়। আপনি যদি এমন কিছু সংরক্ষণ করতে চান যা Bundle যুক্ত করা যায় না তবে বেশ কয়েকটি বিকল্প রয়েছে।

পার্সেলাইজ করুন

সবচেয়ে সহজ সমাধান হ'ল অবজেক্টে @Parcelize টীকা যুক্ত করা। অবজেক্টটি পার্সেলেবল হয়ে যায় এবং বান্ডিল করা যায়। উদাহরণস্বরূপ, এই কোডটি একটি পার্সেলেবল City ডেটা টাইপ করে এবং এটি রাজ্যে সংরক্ষণ করে।

@Parcelize
data class City(val name: String, val country: String) : Parcelable

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

মানচিত্রের

যদি কোনও কারণে @Parcelize উপযুক্ত না হয় তবে আপনি কোনও বস্তুকে এমন মানগুলির সেটে রূপান্তর করার জন্য নিজের নিয়মটি সংজ্ঞায়িত করতে mapSaver ব্যবহার করতে পারেন যা সিস্টেমটি Bundle সংরক্ষণ করতে পারে।

data class City(val name: String, val country: String)

val CitySaver = run {
    val nameKey = "Name"
    val countryKey = "Country"
    mapSaver(
        save = { mapOf(nameKey to it.name, countryKey to it.country) },
        restore = { City(it[nameKey] as String, it[countryKey] as String) }
    )
}

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable(stateSaver = CitySaver) {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

তালিকাভুক্ত

মানচিত্রের কীগুলি সংজ্ঞায়িত করার প্রয়োজন এড়াতে, আপনি listSaver ব্যবহার করতে পারেন এবং এর সূচকগুলি কী হিসাবে ব্যবহার করতে পারেন:

data class City(val name: String, val country: String)

val CitySaver = listSaver<City, Any>(
    save = { listOf(it.name, it.country) },
    restore = { City(it[0] as String, it[1] as String) }
)

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable(stateSaver = CitySaver) {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

কমপোজে রাজ্য ধারক

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

কমপোজ ডকুমেন্টেশনে বা আরও সাধারণভাবে, আরও শিখতে আর্কিটেকচার গাইডে রাজ্যধারক এবং ইউআই রাজ্য পৃষ্ঠা দেখুন।

Retrigger গণনা মনে রাখবেন যখন কীগুলি পরিবর্তন হয়

remember এপিআই প্রায়শই MutableState সাথে একসাথে ব্যবহৃত হয়:

var name by remember { mutableStateOf("") }

এখানে, remember ফাংশনটি ব্যবহার করে MutableState মানকে পুনরুদ্ধার করে তোলে।

সাধারণভাবে, remember একটি calculation ল্যাম্বদা প্যারামিটার নেয়। যখন remember প্রথমটি চালানো হয়, এটি calculation ল্যাম্বডাকে অনুরোধ করে এবং এর ফলাফল সঞ্চয় করে। পুনরুদ্ধার করার সময়, remember যে সর্বশেষে সঞ্চিত মানটি ফেরত দেয়।

ক্যাচিং অবস্থা ছাড়াও, আপনি যে কোনও অবজেক্ট সংরক্ষণ করতে বা রচনাটিতে কোনও অপারেশনের ফলাফল সংরক্ষণ করতেও remember করতে পারেন যা আরম্ভ করা বা গণনা করা ব্যয়বহুল। আপনি প্রতিটি পুনঃনির্মাণে এই গণনাটি পুনরাবৃত্তি করতে চাইবেন না। একটি উদাহরণ এই ShaderBrush অবজেক্ট তৈরি করছে, যা একটি ব্যয়বহুল অপারেশন:

val brush = remember {
    ShaderBrush(
        BitmapShader(
            ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(),
            Shader.TileMode.REPEAT,
            Shader.TileMode.REPEAT
        )
    )
}

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

নিম্নলিখিত উদাহরণগুলি দেখায় যে এই প্রক্রিয়াটি কীভাবে কাজ করে।

এই স্নিপেটে, একটি ShaderBrush তৈরি করা হয় এবং একটি Box কম্পোজেবলের ব্যাকগ্রাউন্ড পেইন্ট হিসাবে ব্যবহৃত হয়। remember ShaderBrush উদাহরণটি সঞ্চয় করে কারণ এটি পুনরায় তৈরি করা ব্যয়বহুল, যেমনটি আগে ব্যাখ্যা করা হয়েছে। remember avatarRes key1 প্যারামিটার হিসাবে নেয়, যা নির্বাচিত ব্যাকগ্রাউন্ড চিত্র। যদি avatarRes পরিবর্তিত হয় তবে ব্রাশটি নতুন চিত্রের সাথে পুনঃনির্মাণ করে এবং Box পুনরায় প্রয়োগ হয়। এটি ঘটতে পারে যখন ব্যবহারকারী কোনও পিকার থেকে পটভূমি হতে অন্য চিত্র নির্বাচন করে।

@Composable
private fun BackgroundBanner(
    @DrawableRes avatarRes: Int,
    modifier: Modifier = Modifier,
    res: Resources = LocalContext.current.resources
) {
    val brush = remember(key1 = avatarRes) {
        ShaderBrush(
            BitmapShader(
                ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(),
                Shader.TileMode.REPEAT,
                Shader.TileMode.REPEAT
            )
        )
    }

    Box(
        modifier = modifier.background(brush)
    ) {
        /* ... */
    }
}

পরবর্তী স্নিপেটে, রাজ্যটি একটি সরল রাষ্ট্রধারার ক্লাস MyAppState উত্তোলন করা হয়। এটি remember ব্যবহার করে ক্লাসের একটি উদাহরণ সূচনা করতে এটি একটি rememberMyAppState ফাংশনটি প্রকাশ করে। পুনরুদ্ধারগুলি বেঁচে থাকা এমন একটি উদাহরণ তৈরি করতে এই জাতীয় ফাংশনগুলি প্রকাশ করা রচনাটি একটি সাধারণ প্যাটার্ন। rememberMyAppState ফাংশনটি windowSizeClass গ্রহণ করে, যা remember জন্য key প্যারামিটার হিসাবে কাজ করে। If this parameter changes, the app needs to recreate the plain state holder class with the latest value. This may occur if, for example, the user rotates the device.

@Composable
private fun rememberMyAppState(
    windowSizeClass: WindowSizeClass
): MyAppState {
    return remember(windowSizeClass) {
        MyAppState(windowSizeClass)
    }
}

@Stable
class MyAppState(
    private val windowSizeClass: WindowSizeClass
) { /* ... */ }

Compose uses the class's equals implementation to decide if a key has changed and invalidate the stored value.

Store state with keys beyond recomposition

The rememberSaveable API is a wrapper around remember that can store data in a Bundle . This API allows state to survive not only recomposition, but also activity recreation and system-initiated process death. rememberSaveable receives input parameters for the same purpose that remember receives keys . The cache is invalidated when any of the inputs change . The next time the function recomposes, rememberSaveable re-executes the calculation lambda block.

In the following example, rememberSaveable stores userTypedQuery until typedQuery changes:

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

আরও জানুন

To learn more about state and Jetpack Compose, consult the following additional resources.

নমুনা

কোডল্যাব

ভিডিও

ব্লগ

{% verbatim %} {% endverbatim %} {% verbatim %} {% endverbatim %}