রচনা এবং অন্যান্য লাইব্রেরি

আপনি কম্পোজে আপনার পছন্দের লাইব্রেরি ব্যবহার করতে পারেন। এই বিভাগে বর্ণনা করা হয়েছে কিভাবে সবচেয়ে দরকারী কয়েকটি লাইব্রেরি অন্তর্ভুক্ত করা যায়।

কার্যকলাপ

কোনও অ্যাক্টিভিটিতে Compose ব্যবহার করার জন্য, আপনাকে ComponentActivity ব্যবহার করতে হবে, যা Activity এর একটি সাবক্লাস যা উপযুক্ত LifecycleOwner এবং Composes-এর জন্য উপাদান সরবরাহ করে। এটি অতিরিক্ত APIও প্রদান করে যা আপনার অ্যাক্টিভিটি ক্লাসের ওভাররাইডিং পদ্ধতি থেকে আপনার কোডকে ডিকপল করে। Activity Compose এই APIগুলিকে composables-এর কাছে উন্মুক্ত করে যাতে আপনার composables-এর বাইরের পদ্ধতিগুলিকে ওভাররাইড করা বা একটি স্পষ্ট Activity ইনস্ট্যান্স পুনরুদ্ধার করার আর প্রয়োজন হয় না। তাছাড়া, এই APIগুলি নিশ্চিত করে যে এগুলি কেবল একবারই শুরু করা হয়েছে, পুনর্গঠন টিকে আছে এবং কম্পোজিশন থেকে কম্পোজিবল সরানো হলে সঠিকভাবে পরিষ্কার করা হয়েছে।

কার্যকলাপের ফলাফল

rememberLauncherForActivityResult() API আপনাকে আপনার কম্পোজেবলের একটি কার্যকলাপ থেকে ফলাফল পেতে দেয়:

@Composable
fun GetContentExample() {
    var imageUri by remember { mutableStateOf<Uri?>(null) }
    val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
        imageUri = uri
    }
    Column {
        Button(onClick = { launcher.launch("image/*") }) {
            Text(text = "Load Image")
        }
        Image(
            painter = rememberAsyncImagePainter(imageUri),
            contentDescription = "My Image"
        )
    }
}

এই উদাহরণটি একটি সহজ GetContent() চুক্তি প্রদর্শন করে। বোতামটি ট্যাপ করলে অনুরোধটি চালু হয়। ব্যবহারকারী যখন একটি ছবি নির্বাচন করে এবং লঞ্চিং কার্যকলাপে ফিরে আসে তখন rememberLauncherForActivityResult() এর জন্য ট্রেলিং ল্যাম্বডা চালু হয়। এটি Coil এর rememberImagePainter() ফাংশন ব্যবহার করে নির্বাচিত ছবিটি লোড করে।

rememberLauncherForActivityResult() এর প্রথম আর্গুমেন্ট হিসেবে ActivityResultContract এর যেকোনো সাবক্লাস ব্যবহার করা যেতে পারে। এর মানে হল আপনি এই কৌশলটি ব্যবহার করে ফ্রেমওয়ার্ক এবং অন্যান্য সাধারণ প্যাটার্ন থেকে কন্টেন্ট অনুরোধ করতে পারেন। আপনি আপনার নিজস্ব কাস্টম চুক্তিও তৈরি করতে পারেন এবং এই কৌশলটি ব্যবহার করতে পারেন।

রানটাইম অনুমতির অনুরোধ করা হচ্ছে

উপরে বর্ণিত একই Activity Result API এবং rememberLauncherForActivityResult() ব্যবহার করে একক অনুমতির জন্য RequestPermission চুক্তি অথবা একাধিক অনুমতির জন্য RequestMultiplePermissions চুক্তি ব্যবহার করে রানটাইম অনুমতির অনুরোধ করা যেতে পারে।

