import com.mindorks.kotlinFlow.data.model.ApiUser import com.mindorks.kotlinFlow.learn.base.ApiUserAdapter import com.mindorks.kotlinFlow.utils.Status import com.mindorks.kotlinFlow.utils.ViewModelFactory import kotlinx.android.synthetic.main.activity_recycler_view.*
class ParallelNetworkCallsActivity : AppCompatActivity() {
private lateinit var viewModel: ParallelNetworkCallsViewModel
private lateinit var adapter: ApiUserAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recycler_view)
setupUI()
setupViewModel()
setupObserver()
}
private fun setupUI() {
recyclerView.layoutManager = LinearLayoutManager(this)
adapter =
ApiUserAdapter(
arrayListOf()
)
recyclerView.addItemDecoration(
DividerItemDecoration(
recyclerView.context,
(recyclerView.layoutManager as LinearLayoutManager).orientation
)
)
recyclerView.adapter = adapter
}
private fun setupObserver() {
viewModel.getUsers().observe(this, Observer {
when (it.status) {
Status.SUCCESS -> {
progressBar.visibility = View.GONE
it.data?.let { users -> renderList(users) }
recyclerView.visibility = View.VISIBLE
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
recyclerView.visibility = View.GONE
}
Status.ERROR -> {
//Handle Error
progressBar.visibility = View.GONE
Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
}
}
})
}
private fun renderList(users: List<ApiUser>) {
adapter.addData(users)
adapter.notifyDataSetChanged()
}
private fun setupViewModel() {
viewModel = ViewModelProviders.of(
this,
ViewModelFactory(
ApiHelperImpl(RetrofitBuilder.apiService),
DatabaseHelperImpl(DatabaseBuilder.getInstance(applicationContext))
)
).get(ParallelNetworkCallsViewModel::class.java)
}
}
* 视图模型代码
package com.mindorks.kotlinFlow.learn.retrofit.parallel
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mindorks.kotlinFlow.data.api.ApiHelper import com.mindorks.kotlinFlow.data.local.DatabaseHelper import com.mindorks.kotlinFlow.data.model.ApiUser import com.mindorks.kotlinFlow.utils.Resource import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.zip import kotlinx.coroutines.launch
class ParallelNetworkCallsViewModel( private val apiHelper: ApiHelper, private val dbHelper: DatabaseHelper ) : ViewModel() {
private val users = MutableLiveData<Resource<List<ApiUser>>>()
init {
fetchUsers()
}
private fun fetchUsers() {
viewModelScope.launch {
users.postValue(Resource.loading(null))
apiHelper.getUsers()
.zip(apiHelper.getMoreUsers()) { usersFromApi, moreUsersFromApi ->
val allUsersFromApi = mutableListOf<ApiUser>()
allUsersFromApi.addAll(usersFromApi)
allUsersFromApi.addAll(moreUsersFromApi)
return@zip allUsersFromApi
}
.flowOn(Dispatchers.Default)
.catch { e ->
users.postValue(Resource.error(e.toString(), null))
}
.collect {
users.postValue(Resource.success(it))
}
}
}
fun getUsers(): LiveData<Resource<List<ApiUser>>> {
return users
}
}
* **Room数据库操作**:了解如何使用 Kotlin Flow 在数据库中获取或插入实体。当您在 Android 应用程序中使用房间数据库时,这很有用。
* 活动代码
package com.mindorks.kotlinFlow.learn.room
import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.mindorks.kotlinFlow.R import com.mindorks.kotlinFlow.data.api.ApiHelperImpl import com.mindorks.kotlinFlow.data.api.RetrofitBuilder import com.mindorks.kotlinFlow.data.local.DatabaseBuilder import com.mindorks.kotlinFlow.data.local.DatabaseHelperImpl import com.mindorks.kotlinFlow.data.local.entity.User import com.mindorks.kotlinFlow.learn.base.UserAdapter import com.mindorks.kotlinFlow.utils.Status import com.mindorks.kotlinFlow.utils.ViewModelFactory import kotlinx.android.synthetic.main.activity_recycler_view.*
class RoomDBActivity : AppCompatActivity() {
private lateinit var viewModel: RoomDBViewModel
private lateinit var adapter: UserAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recycler_view)
setupUI()
setupViewModel()
setupObserver()
}
private fun setupUI() {
recyclerView.layoutManager = LinearLayoutManager(this)
adapter =
UserAdapter(
arrayListOf()
)
recyclerView.addItemDecoration(
DividerItemDecoration(
recyclerView.context,
(recyclerView.layoutManager as LinearLayoutManager).orientation
)
)
recyclerView.adapter = adapter
}
private fun setupObserver() {
viewModel.getUsers().observe(this, Observer {
when (it.status) {
Status.SUCCESS -> {
progressBar.visibility = View.GONE
it.data?.let { users -> renderList(users) }
recyclerView.visibility = View.VISIBLE
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
recyclerView.visibility = View.GONE
}
Status.ERROR -> {
//Handle Error
progressBar.visibility = View.GONE
Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
}
}
})
}
private fun renderList(users: List<User>) {
adapter.addData(users)
adapter.notifyDataSetChanged()
}
private fun setupViewModel() {
viewModel = ViewModelProviders.of(
this,
ViewModelFactory(
ApiHelperImpl(RetrofitBuilder.apiService),
DatabaseHelperImpl(DatabaseBuilder.getInstance(applicationContext))
)
).get(RoomDBViewModel::class.java)
}
}
* 视图模型代码
package com.mindorks.kotlinFlow.learn.room
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mindorks.kotlinFlow.data.api.ApiHelper import com.mindorks.kotlinFlow.data.local.DatabaseHelper import com.mindorks.kotlinFlow.data.local.entity.User import com.mindorks.kotlinFlow.utils.Resource import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch
class RoomDBViewModel(private val apiHelper: ApiHelper, private val dbHelper: DatabaseHelper) : ViewModel() {
private val users = MutableLiveData<Resource<List<User>>>()
init {
fetchUsers()
}
private fun fetchUsers() {
viewModelScope.launch {
users.postValue(Resource.loading(null))
dbHelper.getUsers()
.flatMapConcat { usersFromDb ->
if (usersFromDb.isEmpty()) {
return@flatMapConcat apiHelper.getUsers()
.map { apiUserList ->
val userList = mutableListOf<User>()
for (apiUser in apiUserList) {
val user = User(
apiUser.id,
apiUser.name,
apiUser.email,
apiUser.avatar
)
userList.add(user)
}
userList
}
.flatMapConcat { usersToInsertInDB ->
dbHelper.insertAll(usersToInsertInDB)
.flatMapConcat {
flow {
emit(usersToInsertInDB)
}
}
}
} else {
return@flatMapConcat flow {
emit(usersFromDb)
}
}
}
.flowOn(Dispatchers.Default)
.catch { e ->
users.postValue(Resource.error(e.toString(), null))
}
.collect {
users.postValue(Resource.success(it))
}
}
}
fun getUsers(): LiveData<Resource<List<User>>> {
return users
}
}
* **长时间运行的任务**:了解如何使用 Kotlin Flow 执行长时间运行的任务。如果您想使用 Kotlin Flow 在后台线程中执行任何任务,那么这很有用。
* 活动代码
package com.mindorks.kotlinFlow.learn.task.onetask
import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import com.mindorks.kotlinFlow.R import com.mindorks.kotlinFlow.data.api.ApiHelperImpl import com.mindorks.kotlinFlow.data.api.RetrofitBuilder import com.mindorks.kotlinFlow.data.local.DatabaseBuilder import com.mindorks.kotlinFlow.data.local.DatabaseHelperImpl import com.mindorks.kotlinFlow.utils.Status import com.mindorks.kotlinFlow.utils.ViewModelFactory import kotlinx.android.synthetic.main.activity_long_running_task.* import kotlinx.android.synthetic.main.activity_recycler_view.progressBar
class LongRunningTaskActivity : AppCompatActivity() {
private lateinit var viewModel: LongRunningTaskViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_long_running_task)
setupViewModel()
setupLongRunningTask()
}
private fun setupLongRunningTask() {
viewModel.getStatus().observe(this, Observer {
when (it.status) {
Status.SUCCESS -> {
progressBar.visibility = View.GONE
textView.text = it.data
textView.visibility = View.VISIBLE
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
textView.visibility = View.GONE
}
Status.ERROR -> {
//Handle Error
progressBar.visibility = View.GONE
Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
}
}
})
viewModel.startLongRunningTask()
}
private fun setupViewModel() {
viewModel = ViewModelProviders.of(
this,
ViewModelFactory(
ApiHelperImpl(RetrofitBuilder.apiService),
DatabaseHelperImpl(DatabaseBuilder.getInstance(applicationContext))
)
).get(LongRunningTaskViewModel::class.java)
}
}
* 视图模型代码
package com.mindorks.kotlinFlow.learn.task.onetask
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mindorks.kotlinFlow.data.api.ApiHelper import com.mindorks.kotlinFlow.data.local.DatabaseHelper import com.mindorks.kotlinFlow.utils.Resource import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch
class LongRunningTaskViewModel( private val apiHelper: ApiHelper, private val dbHelper: DatabaseHelper ) : ViewModel() {
private val status = MutableLiveData<Resource<String>>()
fun startLongRunningTask() {
viewModelScope.launch {
status.postValue(Resource.loading(null))
// do a long running task
doLongRunningTask()
.flowOn(Dispatchers.Default)
.catch {
status.postValue(Resource.error("Something Went Wrong", null))
}
.collect {
status.postValue(Resource.success("Task Completed"))
}
}
}
fun getStatus(): LiveData<Resource<String>> {
return status
}
private fun doLongRunningTask(): Flow<Int> {
return flow {
// your code for doing a long running task
// Added delay to simulate
delay(5000)
emit(0)
}
}
}
* **两个长时间运行的任务**:了解如何使用 Kotlin Flow 并行运行两个长时间运行的任务。
* 活动代码
package com.mindorks.kotlinFlow.learn.task.twotasks
import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import com.mindorks.kotlinFlow.R import com.mindorks.kotlinFlow.data.api.ApiHelperImpl import com.mindorks.kotlinFlow.data.api.RetrofitBuilder import com.mindorks.kotlinFlow.data.local.DatabaseBuilder import com.mindorks.kotlinFlow.data.local.DatabaseHelperImpl import com.mindorks.kotlinFlow.utils.Status import com.mindorks.kotlinFlow.utils.ViewModelFactory import kotlinx.android.synthetic.main.activity_long_running_task.* import kotlinx.android.synthetic.main.activity_recycler_view.progressBar
class TwoLongRunningTasksActivity : AppCompatActivity() {
private lateinit var viewModel: TwoLongRunningTasksViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_long_running_task)
setupViewModel()
setupLongRunningTask()
}
private fun setupLongRunningTask() {
viewModel.getStatus().observe(this, Observer {
when (it.status) {
Status.SUCCESS -> {
progressBar.visibility = View.GONE
textView.text = it.data
textView.visibility = View.VISIBLE
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
textView.visibility = View.GONE
}
Status.ERROR -> {
//Handle Error
progressBar.visibility = View.GONE
Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
}
}
})
viewModel.startLongRunningTask()
}
private fun setupViewModel() {
viewModel = ViewModelProviders.of(
this,
ViewModelFactory(
ApiHelperImpl(RetrofitBuilder.apiService),
DatabaseHelperImpl(DatabaseBuilder.getInstance(applicationContext))
)
).get(TwoLongRunningTasksViewModel::class.java)
}
}
* 视图模型代码
package com.mindorks.kotlinFlow.learn.task.twotasks
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mindorks.kotlinFlow.data.api.ApiHelper import com.mindorks.kotlinFlow.data.local.DatabaseHelper import com.mindorks.kotlinFlow.utils.Resource import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch
class TwoLongRunningTasksViewModel( private val apiHelper: ApiHelper, private val dbHelper: DatabaseHelper ) : ViewModel() {
private val status = MutableLiveData<Resource<String>>()
fun startLongRunningTask() {
viewModelScope.launch {
status.postValue(Resource.loading(null))
doLongRunningTaskOne()
.zip(doLongRunningTaskTwo()) { resultOne, resultTwo ->
return@zip resultOne + resultTwo
}
.flowOn(Dispatchers.Default)
.catch { e ->
status.postValue(Resource.error(e.toString(), null))
}
.collect {
status.postValue(Resource.success(it))
}
}
}
fun getStatus(): LiveData<Resource<String>> {
return status
}
private fun doLongRunningTaskTwo(): Flow<String> {
return flow {
// your code for doing a long running task
// Added delay to simulate
delay(5000)
emit("Two")
}
}
private fun doLongRunningTaskOne(): Flow<String> {
return flow {
// your code for doing a long running task
// Added delay to simulate
delay(5000)
emit("One")
}
}
}
* **Catch 错误处理**:了解如何使用 Catch 处理 Kotlin Flow 中的错误。
* 活动代码
package com.mindorks.kotlinFlow.learn.errorhandling.catch
import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.mindorks.kotlinFlow.R import com.mindorks.kotlinFlow.data.api.ApiHelperImpl import com.mindorks.kotlinFlow.data.api.RetrofitBuilder import com.mindorks.kotlinFlow.data.local.DatabaseBuilder import com.mindorks.kotlinFlow.data.local.DatabaseHelperImpl import com.mindorks.kotlinFlow.data.model.ApiUser import com.mindorks.kotlinFlow.learn.base.ApiUserAdapter import com.mindorks.kotlinFlow.utils.Status import com.mindorks.kotlinFlow.utils.ViewModelFactory import kotlinx.android.synthetic.main.activity_recycler_view.*
class CatchActivity : AppCompatActivity() {
private lateinit var viewModel: CatchViewModel
private lateinit var adapter: ApiUserAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recycler_view)
setupUI()
setupViewModel()
setupObserver()
}
private fun setupUI() {
recyclerView.layoutManager = LinearLayoutManager(this)
adapter =
ApiUserAdapter(
arrayListOf()
)
recyclerView.addItemDecoration(
DividerItemDecoration(
recyclerView.context,
(recyclerView.layoutManager as LinearLayoutManager).orientation
)
)
recyclerView.adapter = adapter
}
private fun setupObserver() {
viewModel.getUsers().observe(this, Observer {
when (it.status) {
Status.SUCCESS -> {
progressBar.visibility = View.GONE
it.data?.let { users -> renderList(users) }
recyclerView.visibility = View.VISIBLE
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
recyclerView.visibility = View.GONE
}
Status.ERROR -> {
//Handle Error
progressBar.visibility = View.GONE
Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
}
}
})
}
private fun renderList(users: List<ApiUser>) {
adapter.addData(users)
adapter.notifyDataSetChanged()
}
private fun setupViewModel() {
viewModel = ViewModelProviders.of(
this,
ViewModelFactory(
ApiHelperImpl(RetrofitBuilder.apiService),
DatabaseHelperImpl(DatabaseBuilder.getInstance(applicationContext))
)
).get(CatchViewModel::class.java)
}
}
* 视图模型代码
package com.mindorks.kotlinFlow.learn.errorhandling.catch
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mindorks.kotlinFlow.data.api.ApiHelper import com.mindorks.kotlinFlow.data.local.DatabaseHelper import com.mindorks.kotlinFlow.data.model.ApiUser import com.mindorks.kotlinFlow.utils.Resource import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch
class CatchViewModel( private val apiHelper: ApiHelper, private val dbHelper: DatabaseHelper ) : ViewModel() {
private val users = MutableLiveData<Resource<List<ApiUser>>>()
init {
fetchUsers()
}
private fun fetchUsers() {
viewModelScope.launch {
users.postValue(Resource.loading(null))
apiHelper.getUsersWithError()
.catch { e ->
users.postValue(Resource.error(e.toString(), null))
}
.collect {
users.postValue(Resource.success(it))
}
}
}
fun getUsers(): LiveData<Resource<List<ApiUser>>> {
return users
}
}
* **EmitAll 错误处理**:了解如何使用 emitAll 处理 Kotlin Flow 中的错误。
* 活动代码
package com.mindorks.kotlinFlow.learn.errorhandling.emitall
import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.mindorks.kotlinFlow.R import com.mindorks.kotlinFlow.data.api.ApiHelperImpl import com.mindorks.kotlinFlow.data.api.RetrofitBuilder import com.mindorks.kotlinFlow.data.local.DatabaseBuilder import com.mindorks.kotlinFlow.data.local.DatabaseHelperImpl import com.mindorks.kotlinFlow.data.model.ApiUser import com.mindorks.kotlinFlow.learn.base.ApiUserAdapter import com.mindorks.kotlinFlow.utils.Status import com.mindorks.kotlinFlow.utils.ViewModelFactory import kotlinx.android.synthetic.main.activity_recycler_view.*
class EmitAllActivity : AppCompatActivity() {
private lateinit var viewModel: EmitAllViewModel
private lateinit var adapter: ApiUserAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recycler_view)
setupUI()
setupViewModel()
setupObserver()
}
private fun setupUI() {
recyclerView.layoutManager = LinearLayoutManager(this)
adapter =
ApiUserAdapter(
arrayListOf()
)
recyclerView.addItemDecoration(
DividerItemDecoration(
recyclerView.context,
(recyclerView.layoutManager as LinearLayoutManager).orientation
)
)
recyclerView.adapter = adapter
}
private fun setupObserver() {
viewModel.getUsers().observe(this, Observer {
when (it.status) {
Status.SUCCESS -> {
progressBar.visibility = View.GONE
it.data?.let { users -> renderList(users) }
recyclerView.visibility = View.VISIBLE
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
recyclerView.visibility = View.GONE
}
Status.ERROR -> {
//Handle Error
progressBar.visibility = View.GONE
Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
}
}
})
}
private fun renderList(users: List<ApiUser>) {
adapter.addData(users)
adapter.notifyDataSetChanged()
}
private fun setupViewModel() {
viewModel = ViewModelProviders.of(
this,
ViewModelFactory(
ApiHelperImpl(RetrofitBuilder.apiService),
DatabaseHelperImpl(DatabaseBuilder.getInstance(applicationContext))
)
).get(EmitAllViewModel::class.java)
}
}
* 视图模型代码
package com.mindorks.kotlinFlow.learn.errorhandling.emitall
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mindorks.kotlinFlow.data.api.ApiHelper import com.mindorks.kotlinFlow.data.local.DatabaseHelper import com.mindorks.kotlinFlow.data.model.ApiUser import com.mindorks.kotlinFlow.utils.Resource import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch
class EmitAllViewModel( private val apiHelper: ApiHelper, private val dbHelper: DatabaseHelper ) : ViewModel() {
private val users = MutableLiveData<Resource<List<ApiUser>>>()
init {
fetchUsers()
}
private fun fetchUsers() {
viewModelScope.launch {
users.postValue(Resource.loading(null))
apiHelper.getUsers()
.zip(
apiHelper.getUsersWithError()
.catch { emitAll(flowOf(emptyList())) }) { usersFromApi, moreUsersFromApi ->
val allUsersFromApi = mutableListOf<ApiUser>()
allUsersFromApi.addAll(usersFromApi)
allUsersFromApi.addAll(moreUsersFromApi)
return@zip allUsersFromApi
}
.flowOn(Dispatchers.Default)
.catch { e ->
users.postValue(Resource.error(e.toString(), null))
}
.collect {
users.postValue(Resource.success(it))
}
}
}
fun getUsers(): LiveData<Resource<List<ApiUser>>> {
return users
}
}
* **完成:**
* 活动代码
package com.mindorks.kotlinFlow.learn.completion
import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import com.mindorks.kotlinFlow.R import com.mindorks.kotlinFlow.data.api.ApiHelperImpl import com.mindorks.kotlinFlow.data.api.RetrofitBuilder import com.mindorks.kotlinFlow.data.local.DatabaseBuilder import com.mindorks.kotlinFlow.data.local.DatabaseHelperImpl import com.mindorks.kotlinFlow.learn.base.ApiUserAdapter import com.mindorks.kotlinFlow.utils.Status import com.mindorks.kotlinFlow.utils.ViewModelFactory import kotlinx.android.synthetic.main.activity_long_running_task.* import kotlinx.android.synthetic.main.activity_recycler_view.progressBar
class CompletionActivity : AppCompatActivity() {
private lateinit var viewModel: CompletionViewModel
private lateinit var adapter: ApiUserAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_completion)
setupViewModel()
setupObserver()
}
private fun setupObserver() {
viewModel.getStatus().observe(this, Observer {
when (it.status) {
Status.SUCCESS -> {
progressBar.visibility = View.GONE
textView.text = it.data
textView.visibility = View.VISIBLE
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
textView.visibility = View.GONE
}
Status.ERROR -> {
//Handle Error
progressBar.visibility = View.GONE
Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
}
}
})
}
private fun setupViewModel() {
viewModel = ViewModelProviders.of(
this,
ViewModelFactory(
ApiHelperImpl(RetrofitBuilder.apiService),
DatabaseHelperImpl(DatabaseBuilder.getInstance(applicationContext))
)
).get(CompletionViewModel::class.java)
}
}
* 视图模型代码
package com.mindorks.kotlinFlow.learn.completion
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mindorks.kotlinFlow.data.api.ApiHelper import com.mindorks.kotlinFlow.data.local.DatabaseHelper import com.mindorks.kotlinFlow.utils.Resource import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.launch
class CompletionViewModel( private val apiHelper: ApiHelper, private val dbHelper: DatabaseHelper ) : ViewModel() {
private val status = MutableLiveData<Resource<String>>()
init{
fetchUsers()
}
private fun fetchUsers() {
viewModelScope.launch {
status.postValue(Resource.loading(null))
apiHelper.getUsers()
.catch { e ->
status.postValue(Resource.error(e.toString(), null))
}
.onCompletion {
status.postValue(Resource.success("Task Completed"))
}
.collect {
}
}
}
fun getStatus(): LiveData<Resource<String>> {
return status
}
}
* **减少:**
* 活动代码
package com.mindorks.kotlinFlow.learn.reduce
import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import com.mindorks.kotlinFlow.R import com.mindorks.kotlinFlow.data.api.ApiHelperImpl import com.mindorks.kotlinFlow.data.api.RetrofitBuilder import com.mindorks.kotlinFlow.data.local.DatabaseBuilder import com.mindorks.kotlinFlow.data.local.DatabaseHelperImpl import com.mindorks.kotlinFlow.utils.Status import com.mindorks.kotlinFlow.utils.ViewModelFactory import kotlinx.android.synthetic.main.activity_long_running_task.*
class ReduceActivity : AppCompatActivity() {
private lateinit var viewModel: ReduceViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_long_running_task)
setupViewModel()
setupLongRunningTask()
}
private fun setupLongRunningTask() {
viewModel.getStatus().observe(this, Observer {
when (it.status) {
Status.SUCCESS -> {
progressBar.visibility = View.GONE
textView.text = it.data
textView.visibility = View.VISIBLE
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
textView.visibility = View.GONE
}
Status.ERROR -> {
//Handle Error
progressBar.visibility = View.GONE
Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
}
}
})
viewModel.startReduceTask()
}
private fun setupViewModel() {
viewModel = ViewModelProviders.of(
this,
ViewModelFactory(
ApiHelperImpl(RetrofitBuilder.apiService),
DatabaseHelperImpl(DatabaseBuilder.getInstance(applicationContext))
)
).get(ReduceViewModel::class.java)
}
}
* 视图模型代码
package com.mindorks.kotlinFlow.learn.reduce
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mindorks.kotlinFlow.data.api.ApiHelper import com.mindorks.kotlinFlow.data.local.DatabaseHelper import com.mindorks.kotlinFlow.utils.Resource import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.reduce import kotlinx.coroutines.launch
class ReduceViewModel( val apiHelper: ApiHelper, dbHelper: DatabaseHelper ) : ViewModel() {
private val status = MutableLiveData<Resource<String>>()
fun startReduceTask() {
viewModelScope.launch {
status.postValue(Resource.loading(null))
val result = (1..5).asFlow()
.reduce { a, b -> a + b }
status.postValue(Resource.success(result.toString()))
}
}
fun getStatus(): LiveData<Resource<String>> {
return status
}
}
* **地图:**
* 活动代码
package com.mindorks.kotlinFlow.learn.map
import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.mindorks.kotlinFlow.R import com.mindorks.kotlinFlow.data.api.ApiHelperImpl import com.mindorks.kotlinFlow.data.api.RetrofitBuilder import com.mindorks.kotlinFlow.data.local.DatabaseBuilder import com.mindorks.kotlinFlow.data.local.DatabaseHelperImpl import com.mindorks.kotlinFlow.data.local.entity.User import com.mindorks.kotlinFlow.learn.base.UserAdapter import com.mindorks.kotlinFlow.utils.Status import com.mindorks.kotlinFlow.utils.ViewModelFactory import kotlinx.android.synthetic.main.activity_recycler_view.*
class MapActivity : AppCompatActivity() {
private lateinit var viewModel: MapViewModel
private lateinit var adapter: UserAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recycler_view)
setupUI()
setupViewModel()
setupObserver()
}
private fun setupUI() {
recyclerView.layoutManager = LinearLayoutManager(this)
adapter =
UserAdapter(
arrayListOf()
)
recyclerView.addItemDecoration(
DividerItemDecoration(
recyclerView.context,
(recyclerView.layoutManager as LinearLayoutManager).orientation
)
)
recyclerView.adapter = adapter
}
private fun setupObserver() {
viewModel.getUsers().observe(this, Observer {
when (it.status) {
Status.SUCCESS -> {
progressBar.visibility = View.GONE
it.data?.let { users -> renderList(users) }
recyclerView.visibility = View.VISIBLE
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
recyclerView.visibility = View.GONE
}
Status.ERROR -> {
//Handle Error
progressBar.visibility = View.GONE
Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
}
}
})
}
private fun renderList(users: List<User>) {
adapter.addData(users)
adapter.notifyDataSetChanged()
}
private fun setupViewModel() {
viewModel = ViewModelProviders.of(
this,
ViewModelFactory(
ApiHelperImpl(RetrofitBuilder.apiService),
DatabaseHelperImpl(DatabaseBuilder.getInstance(applicationContext))
)
).get(MapViewModel::class.java)
}
}
* 视图模型代码
package com.mindorks.kotlinFlow.learn.map
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mindorks.kotlinFlow.data.api.ApiHelper import com.mindorks.kotlinFlow.data.local.DatabaseHelper import com.mindorks.kotlinFlow.data.local.entity.User import com.mindorks.kotlinFlow.utils.Resource import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch
class MapViewModel( val apiHelper: ApiHelper, dbHelper: DatabaseHelper ) : ViewModel() {
private val users = MutableLiveData<Resource<List<User>>>()
init {
fetchUsers()
}
private fun fetchUsers() {
viewModelScope.launch {
users.postValue(Resource.loading(null))
apiHelper.getUsers()
.map { apiUserList ->
val userList = mutableListOf<User>()
for (apiUser in apiUserList) {
val user = User(
apiUser.id,
apiUser.name,
apiUser.email,
apiUser.avatar
)
userList.add(user)
}
userList
}
.catch { e ->
users.postValue(Resource.error(e.toString(), null))
}
.collect {
users.postValue(Resource.success(it))
}
}
}
fun getUsers(): LiveData<Resource<List<User>>> {
return users
}
}
* **筛选:**
* 活动代码
package com.mindorks.kotlinFlow.learn.filter
import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import com.mindorks.kotlinFlow.R import com.mindorks.kotlinFlow.data.api.ApiHelperImpl import com.mindorks.kotlinFlow.data.api.RetrofitBuilder import com.mindorks.kotlinFlow.data.local.DatabaseBuilder import com.mindorks.kotlinFlow.data.local.DatabaseHelperImpl import com.mindorks.kotlinFlow.utils.Status import com.mindorks.kotlinFlow.utils.ViewModelFactory import kotlinx.android.synthetic.main.activity_long_running_task.* import kotlinx.android.synthetic.main.activity_recycler_view.progressBar
class FilterActivity : AppCompatActivity() {
private lateinit var viewModel: FilterViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_long_running_task)
setupViewModel()
setupLongRunningTask()
}
private fun setupLongRunningTask() {
viewModel.getStatus().observe(this, Observer {
when (it.status) {
Status.SUCCESS -> {
progressBar.visibility = View.GONE
textView.text = it.data
textView.visibility = View.VISIBLE
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
textView.visibility = View.GONE
}
Status.ERROR -> {
//Handle Error
progressBar.visibility = View.GONE
Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
}
}
})
viewModel.startFilterTask()
}
private fun setupViewModel() {
viewModel = ViewModelProviders.of(
this,
ViewModelFactory(
ApiHelperImpl(RetrofitBuilder.apiService),
DatabaseHelperImpl(DatabaseBuilder.getInstance(applicationContext))
)
).get(FilterViewModel::class.java)
}
}
* 视图模型代码
package com.mindorks.kotlinFlow.learn.filter
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mindorks.kotlinFlow.data.api.ApiHelper import com.mindorks.kotlinFlow.data.local.DatabaseHelper import com.mindorks.kotlinFlow.utils.Resource import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.toList import kotlinx.coroutines.launch
class FilterViewModel( apiHelper: ApiHelper, dbHelper: DatabaseHelper ) : ViewModel() { private val status = MutableLiveData<Resource>()
fun startFilterTask() {
viewModelScope.launch {
status.postValue(Resource.loading(null))
val result = mutableListOf<Int>()
(1..5).asFlow()
.filter {
it % 2 == 0
}
.toList(result)
status.postValue(Resource.success(result.toString()))
}
}
fun getStatus(): LiveData<Resource<String>> {
return status
}
}
* **搜索功能**:使用 Kotlin Flow Operators 实现搜索 - Debounce、Filter、DistinctUntilChanged、FlatMapLatest。
+ 活动代码
package com.mindorks.kotlinFlow.learn.search
import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.mindorks.kotlinFlow.R import com.mindorks.kotlinFlow.utils.getQueryTextChangeStateFlow import kotlinx.android.synthetic.main.activity_search.* import kotlinx.coroutines.* import kotlinx.coroutines.flow.* import kotlin.coroutines.CoroutineContext
class SearchActivity : AppCompatActivity(), CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
private lateinit var job: Job
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_search)
job = Job()
setUpSearchStateFlow()
}
override fun onDestroy() {
job.cancel()
super.onDestroy()
}
private fun setUpSearchStateFlow() {
launch {
searchView.getQueryTextChangeStateFlow()
.debounce(300)
.filter { query ->
if (query.isEmpty()) {
textViewResult.text = ""
return@filter false
} else {
return@filter true
}
}
.distinctUntilChanged()
.flatMapLatest { query ->
dataFromNetwork(query)
.catch {
emitAll(flowOf(""))
}
}
.flowOn(Dispatchers.Default)
.collect { result ->
textViewResult.text = result
}
}
}
/**
* Simulation of network data
*/
private fun dataFromNetwork(query: String): Flow<String> {
return flow {
delay(2000)
emit(query)
}
}
}
* **重试:**
* 活动代码
package com.mindorks.kotlinFlow.learn.retry
import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import com.mindorks.kotlinFlow.R import com.mindorks.kotlinFlow.data.api.ApiHelperImpl import com.mindorks.kotlinFlow.data.api.RetrofitBuilder import com.mindorks.kotlinFlow.data.local.DatabaseBuilder import com.mindorks.kotlinFlow.data.local.DatabaseHelperImpl import com.mindorks.kotlinFlow.utils.Status import com.mindorks.kotlinFlow.utils.ViewModelFactory import kotlinx.android.synthetic.main.activity_retry.*
class RetryActivity : AppCompatActivity() {
private lateinit var viewModel: RetryViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_retry)
setupViewModel()
setupLongRunningTask()
}
private fun setupLongRunningTask() {
viewModel.getStatus().observe(this, Observer {
when (it.status) {
Status.SUCCESS -> {
progressBar.visibility = View.GONE
textView.text = it.data
textView.visibility = View.VISIBLE
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
textView.visibility = View.GONE
}
Status.ERROR -> {
//Handle Error
progressBar.visibility = View.GONE
Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
}
}
})
viewModel.startTask()
}
private fun setupViewModel() {
viewModel = ViewModelProviders.of(
this,
ViewModelFactory(
ApiHelperImpl(RetrofitBuilder.apiService),
DatabaseHelperImpl(DatabaseBuilder.getInstance(applicationContext))
)
).get(RetryViewModel::class.java)
}
}
* 视图模型代码
package com.mindorks.kotlinFlow.learn.retry
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mindorks.kotlinFlow.data.api.ApiHelper import com.mindorks.kotlinFlow.data.local.DatabaseHelper import com.mindorks.kotlinFlow.utils.Resource import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import java.io.IOException
class RetryViewModel( val apiHelper: ApiHelper, dbHelper: DatabaseHelper ) : ViewModel() {
private val status = MutableLiveData<Resource<String>>()
fun startTask() {
viewModelScope.launch {
status.postValue(Resource.loading(null))
// do a long running task
doLongRunningTask()
.flowOn(Dispatchers.Default)
.retry(retries = 3) { cause ->
if (cause is IOException) {
delay(2000)
return@retry true
} else {
return@retry false
}
}
.catch {
status.postValue(Resource.error("Something Went Wrong", null))
}
.collect {
status.postValue(Resource.success("Task Completed"))
}
}
}
fun getStatus(): LiveData<Resource<String>> {
return status
}
private fun doLongRunningTask(): Flow<Int> {
return flow {
// your code for doing a long running task
// Added delay, random number, and exception to simulate
delay(2000)
val randomNumber = (0..2).random()
if (randomNumber == 0) {
throw IOException()
} else if (randomNumber == 1) {
throw IndexOutOfBoundsException()
}
delay(2000)
emit(0)
}
}
}
* **重试时间:**
* 活动代码
package com.mindorks.kotlinFlow.learn.retrywhen
import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import com.mindorks.kotlinFlow.R import com.mindorks.kotlinFlow.data.api.ApiHelperImpl import com.mindorks.kotlinFlow.data.api.RetrofitBuilder import com.mindorks.kotlinFlow.data.local.DatabaseBuilder import com.mindorks.kotlinFlow.data.local.DatabaseHelperImpl import com.mindorks.kotlinFlow.utils.Status import com.mindorks.kotlinFlow.utils.ViewModelFactory import kotlinx.android.synthetic.main.activity_retry.*
class RetryWhenActivity : AppCompatActivity() {
private lateinit var viewModel: RetryWhenViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_retry)
setupViewModel()
setupLongRunningTask()
}
private fun setupLongRunningTask() {
viewModel.getStatus().observe(this, Observer {
when (it.status) {
Status.SUCCESS -> {
progressBar.visibility = View.GONE
textView.text = it.data
textView.visibility = View.VISIBLE
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
textView.visibility = View.GONE
}
Status.ERROR -> {
//Handle Error
progressBar.visibility = View.GONE
Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
}
}
})
viewModel.startTask()
}
private fun setupViewModel() {
viewModel = ViewModelProviders.of(
this,
ViewModelFactory(
ApiHelperImpl(RetrofitBuilder.apiService),
DatabaseHelperImpl(DatabaseBuilder.getInstance(applicationContext))
)
).get(RetryWhenViewModel::class.java)
}
}
* 视图模型代码
package com.mindorks.kotlinFlow.learn.retrywhen
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mindorks.kotlinFlow.data.api.ApiHelper import com.mindorks.kotlinFlow.data.local.DatabaseHelper import com.mindorks.kotlinFlow.utils.Resource import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import java.io.IOException
class RetryWhenViewModel( val apiHelper: ApiHelper, dbHelper: DatabaseHelper ) : ViewModel() {
private val status = MutableLiveData<Resource<String>>()
fun startTask() {
viewModelScope.launch {
status.postValue(Resource.loading(null))
// do a long running task
doLongRunningTask()
.flowOn(Dispatchers.Default)
.retryWhen { cause, attempt ->
if (cause is IOException && attempt < 3) {
delay(2000)
return@retryWhen true
} else {
return@retryWhen false
}
}
.catch {
status.postValue(Resource.error("Something Went Wrong", null))
}
.collect {
status.postValue(Resource.success("Task Completed"))
}
}
}
fun getStatus(): LiveData<Resource<String>> {
return status
}
private fun doLongRunningTask(): Flow<Int> {
return flow {
// your code for doing a long running task
// Added delay, random number, and exception to simulate
delay(2000)
val randomNumber = (0..2).random()
if (randomNumber == 0) {
throw IOException()
} else if (randomNumber == 1) {
throw IndexOutOfBoundsException()
}
delay(2000)
emit(0)
}
}
}
* **使用指数退避重试:**
* 活动代码
package com.mindorks.kotlinFlow.learn.retryexponentialbackoff
import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import com.mindorks.kotlinFlow.R import com.mindorks.kotlinFlow.data.api.ApiHelperImpl import com.mindorks.kotlinFlow.data.api.RetrofitBuilder import com.mindorks.kotlinFlow.data.local.DatabaseBuilder import com.mindorks.kotlinFlow.data.local.DatabaseHelperImpl import com.mindorks.kotlinFlow.utils.Status import com.mindorks.kotlinFlow.utils.ViewModelFactory import kotlinx.android.synthetic.main.activity_retry.*
class RetryExponentialBackoffActivity : AppCompatActivity() {
private lateinit var viewModel: RetryExponentialBackoffModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_retry)
setupViewModel()
setupLongRunningTask()
}
private fun setupLongRunningTask() {
viewModel.getStatus().observe(this, Observer {
when (it.status) {
Status.SUCCESS -> {
progressBar.visibility = View.GONE
textView.text = it.data
textView.visibility = View.VISIBLE
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
textView.visibility = View.GONE
}
Status.ERROR -> {
//Handle Error
progressBar.visibility = View.GONE
Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
}
}
})
viewModel.startTask()
}
private fun setupViewModel() {
viewModel = ViewModelProviders.of(
this,
ViewModelFactory(
ApiHelperImpl(RetrofitBuilder.apiService),
DatabaseHelperImpl(DatabaseBuilder.getInstance(applicationContext))
)
).get(RetryExponentialBackoffModel::class.java)
}
}
* 视图模型代码
package com.mindorks.kotlinFlow.learn.retryexponentialbackoff