王学岗协程(七)————Flow与Room应用

看下应用效果在这里插入图片描述
点击addUser,就增加一条数据,同步到下面的RecyclerView。

界面很简单,没什么可讲的

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="5dip">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <EditText
                android:id="@+id/et_user_id"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:hint="USER ID"/>

            <EditText
                android:id="@+id/et_first_name"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:hint="FIRST NAME"/>

            <EditText
                android:id="@+id/et_last_name"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:hint="LAST NAME"/>

        </LinearLayout>

        <Button
            android:id="@+id/btn_add_user"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="ADD USER"/>
    </LinearLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
</LinearLayout>

上面三个输入框,中间一个按钮,下面一个RecyclerView
看下AppDatabase

package com.dongnaoedu.flowpractice.db

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import kotlin.coroutines.Continuation

/**
 *
 * @author ningchuanqi
 * @version V1.0
 */
@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao

    companion object {

        private var instance: AppDatabase? = null

        fun getInstance(context: Context): AppDatabase {
            return instance ?: synchronized(this) {
                Room.databaseBuilder(context, AppDatabase::class.java, "flow_practice.db")
                    .build().also { instance = it }
            }
        }

    }
}

user实体

package com.dongnaoedu.flowpractice.db

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

/**
 *
 * @author ningchuanqi
 * @version V1.0
 */
@Entity
data class User(
    @PrimaryKey val uid: Int,
    @ColumnInfo(name = "first_name") val firstName: String,
    @ColumnInfo(name = "last_name") val lastName: String
)

Dao类

package com.dongnaoedu.flowpractice.db

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import kotlinx.coroutines.flow.Flow

/**
 *
 * @author ningchuanqi
 * @version V1.0
 */
@Dao
interface UserDao {
     //冲突策略,ID相同替换
     //插入需要关键字suspend,以支持协程
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(user: User)
//查询所有用户,返回一个Flow,查询函数不需要加suspend 
//如果是返回livedata,也不需要suspend 
    @Query("SELECT * FROM user")
    fun getAll(): Flow<List<User>>

}

通过ViewModel访问数据库

package com.dongnaoedu.flowpractice.viewmodel

import android.app.Application
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.dongnaoedu.flowpractice.db.AppDatabase
import com.dongnaoedu.flowpractice.db.User
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch

/**
   继承AndroidViewModel,可以拿到上下文。
 */
class UserViewModel(app: Application) : AndroidViewModel(app) {


    fun insert(uid: String, firstName: String, lastName: String) {
        viewModelScope.launch {
            //insert是个挂起函数,要在协程里执行
            AppDatabase.getInstance(getApplication())
                .userDao()
                .insert(User(uid.toInt(), firstName, lastName))
            Log.d("ning", "insert user:$uid")
        }
    }


    fun getAll(): Flow<List<User>> {
        return AppDatabase.getInstance(getApplication())
            .userDao()
            .getAll()
                //捕捉异常
            .catch { e -> e.printStackTrace() }
                //指定调度器,在IO调度器上查询
            .flowOn(Dispatchers.IO)
    }

}

看下Fragment界面,首先创建RecyclerView的是配置

package com.dongnaoedu.flowpractice.adapter

import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.dongnaoedu.flowpractice.databinding.ItemUserBinding
import com.dongnaoedu.flowpractice.db.User

/**
 *
 * @author ningchuanqi
 * @version V1.0
 */
class UserAdapter(private val context: Context) : RecyclerView.Adapter<BindingViewHolder>() {

    private val data = ArrayList<User>()

    fun setData(data: List<User>) {
        this.data.clear()
        this.data.addAll(data)
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingViewHolder {
    //ItemUserBinding自动生成的
        val binding = ItemUserBinding.inflate(LayoutInflater.from(context), parent, false)
        return BindingViewHolder(binding)
    }

    override fun onBindViewHolder(holder: BindingViewHolder, position: Int) {
    //取出数据
        val item = data[position]
        val binding = holder.binding as ItemUserBinding
        binding.text.text = "${item.uid}, ${item.firstName}, ${item.lastName}"
    }

    override fun getItemCount() = data.size
}
package com.dongnaoedu.flowpractice.adapter

import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding

/**
 *
 * @author ningchuanqi
 * @version V1.0
 */
class BindingViewHolder(val binding: ViewBinding) : RecyclerView.ViewHolder(binding.root) {
}

看下Fragment

package com.dongnaoedu.flowpractice.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import com.dongnaoedu.flowpractice.R
import com.dongnaoedu.flowpractice.adapter.UserAdapter
import com.dongnaoedu.flowpractice.databinding.FragmentDownloadBinding
import com.dongnaoedu.flowpractice.databinding.FragmentUserBinding
import com.dongnaoedu.flowpractice.viewmodel.UserViewModel
import kotlinx.coroutines.flow.collect

class UserFragment : Fragment() {
    //拿到ViewModel
    private val viewModel by viewModels<UserViewModel>()

    private val mBinding: FragmentUserBinding by lazy {
        FragmentUserBinding.inflate(layoutInflater)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return mBinding.root
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        mBinding.apply {
            btnAddUser.setOnClickListener {
                viewModel.insert(
                    etUserId.text.toString(),
                    etFirstName.text.toString(),
                    etLastName.text.toString()
                )
            }
        }
          //UserAdapter传入的context可空,使用空安全操作符+let
        context?.let {
            val adapter = UserAdapter(it)
            mBinding.recyclerView.adapter = adapter
            //起一个协程,从flow里收集元素
            lifecycleScope.launchWhenCreated {
                viewModel.getAll().collect { value ->
                    adapter.setData(value)//数据给到适配器,刷新视图
                }
            }
        }

    }


}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值