Accompanist Permissions লাইব্রেরিটি সেই API গুলির উপরে একটি স্তর ব্যবহার করে বর্তমান অনুমোদিত অনুমতির অবস্থা ম্যাপ করা যেতে পারে যা আপনার Compose UI ব্যবহার করতে পারে।

সিস্টেম ব্যাক বোতামটি পরিচালনা করা

আপনার কম্পোজেবলের ভেতর থেকে কাস্টম ব্যাক নেভিগেশন প্রদান এবং সিস্টেম ব্যাক বোতামের ডিফল্ট আচরণকে ওভাররাইড করতে, আপনার কম্পোজেবল সেই ইভেন্টটি আটকাতে একটি BackHandler ব্যবহার করতে পারে:

var backHandlingEnabled by remember { mutableStateOf(true) }
BackHandler(backHandlingEnabled) {
    // Handle back press
}

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

ViewModel

যদি আপনি Architecture Components ViewModel লাইব্রেরি ব্যবহার করেন, তাহলে আপনি viewModel() ফাংশনটি কল করে যেকোনো কম্পোজেবল থেকে ViewModel অ্যাক্সেস করতে পারবেন। আপনার Gradle ফাইলে নিম্নলিখিত নির্ভরতা যোগ করুন:

খাঁজকাটা

dependencies {
    implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5'
}

কোটলিন

dependencies {
    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5")
}

তারপর আপনি আপনার কোডে viewModel() ফাংশনটি ব্যবহার করতে পারেন।

class MyViewModel : ViewModel() { /*...*/ }

// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    // use viewModel here
}

viewModel() একটি বিদ্যমান ViewModel ফেরত পাঠায় অথবা একটি নতুন তৈরি করে। ডিফল্টরূপে, ফিরে আসা ViewModel এনক্লোজিং অ্যাক্টিভিটি, ফ্র্যাগমেন্ট বা নেভিগেশন গন্তব্যে স্কোপ করা হয় এবং যতক্ষণ স্কোপটি সক্রিয় থাকে ততক্ষণ পর্যন্ত এটি ধরে রাখা হয়।

উদাহরণস্বরূপ, যদি কম্পোজেবলটি কোনও কার্যকলাপে ব্যবহার করা হয়, তাহলে viewModel() কার্যকলাপটি শেষ না হওয়া পর্যন্ত বা প্রক্রিয়াটি বন্ধ না হওয়া পর্যন্ত একই উদাহরণ প্রদান করে।

class MyViewModel : ViewModel() { /*...*/ }
// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    // Returns the same instance as long as the activity is alive,
    // just as if you grabbed the instance from an Activity or Fragment
    viewModel: MyViewModel = viewModel()
) { /* ... */ }

@Composable
fun MyScreen2(
    viewModel: MyViewModel = viewModel() // Same instance as in MyScreen
) { /* ... */ }

ব্যবহারের নির্দেশিকা

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

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

সাব স্ক্রিন-লেভেল কম্পোজেবলের অবস্থা পরিচালনা করতে আপনি ViewModel ইনস্ট্যান্স ব্যবহার করতে পারেন , তবে ViewModel এর জীবনচক্র এবং সুযোগ সম্পর্কে সচেতন থাকুন। যদি কম্পোজেবলটি স্বয়ংসম্পূর্ণ হয়, তাহলে প্যারেন্ট কম্পোজেবল থেকে নির্ভরতা এড়াতে ViewModel ইনজেক্ট করার জন্য আপনি Hilt ব্যবহার করার কথা বিবেচনা করতে পারেন।

যদি আপনার ViewModel উপর নির্ভরতা থাকে, viewModel() একটি ঐচ্ছিক ViewModelProvider.Factory প্যারামিটার হিসেবে গ্রহণ করে।

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

তথ্যের প্রবাহ

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

  • LiveData.observeAsState() androidx.compose.runtime:runtime-livedata:$composeVersion আর্টিফ্যাক্টে অন্তর্ভুক্ত।
  • Flow.collectAsState() জন্য অতিরিক্ত নির্ভরতা প্রয়োজন হয় না।
  • Observable.subscribeAsState() androidx.compose.runtime:runtime-rxjava2:$composeVersion অথবা androidx.compose.runtime:runtime-rxjava3:$composeVersion আর্টিফ্যাক্টে অন্তর্ভুক্ত।

