Lifecycle
- 添加依赖
def lifecycle_version = "2.2.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
- 管理fragment和activity的生命周期
OnLifecycleEvent注解表示监听哪个生命周期 - 使用
class LifecycleObserver : LifecycleObserver {
private val TAG = LifecycleObserver::class.simpleName
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun create() {
Log.e(TAG, "LifecycleObserver->onCreate")
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun start(){
Log.e(TAG, "LifecycleObserver->onStart")
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun resume(){
Log.e(TAG, "LifecycleObserver->onResume")
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stop(){
Log.e(TAG, "LifecycleObserver->onStop")
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun destory(){
Log.e(TAG, "LifecycleObserver->onDestory")
}
}
activity中使用
class MainActivity : AppCompatActivity(){
protected override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val observer=LifecycleObserver()
lifecycle.addObserver(observer)
}
}
使用很简单,实际就是用一个类统一管理了activity或者fragment的生命周期
ViewModel
- ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据
- 使用
class MainViewModel : ViewModel() {
var number = 0
}
activity的代码
lateinit var mainViewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainViewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
value.text= mainViewModel.number.toString()
button1.setOnClickListener {
mainViewModel.number++
value.text = mainViewModel.number.toString()
}
button2.setOnClickListener{
mainViewModel.number--
value.text = mainViewModel.number.toString()
}
}
布局
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="0"
android:textSize="18sp" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:text="加" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:text="减" />
</LinearLayout>
LiveData
- 在底层数据库更改时通知视图(实际是观察者和被观察者)
- 使用
class MainViewModel : ViewModel() {
private var numbers: MutableLiveData<Int>? = null
fun getNumber(): MutableLiveData<Int>? {
if (numbers == null) {
numbers = MutableLiveData()
numbers!!.value = 0
}
return numbers
}
fun addNumber(data: Int) {
numbers?.value = numbers?.value?.plus(data)
}
}
lateinit var mainViewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainViewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
mainViewModel.getNumber()?.observe(this, Observer {
value.text = it.toString()
})
button1.setOnClickListener {
mainViewModel.addNumber(1)
}
button2.setOnClickListener {
mainViewModel.addNumber(-1)
}
}
DataBinding
需要在build.gradle中的 defaultConfig添加以下代码
dataBinding {
enabled true
}
修改布局
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="data"
type="com.peakmain.jetpack.MainViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@{String.valueOf(data.number)}"
android:textSize="18sp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:onClick="@{()->data.addNumber(1)}"
android:text="加" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:onClick="@{()->data.addNumber(-1)}"
android:text="减" />
</LinearLayout>
</layout>
MainViewModel管理界面中的数据
class MainViewModel : ViewModel() {
private var number: MutableLiveData<Int>? = null
fun getNumber(): MutableLiveData<Int> {
if (number == null) {
number = MutableLiveData()
number!!.value = 0
}
return number!!
}
fun addNumber(data: Int) {
number!!.value = number!!.value!! + data
}
}
activity的使用
lateinit var binding: ActivityMainBinding
private lateinit var mainViewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
mainViewModel=ViewModelProviders.of(this).get(MainViewModel::class.java)//创建mainViewModel
binding.data = mainViewModel
binding.lifecycleOwner = this
}
ViewModelSavedState
即使进程在后台被系统杀死数据也存活
修改MainViewModel
class MainViewModel(state: SavedStateHandle) : ViewModel() {
private val handle: SavedStateHandle = state
companion object {
const val KEY_NUMBER = "key_number"
}
fun getNumber(): MutableLiveData<Int> {
if (!handle.contains(KEY_NUMBER)) {
handle.set(KEY_NUMBER, 0)
}
return handle.getLiveData(KEY_NUMBER)
}
fun addNumber(data: Int) {
getNumber().value = getNumber().value!!.plus(data)
}
}
activity中修改mainViewModel
mainViewModel = ViewModelProvider(this, SavedStateViewModelFactory(this.application, this)).get(MainViewModel::class.java)
AndroidViewModel
方便传context
修改mainViewModel
class MainViewModel(application: Application,state: SavedStateHandle) : AndroidViewModel(application) {
private val handle: SavedStateHandle = state
private val context: Application = application
companion object {
const val KEY_NUMBER = "key_number"
}
fun getNumber(): MutableLiveData<Int> {
if (!handle.contains(KEY_NUMBER)) {
handle.set(KEY_NUMBER, 0)
}
return handle.getLiveData(KEY_NUMBER)
}
fun addNumber(data: Int) {
getNumber().value = getNumber().value!!.plus(data)
}
fun startActivity() {
val intent=Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(intent)
}
}
Room
- 持久性库在 SQLite 的基础上提供了一个抽象层
- 添加依赖
apply plugin: 'kotlin-kapt'
def room_version = "2.2.5"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor
// optional - Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:$room_version"
// Test helpers
testImplementation "androidx.room:room-testing:$room_version"
Entity、Dao、Database
使用 @Database
注释的类应满足以下条件:
- 是扩展
RoomDatabase
的抽象类。 - 在注释中添加与数据库关联的实体列表。
- 包含具有 0 个参数且返回使用
@Dao
注释的类的抽象方法。
Entity表示数据库中的表,Dao包含用于访问数据库的方法
@Entity
class Word() {
@PrimaryKey(autoGenerate = true)
var id: Int = 0
@ColumnInfo(name = "english_word")
var word: String = ""
@ColumnInfo(name = "chinese_mean")
var chineseMean: String = ""
constructor(word: String, chineseMean: String) : this() {
this.word = word
this.chineseMean=chineseMean
}
}
- Dao包含用于访问数据库的方法
@Dao
interface WordDao {
@Insert
fun insertWord(vararg words: Word?)
@Update
fun updateWord(vararg words: Word?)
@Delete
fun deleteWord(vararg words: Word?)
@Query("DELETE FROM WORD")
fun deleteAllWords()
@Query("SELECT *FROM WORD ORDER BY ID DESC ")
fun getAllWords():List<Word>
}
- Database
@Database(entities = [Word::class], version = 1, exportSchema = false)
abstract class WordDatabase : RoomDatabase() {
abstract fun getWordDao(): WordDao
}
activity的使用
class MainActivity : AppCompatActivity() {
lateinit var wordDatabase: WordDatabase
lateinit var wordDao: WordDao
lateinit var binding: ActivityMainBinding
private lateinit var mainViewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
mainViewModel = ViewModelProvider(this, SavedStateViewModelFactory(this.application, this)).get(MainViewModel::class.java)
binding.data = mainViewModel
binding.lifecycleOwner = this
wordDatabase = Room.databaseBuilder(this, WordDatabase::class.java, "word_database")
.allowMainThreadQueries()
.build()
wordDao = wordDatabase.getWordDao()
updateView()
}
//更新view
fun updateView() {
val list = wordDao.getAllWords()
var test = ""
for (word in list) {
test = test + word.id + ":" + word.word + "=" + word.chineseMean + "\n"
}
value.text = test
}
//添加数据
fun add(view: View) {
val word = Word("peakmain", "皮克曼")
val word1 = Word("body", "宝宝")
wordDao.insertWord(word, word1)
updateView()
}
//更新
fun update(view: View) {
val word = Word("Treasure", "喜")
word.id = 1
wordDao.updateWord(word)
updateView()
}
}
代码修改一
问题:1、会存在多个对象的实体类
2、mainviewmodel实际应该只是管理数据而不负责创建数据和删除数据等功能
- WordDatabase单例
@Database(entities = [Word::class], version = 1, exportSchema = false)
abstract class WordDatabase : RoomDatabase() {
companion object {
private var INSTANCE: WordDatabase? = null
fun getInstance(context: Context): WordDatabase {
if (INSTANCE == null) {
synchronized(this) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.applicationContext
, WordDatabase::class.java, "word_database")
.build()
}
}
}
return INSTANCE!!
}
}
abstract fun getWordDao(): WordDao
}
- 修改wordDao里面获取数据
@Query("SELECT *FROM WORD ORDER BY ID DESC ")
fun getAllWords():LiveData<List<Word>>
- 建立仓库
我们会发现一个问题:ViewModel的作用是和管理界面相关的数据,所以插入数据、更新数据和获取数据我们应该放到一个仓库里面
class WordRepository(context: Context) {
val wordDatabase: WordDatabase = WordDatabase.getInstance(context.applicationContext)
val wordDao = wordDatabase.getWordDao()
val allWordsLive: LiveData<List<Word>> = wordDao.getAllWords()
fun insertWords(vararg word: Word) {
InsertAsyncTask(wordDao).execute(*word)
}
fun updateWord(vararg word: Word) {
UpdateAsyncTask(wordDao).execute(*word)
}
class InsertAsyncTask(private val wordDao: WordDao) : AsyncTask<Word, Void, Void>() {
override fun doInBackground(vararg p0: Word): Void? {
wordDao.insertWord(*p0)
return null
}
}
class UpdateAsyncTask(private val wordDao: WordDao) : AsyncTask<Word, Void, Void>() {
override fun doInBackground(vararg p0: Word): Void? {
wordDao.updateWord(*p0)
return null
}
}
}
- MainViewModel代码修改
class MainViewModel(application: Application) : AndroidViewModel(application) {
private val context: Application = application
var wordRepository: WordRepository = WordRepository(application)
fun getAllWordsLive(): LiveData<List<Word>> {
return wordRepository.allWordsLive
}
fun insertWords(vararg word: Word) {
wordRepository.insertWords(*word)
}
fun updateWord(vararg word: Word) {
wordRepository.updateWord(*word)
}
fun startActivity() {
val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(intent)
}
}
- mainActivity代码修改
class MainActivity : AppCompatActivity() {
lateinit var wordDao: WordDao
lateinit var binding: ActivityMainBinding
private lateinit var mainViewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
mainViewModel =
ViewModelProvider(this, SavedStateViewModelFactory(this.application, this))
.get(MainViewModel::class.java)
binding.data = mainViewModel
binding.lifecycleOwner = this
mainViewModel.getAllWordsLive().observe(this, Observer<List<Word>> { t ->
var test = ""
for (word in t) {
test = test + word.id + ":" + word.word + "=" + word.chineseMean + "\n"
}
value.text = test
})
}
//添加数据
fun add(view: View) {
val word1 = Word("peakmain", "皮克曼")
val word2 = Word("body", "宝宝")
mainViewModel.insertWords(word1,word2)
}
//更新
fun update(view: View) {
val word = Word("Treasure", "喜")
word.id = 3
mainViewModel.updateWord(word)
}
}
迁移表结构
- word修改
@ColumnInfo(name = "showChinese")
var showChinese: Boolean = false
- WordDatabase
@Database(entities = [Word::class], version = 2, exportSchema = false)
abstract class WordDatabase : RoomDatabase() {
companion object {
private var INSTANCE: WordDatabase? = null
fun getInstance(context: Context): WordDatabase {
if (INSTANCE == null) {
synchronized(this) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.applicationContext
, WordDatabase::class.java, "word_database")
.addMigrations(migration1_2)
.build()
}
}
}
return INSTANCE!!
}
}
abstract fun getWordDao(): WordDao
}
object migration1_2 : Migration(1,2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE word ADD COLUMN showChinese INTEGER NOT NULL DEFAULT 1")
}
}
删除数据库中某个字段
删除数据库中某个字段步骤
- 1、创建新表
- 2、从旧表中插入数据
- 3、删除旧表
- 4、修改表名为旧表表名
object migration2_3 : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.run {
execSQL("CREATE TABLE word_tmp (id INTEGER PRIMARY KEY NOT NULL,english_word TEXT," +
"chinese_mean TEXT)")
execSQL("INSERT INTO word_tmp (id,english_word,chinese_mean) " +
"SELECT id,english_word,chinese_mean from word")
execSQL("DROP TABLE word")
execSQL("ALTER TABLE word_tmp RENAME to word")
}
}
}
WorkManager
使用 WorkManager API 可以轻松地调度即使在应用退出或设备重启时仍应运行的可延迟异步任务
def work_version = "2.3.4"
// Kotlin + coroutines
implementation "androidx.work:work-runtime-ktx:$work_version"
// optional - GCMNetworkManager support
implementation "androidx.work:work-gcm:$work_version"
// optional - Test helpers
androidTestImplementation "androidx.work:work-testing:$work_version"
class MyWork(@NonNull context: Context, @NonNull workerParams: WorkerParameters)
: Worker(context, workerParams) {
override fun doWork(): Result {
val value = inputData.getString("in_key")
Log.e("TAG", "value = $value")
Log.e("TAG", "开始睡眠")
Thread.sleep(3000)
Log.e("TAG", "结束睡眠")
return Result.success(workDataOf("out_key" to "$value result"))
}
}
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)//👈设置条件为网络连接情况
.build()
val workReuest =
OneTimeWorkRequestBuilder<MyWork>()
//.setConstraints(constraints)//👈设置条件
.setInputData(workDataOf("in_key" to "Peakmain"))//👈输入简单数据
.build()
workManager.enqueue(workReuest)
//监听数据变化
workManager.getWorkInfoByIdLiveData(workReuest.id)
.observe(this, Observer {
Log.e("TAG", "onCreate:" + it.state)
if (it.state == WorkInfo.State.SUCCEEDED) {
Log.e("TAG", "onCreate" + it.outputData.getString("out_key"))
}
})
网友评论