Dòng chảy Kotlin vs Android LiveData


20

Tôi có một số câu hỏi về Dòng chảy Kotlin

  1. Tôi có thể quan sát LiveData từ nhiều mảnh vỡ. Tôi có thể làm điều này với Flow không? Nếu có thì làm thế nào?
  2. Chúng tôi có thể có nhiều LiveData từ một LiveData bằng cách sử dụng map& switchMap. Có cách nào để có nhiều Flow từ một luồng nguồn không?
  3. Sử dụng MutableLiveDataTôi có thể cập nhật dữ liệu từ bất cứ đâu bằng cách sử dụng tham chiếu biến. Có cách nào để làm điều tương tự với Flow không?

Tôi có một trường hợp sử dụng như: Tôi sẽ quan sát SharedPreferencesviệc sử dụng callbackFlow{...}sẽ cung cấp cho tôi một luồng nguồn duy nhất. Từ luồng đó, tôi muốn tạo nhiều luồng cho mỗi cặp khóa-giá trị.

Đây có thể là những câu hỏi ngớ ngẩn. Tôi mới đến thế giới Rx và Flow.


Cách tiếp cận nào bạn đã giải quyết - Flow hoặc LiveData ?
IgorGanapolsky

2
Hiện tại, tôi đang sử dụng LiveData cho lượt xem và Flow cho mọi thứ khác. Trong ViewModel, tôi nhận được Flow và phát LiveData để quan sát từ các mảnh vỡ.
zoha131

@ zoha131 bạn làm điều đó đúng cách! Vì LiveData chỉ có thể được quan sát trên luồng chính, chúng phù hợp hoàn hảo với các tương tác View <-> ViewModel. Sau đó, Flows cho phép bạn thực hiện các hoạt động phức tạp hơn trong phần còn lại của kiến ​​trúc.
smora

Câu trả lời:


15

Tôi có thể quan sát LiveData từ nhiều mảnh vỡ. Tôi có thể làm điều này với Flow không? Nếu có thì làm thế nào?

Đúng. Bạn có thể làm điều này với emitcollect. Suy nghĩ emittương tự như dữ liệu trực tiếp postValuecollecttương tự như observe. Hãy cho một ví dụ.

Kho

// I just faked the weather forecast
val weatherForecast = listOf("10", "12", "9")

// This function returns flow of forecast data
// Whenever the data is fetched, it is emitted so that
// collector can collect (if there is any)
fun getWeatherForecastEveryTwoSeconds(): Flow<String> = flow { 
    for (i in weatherForecast) {
        delay(2000)
        emit(i)
    }
}

ViewModel

fun getWeatherForecast(): Flow<String> {
    return forecastRepository.getWeatherForecastEveryTwoSeconds()
}

Miếng

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    // Collect is suspend function. So you have to call it from a 
    // coroutine scope. You can create a new coroutine or just use 
    // lifecycleScope
    // https://developer.android.com/topic/libraries/architecture/coroutines
    lifecycleScope.launch {
            viewModel.getWeatherForecastEveryTwoSeconds().collect {
                    // Use the weather forecast data
                    // This will be called 3 times since we have 3 
                    // weather forecast data
            }
    }
}

Chúng tôi có thể có nhiều LiveData từ một LiveData bằng cách sử dụng map & switchMap. Có cách nào để có nhiều Flow từ một luồng nguồn không?

Dòng chảy rất tiện dụng. Bạn chỉ có thể tạo dòng chảy bên trong dòng chảy. Hãy nói rằng bạn muốn thêm ký hiệu độ vào từng dữ liệu dự báo thời tiết.

ViewModel

fun getWeatherForecast(): Flow<String> {
    return flow {
        forecastRepository
            .getWeatherForecastEveryTwoSeconds(spendingDetailsRequest)
                .map {
                    it + " °C"
                }
                .collect {
                    // This will send "10 °C", "12 °C" and "9 °C" respectively
                    emit(it) 
                }
    }
}

Sau đó thu thập dữ liệu trong Fragment giống như # 1. Ở đây điều xảy ra là mô hình xem đang thu thập dữ liệu từ kho lưu trữ và đoạn đang thu thập dữ liệu từ mô hình xem.