এই আর্টিফ্যাক্টগুলি শ্রোতা হিসেবে নিবন্ধিত হয় এবং মানগুলিকে State হিসেবে উপস্থাপন করে। যখনই একটি নতুন মান নির্গত হয়, Compose UI এর সেই অংশগুলিকে পুনরায় কম্পোজ করে যেখানে সেই state.value ব্যবহার করা হয়। উদাহরণস্বরূপ, এই কোডে, প্রতিবার exampleLiveData একটি নতুন মান নির্গত করার সময় ShowData পুনরায় কম্পোজ করে।

// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    val dataExample = viewModel.exampleLiveData.observeAsState()

    // Because the state is read here,
    // MyScreen recomposes whenever dataExample changes.
    dataExample.value?.let {
        ShowData(dataExample)
    }
}

কম্পোজে অ্যাসিঙ্ক্রোনাস অপারেশন

জেটপ্যাক কম্পোজ আপনাকে আপনার কম্পোজেবলের মধ্যে থেকে কোরোটিন ব্যবহার করে অ্যাসিঙ্ক্রোনাস অপারেশন সম্পাদন করতে দেয়।

আরও তথ্যের জন্য পার্শ্ব প্রতিক্রিয়া ডকুমেন্টেশনে LaunchedEffect , produceState এবং rememberCoroutineScope API গুলি দেখুন।

নেভিগেশন কম্পোনেন্টটি জেটপ্যাক কম্পোজ অ্যাপ্লিকেশনগুলির জন্য সমর্থন প্রদান করে। আরও তথ্যের জন্য কম্পোজ দিয়ে নেভিগেট করা এবং জেটপ্যাক নেভিগেশনকে নেভিগেশন কম্পোজে স্থানান্তর করা দেখুন।

হিল্ট

অ্যান্ড্রয়েড অ্যাপে নির্ভরতা ইনজেকশনের জন্য হিল্ট হল প্রস্তাবিত সমাধান, এবং কম্পোজের সাথে নির্বিঘ্নে কাজ করে।

ViewModel বিভাগে উল্লিখিত viewModel() ফাংশনটি স্বয়ংক্রিয়ভাবে ViewModel ব্যবহার করে যা Hilt @HiltViewModel অ্যানোটেশন দিয়ে তৈরি করে। আমরা Hilt এর ViewModel ইন্টিগ্রেশন সম্পর্কে তথ্য সহ ডকুমেন্টেশন সরবরাহ করেছি।

@HiltViewModel
class MyViewModel @Inject constructor(
    private val savedStateHandle: SavedStateHandle,
    private val repository: ExampleRepository
) : ViewModel() { /* ... */ }

// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) { /* ... */ }

হিল্ট এবং নেভিগেশন

হিল্ট নেভিগেশন কম্পোজ লাইব্রেরির সাথেও একীভূত হয়। আপনার গ্র্যাডল ফাইলে নিম্নলিখিত অতিরিক্ত নির্ভরতা যোগ করুন:

খাঁজকাটা

dependencies {
    implementation 'androidx.hilt:hilt-navigation-compose:1.3.0'
}

কোটলিন

dependencies {
    implementation("androidx.hilt:hilt-navigation-compose:1.3.0")
}

নেভিগেশন কম্পোজ ব্যবহার করার সময়, সর্বদা hiltViewModel composable ফাংশনটি ব্যবহার করে আপনার @HiltViewModel টীকাযুক্ত ViewModel এর একটি উদাহরণ পান। এটি @AndroidEntryPoint দিয়ে টীকাযুক্ত টুকরো বা কার্যকলাপের সাথে কাজ করে।

