这是小项目的样子,主界面是一个recyclerView从room取出的所有数据并使用livedata观察,左边floatiingButton点击清除room数据库,右边floatingButton点击进入存储数据界面insert表。
db
room数据库所有操作
WordRoomDatabase
1、创建abstract WordRoomDatabase继承RoomDatabase,create abstract fun wordDao()
2、dcl单例wordRoomDatabase instance by fun getDatabase
3、addCallback(),wordDatabaseCallback override fun onCreate use coroutine function launch()对room init。deleteAll() insert() insert()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| @Database(entities = arrayOf(Word::class), version = 1, exportSchema = false) abstract class WordRoomDatabase : RoomDatabase() { abstract fun wordDao(): WordDao
companion object { @Volatile private var INSTANCE: WordRoomDatabase? = null fun getDatabase(context: Context, scope: CoroutineScope): WordRoomDatabase { return INSTANCE ?: synchronized(this) { val instance = Room.databaseBuilder( context.applicationContext, WordRoomDatabase::class.java, "word_database" ).addCallback(WordDatabaseCallback(scope)).build() INSTANCE = instance instance } } }
private class WordDatabaseCallback(private val scope: CoroutineScope) : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) { super.onCreate(db) INSTANCE?.let { wordRoomDatabase -> scope.launch { populateDatabase(wordRoomDatabase.wordDao()) } } }
suspend fun populateDatabase(wordDao: WordDao) { wordDao.deleteAll() wordDao.insert(Word("BE BRAVE DI")) wordDao.insert(Word("DO NOT GIVEUP")) } } }
|
Word
word表。tableName 设置表名称,ColumnInfo设置每一列名称,在这里只有word和autoGenerate id
1 2 3 4 5 6 7 8
| @Entity(tableName = "work_table") data class Word( @ColumnInfo(name = "word") var word: String = "" ) { @PrimaryKey(autoGenerate = true) var id: Int = 0 }
|
WordDao
对word表进行的sql操作。
1 2 3 4 5 6 7 8 9 10 11 12
| @Dao interface WordDao {
@Query("SELECT * FROM work_table ORDER BY word ASC") fun getAlphabetizedWords() :Flow<List<Word>>
@Insert(onConflict = OnConflictStrategy.IGNORE) suspend fun insert(word: Word)
@Query("DELETE FROM work_table") suspend fun deleteAll() }
|
repo
WordRepository是对db和net进行的统一管理,调用wordDao.function
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class WordRepository(private val wordDao: WordDao) { val allWords: Flow<List<Word>> = wordDao.getAlphabetizedWords()
@Suppress("RedundantSuspendModifier") @WorkerThread suspend fun insert(word: Word){ wordDao.insert(word) }
@WorkerThread suspend fun deleteAll(){ wordDao.deleteAll() } }
|
viewmodel
viewmodel对activity界面数据保存
WordViewModelFactory
Return WordViewModel(repository) as T
1 2 3 4 5 6 7 8 9
| class WordViewModelFactory(private val repository: WordRepository) : ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T { if (modelClass.isAssignableFrom(WordViewModel::class.java)){ @Suppress("UNCHECK_CAST") return WordViewModel(repository) as T } throw IllegalArgumentException("Unknown ViewModel class") } }
|
WordViewModel
allWords()使用Flow.asLiveData
Insert()使用协程viewmodelscope.launch()
deleteAdd()同上
1 2 3 4 5 6 7 8 9 10 11 12
| class WordViewModel(private var repository: WordRepository) : ViewModel() {
val allWords:LiveData<List<Word>> = repository.allWords.asLiveData()
fun insert(word: Word) = viewModelScope.launch { repository.insert(word) }
fun deleteAdd() = viewModelScope.launch { repository.deleteAll() } }
|
adapter
WordListAdapter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| class WordListAdapter : ListAdapter<Word, WordListAdapter.WordViewHolder>(WordsComparator()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WordViewHolder { return WordViewHolder.create(parent) }
override fun onBindViewHolder(holder: WordViewHolder, position: Int) { val current = getItem(position) holder.bind(current.word) }
class WordViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private val wordItemView: TextView = itemView.findViewById(R.id.textView) private val wordItemContent: ConstraintLayout = itemView.findViewById(R.id.recyclerviewcontent) fun bind(text: String?) { wordItemView.text = text val colorArr = arrayOf(Color.WHITE, Color.YELLOW, Color.GREEN, Color.RED) wordItemContent.setBackgroundColor(colorArr[Random.nextInt(colorArr.size)]) }
companion object { fun create(parent: ViewGroup): WordViewHolder { val view: View = LayoutInflater.from(parent.context) .inflate(R.layout.recyclerview_item, parent, false) return WordViewHolder(view) } } }
class WordsComparator : DiffUtil.ItemCallback<Word>() { override fun areItemsTheSame(oldItem: Word, newItem: Word): Boolean { return oldItem === newItem }
override fun areContentsTheSame(oldItem: Word, newItem: Word): Boolean { return oldItem.word == newItem.word }
} }
|
Activity and application
WordsApplication
By lazy调用到在初始化
Init function: WordRoomDatabase.getDatabase(this,scope), WordRepository(database.wordDao)
1 2 3 4 5
| class WordsApplication : Application() { val applicationScope = CoroutineScope(SupervisorJob()) val database by lazy { WordRoomDatabase.getDatabase(this, scope = applicationScope) } val repository by lazy { WordRepository(database.wordDao()) } }
|
NewWordActivity
存储word表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class NewWordActivity : AppCompatActivity() { private lateinit var binding:ActivityNewWordBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityNewWordBinding.inflate(layoutInflater) setContentView(binding.root) binding.buttonSave.setOnClickListener { val replyIntent = Intent() if (TextUtils.isEmpty(binding.editWord.text)){ setResult(Activity.RESULT_CANCELED, replyIntent) } else { Log.d("DI", binding.editWord.text.toString()) replyIntent.putExtra(EXTRA_REPLY, binding.editWord.text.toString()) setResult(Activity.RESULT_OK, replyIntent) } finish() } }
companion object{ const val EXTRA_REPLY = "com.example.android.wordlistsqp.REPLY" } }
|
MainActivity
first —> viewModel. ‘’Viewmodel include liveData scope’’
Second —> livedata.observe() 数据变化则adapter跟着变化.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding private val newWOrdActivityRequestCode = 1 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) var adapter = WordListAdapter() binding.recyclerview.adapter = adapter binding.recyclerview.layoutManager = LinearLayoutManager(this) wordViewModel.allWords.observe(this, Observer { wordViewModel -> wordViewModel?.let { adapter.submitList(it) } }) binding.floatingActionButton.setOnClickListener{ val intent = Intent(this, NewWordActivity::class.java) startActivityForResult(intent, newWOrdActivityRequestCode) } binding.clear.setOnClickListener{ wordViewModel.deleteAdd() } }
private val wordViewModel: WordViewModel by viewModels { WordViewModelFactory((application as WordsApplication).repository) }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == newWOrdActivityRequestCode && resultCode == Activity.RESULT_OK) { data?.getStringExtra(NewWordActivity.EXTRA_REPLY)?.let { wordViewModel.insert(Word(it)) } } else { Snackbar.make(binding.content, "没有数据返回哦", Snackbar.LENGTH_LONG).show() } } }
|