chrisChris
chrisChris

Reputation: 99

How to communicate between adapter vs jetpack compose (lazy column)?

In classic Android programming (before composites) to show list on recyclerview I need adapter and if I want to give any action like clickable element, where logic will be provide in fragment/viewmodel I had to through argument create such parameter like

(Int) -> Unit

how does it look in jetpack compose when I create lazy column? Should it look the same and just create paramaters in Screens/UI then configure logic in the same way in fragment/viewmodel or there is some other approachs?

Upvotes: 0

Views: 1140

Answers (1)

m.reiter
m.reiter

Reputation: 2565

Getting rid of all the bloat of recyclerview is one of my favorite advantages of compose. Let's assume you'd like to include the following list in your screen:

@Composable
private fun TestList(
    myItems: List<String>,
    onClick: (String) -> Unit,
    modifier: Modifier = Modifier,
) {
    LazyColumn(modifier.fillMaxSize()) {
        items(myItems) { item ->
            TestItemView(
                text = item,
                onClick = onClick
            )
        }
    }
}

@Composable
private fun TestItemView(
    text: String,
    onClick: (String) -> Unit,
    modifier: Modifier = Modifier,
) {
    Surface(modifier.fillMaxWidth()) {
        Button(
            onClick = { onClick(text) },
            content = { Text(text) }
        )
    }
}

Option A: keep the state in the composable.

@Composable
private fun TestScreenA() {
    val myItems = remember { mutableStateOf(listOf("A", "B", "C", "D")) }

    TestList(
        myItems = myItems.value,
        onClick = { clickedItem ->
            // for demonstration purposes we remove item on click
            myItems.value = myItems.value.filterNot { it == clickedItem }
        }
    )
}

Option B: Keep the state in the viewmodel (like before)

class TestViewModelB: ViewModel() {
    private val _myItems = MutableStateFlow(listOf("A", "B", "C", "D"))
    val myItems = _myItems.asStateFlow()

    fun onItemClicked(clickedItem: String){
         // for demonstration purposes we remove item on click
        _myItems.update { items -> items.filterNot { it == clickedItem } }
    }
}

@Composable
private fun TestScreenB(
    // inject viewModel here using your favorite DI-Framework
    viewModel: TestViewModelB 
) {
    TestList(
        // you might want to use collectAsStateWithLifecycle in the future
        // see https://medium.com/androiddevelopers/consuming-flows-safely-in-jetpack-compose-cde014d0d5a3
        myItems = viewModel.myItems.collectAsState().value,
        onClick = viewModel::onItemClicked
    )
}

Both options are viable (especially when using rememberSavable). However, i suggest to use optionB for people just migrating to compose, as its more similar to what they're used. I personally use OptionA for simple states, and OptionB for more complex ones (like a list)

Upvotes: 1

Related Questions