উদাহরণস্বরূপ, যদি ExampleScreen একটি নেভিগেশন গ্রাফে একটি গন্তব্য হয়, তাহলে নীচের কোড স্নিপেটে দেখানো হিসাবে ExampleViewModel এর একটি উদাহরণ গন্তব্যে পৌঁছাতে hiltViewModel() কল করুন:

// import androidx.hilt.navigation.compose.hiltViewModel

@Composable
fun MyApp() {
    val navController = rememberNavController()
    val startRoute = "example"
    NavHost(navController, startDestination = startRoute) {
        composable("example") { backStackEntry ->
            // Creates a ViewModel from the current BackStackEntry
            // Available in the androidx.hilt:hilt-navigation-compose artifact
            val viewModel = hiltViewModel<MyViewModel>()
            MyScreen(viewModel)
        }
        /* ... */
    }
}

যদি আপনার নেভিগেশন রুট বা নেভিগেশন গ্রাফের সাথে সংযুক্ত ViewModel এর উদাহরণ পুনরুদ্ধার করার প্রয়োজন হয়, তাহলে hiltViewModel composable ফাংশনটি ব্যবহার করুন এবং সংশ্লিষ্ট backStackEntry একটি প্যারামিটার হিসেবে পাস করুন:

// import androidx.hilt.navigation.compose.hiltViewModel
// import androidx.navigation.compose.getBackStackEntry

@Composable
fun MyApp() {
    val navController = rememberNavController()
    val startRoute = "example"
    val innerStartRoute = "exampleWithRoute"
    NavHost(navController, startDestination = startRoute) {
        navigation(startDestination = innerStartRoute, route = "Parent") {
            // ...
            composable("exampleWithRoute") { backStackEntry ->
                val parentEntry = remember(backStackEntry) {
                    navController.getBackStackEntry("Parent")
                }
                val parentViewModel = hiltViewModel<ParentViewModel>(parentEntry)
                ExampleWithRouteScreen(parentViewModel)
            }
        }
    }
}

পেজিং

পেজিং লাইব্রেরি আপনার জন্য ধীরে ধীরে ডেটা লোড করা সহজ করে তোলে এবং এটি কম্পোজে সমর্থিত। পেজিং রিলিজ পৃষ্ঠায় প্রকল্প এবং এর সংস্করণে অতিরিক্ত paging-compose নির্ভরতা যোগ করার তথ্য রয়েছে।

পেজিং লাইব্রেরির কম্পোজ এপিআই-এর একটি উদাহরণ এখানে দেওয়া হল:

@Composable
fun MyScreen(flow: Flow<PagingData<String>>) {
    val lazyPagingItems = flow.collectAsLazyPagingItems()
    LazyColumn {
        items(
            lazyPagingItems.itemCount,
            key = lazyPagingItems.itemKey { it }
        ) { index ->
            val item = lazyPagingItems[index]
            Text("Item is $item")
        }
    }
}

কম্পোজে পেজিং ব্যবহার সম্পর্কে আরও তথ্যের জন্য তালিকা এবং গ্রিড ডকুমেন্টেশন দেখুন।

মানচিত্র

আপনার অ্যাপে Google Maps প্রদান করতে আপনি Maps Compose লাইব্রেরি ব্যবহার করতে পারেন। এখানে একটি ব্যবহারের উদাহরণ দেওয়া হল:

@Composable
fun MapsExample() {
    val singapore = LatLng(1.35, 103.87)
    val cameraPositionState = rememberCameraPositionState {
        position = CameraPosition.fromLatLngZoom(singapore, 10f)
    }
    GoogleMap(
        modifier = Modifier.fillMaxSize(),
        cameraPositionState = cameraPositionState
    ) {
        Marker(
            state = remember { MarkerState(position = singapore) },
            title = "Singapore",
            snippet = "Marker in Singapore"
        )
    }
}

{% অক্ষরে অক্ষরে %} {% এন্ডভারব্যাটিম %} {% অক্ষরে অক্ষরে %} {% এন্ডভারব্যাটিম %}