Lắng nghe sự thay đổi dữ liệu Realm Background trong Clean Architecture (Realm + Flow + Clean Architecture)
Bài đăng này đã không được cập nhật trong 3 năm
Mở đầu
Tôi thích dùng realm trong dự án vì tốc độ và tính linh hoạt khi lắng nghe sự thay đổi dữ liệu từ database, Thế nhưng điều đó không còn khi tôi làm việc với một dự án xây dựng theo mô hình clean architecture bởi tính độc lập giữa các tầng trong dự án.
Cách
Có cách nào không? có chứ và có nhiều ) chúng ta cùng thử liệt kê nhé:
Realm + Broadcast Receiver ---> quá tốn tài nguyên, cần phải viết hàm đăng ký lắng nghe và hủy đăng ký của Broadcast Receiver
Realm + Live Data ---> hay, nhưng live data là của android mà tầng nghiệp vụ (Domain) thì không nên chứa android trong đó
Realm + Rx ---> hay, nhưng yêu cầu toàn bộ luồng xử lý sẽ phải xử lý trong luồng main thread (ảnh hưởng đến UI)
Vậy còn cách nào nữa không nhỉ, tôi đã rất tuyệt vọng cho đến khi Flow trong Coroutines xuất hiện tính linh hoạt trong đa luồng đã thu hút tôi tìm hiểm thật tuyệt khi tôi đã tìm ra giải pháp cho nó =)), giờ thì cùng thử code nào
Code
Code Base
@OptIn(ExperimentalCoroutinesApi::class)
fun <S : RealmObject, R> handlerAndReturnListFlow(block: () -> RealmQuery<S>): Flow<List<R>> = callbackFlow {
val results = block().findAllAsync()!!
val realm = results.realm!!
val listener = RealmChangeListener<RealmResults<S>> { t ->
offer(realm.copyFromRealm(t))
}
results.addChangeListener(listener)
offer(realm.copyFromRealm(results))
awaitClose {
if (!realm.isClosed) {
results.removeChangeListener(listener)
realm.close()
}
}
}.flowOn(Dispatchers.Main) // đẩy bộ lắng nghe thay đổi dữ liệu vào trong luồng main để tận dụng cơ chế looper của main
/*.flowOn(android.os.Handler(HandlerThread("RealmDb").apply { start() }.looper).asCoroutineDispatcher("db"))*/ // đẩy bộ lắng nghe thay đổi dữ liệu vào trong luồng background, nhưng hãy chắc chắn rằng bạn quản lý tốt về thread
.map {
// chuyển đổi entity database S sang entity R
}
Code in Database
fun getAll() = handlerAndReturnListFlow {
Realm.getDefaultInstance().where(TestObject::class.java)
}
Code in Repository
fun getAll() = testDb.getAll()
Code in UseCase
fun execute() = testRepository.getAll()
Code in ViewModel
fun listTest = getAllTest.execute()
.asLiveData(Dispatchers.IO) // yêu cầu xử lý trong luồng backgroud
Code in Activity
viewModel.listTest.observe(this){
Log.d("HoangAnhTuan95Ptit", "onCreate: ${it.size}")
}
Tài liệu tham khảo
Tự nghĩ ra =))), có thể sắp tới mình sẽ viết một bài trên medium
Kết
Tôi hi vọng sẽ giúp ích cho bạn trong quá trình làm việc với realm trong clean architecture, Nếu có bất kỳ thắc mắc nào thì đừng ngần ngại comment vào bài viết, tôi sẽ cố gắng trả lời. Cảm ơn
All rights reserved