Sử dụng MutableLiveData Tôi có thể cập nhật dữ liệu từ bất cứ đâu bằng cách sử dụng tham chiếu biến. Có cách nào để làm điều tương tự với Flow không?

Bạn không thể phát ra giá trị bên ngoài dòng chảy. Khối mã bên trong luồng chỉ được thực thi khi có bất kỳ trình thu thập nào. Nhưng bạn có thể chuyển đổi luồng thành dữ liệu trực tiếp bằng cách sử dụng tiện ích mở rộng asLiveData từ LiveData.

ViewModel

fun getWeatherForecast(): LiveData<String> {
    return forecastRepository
    .getWeatherForecastEveryTwoSeconds()
    .asLiveData() // Convert flow to live data
}

Trong trường hợp của bạn, bạn có thể làm điều này

private fun getSharedPrefFlow() = callbackFlow {
    val sharedPref = context?.getSharedPreferences("SHARED_PREF_NAME", MODE_PRIVATE)
    sharedPref?.all?.forEach {
        offer(it)
    }
}

getSharedPrefFlow().collect {
    val key = it.key
    val value = it.value
}

Biên tập

Cảm ơn @mark vì bình luận của anh ấy. Tạo một luồng mới trong mô hình khung nhìn cho getWeatherForecastchức năng thực sự không cần thiết. Nó có thể được viết lại thành

fun getWeatherForecast(): Flow<String> {
        return forecastRepository
                .getWeatherForecastEveryTwoSeconds(spendingDetailsRequest)
                    .map {
                        it + " °C"
                    }
    }

Tôi không biết tại sao nhưng tôi có một giả định rằng tôi không thể gọi hàm coll () ở nhiều nơi cho một Luồng. cảm ơn câu trả lời
zoha131

1
Không. Bạn có thể thu thập cùng một luồng ở nhiều nơi. val sharedPref = getSharedPref()và bạn có thể sử dụng thu thập ở nhiều nơi sharedPref.collect {}. Điều duy nhất là vì thu thập bị đình chỉ, bạn cần gọi nó từ khối coroutine. Và rất vui khi được giúp đỡ np :)
Fatih

đối với câu hỏi thứ ba của tôi, cách giải quyết có thể là một kênh phát sóng.
zoha131

Bạn có thể kiểm tra cam kết này để sử dụng các kênh thay vì dữ liệu trực tiếp. github.com/android/plaid/pull/770/commits/ từ
Fatih

1
Có bạn đúng. Đây là nơi dòng chảy đến. Các kênh có rất nhiều thứ bạn phải quan tâm và chúng có nghĩa là chúng luôn mở ngay cả khi không có người quan sát. Nhưng với dòng chảy, bạn có thể nhận được những lợi ích tương tự mà không có bất kỳ mối quan tâm nào vì chúng lạnh. Vì vậy, thay vì kênh tôi nghĩ tốt hơn nên sử dụng luồng
Fatih

3

Có một Flow.asLiveData()chức năng mở rộng mới trong các androidx.lifecyclegói ktx mới . Bạn có thể tìm hiểu thêm trong bài viết của tôi: https://www.netguru.com/codestories/android-coroutines-%EF%B8%8Fin-2020


Khi nào chúng ta cần sử dụng cái này?
IgorGanapolsky

1
Khi bạn muốn đáp ứng API yêu cầu LiveData với phiên bản Flow
Samuel Urbanowicz

Theo google, chúng tôi phải chọn LiveData hoặc Flow: codelabs.developers.google.com/codelabs/ mẹo
IgorGanapolsky

1

Trong kiến ​​trúc 3 tầng: trình bày miền dữ liệu, Flow sẽ diễn ra trong lớp dữ liệu (cơ sở dữ liệu, mạng, bộ đệm ...) và sau đó như Samuel Urbanowicz đã đề cập, bạn có thể ánh xạ Flow tới LiveData.

Nói chung, Flow gần như là những gì mà Observable (hoặc Flowable) dành cho RxJava. Đừng nhầm lẫn nó với LiveData.

thêm tại đây: https://medium.com/@elizarov/cold-flows-hot-channels-d74769805f9


Đối với các thao tác một lần (tức là đọc Cơ sở dữ liệu), LiveData là đủ.
IgorGanapolsky
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.