源码分析: Jetpack 之 ViewModel 原理
ViewModel
- 管理数据,把VIEW中的数据独出来,单独进行管理
- 管理数据的保存与恢复,比如屏幕转动,用户点回退按钮,或切换语言等操作
- 可以很方便的监听到UI上的数据变化
- 主要和LiveData与Room组合使用
注意:ViewModel只是用来管理UI的数据的,千万不要让它持有View、Activity或者Fragment的引用(小心内存泄露)。
ViewModel数据恢复原理
public class NameViewModel extends ViewModel {
public int i = 0;
private MutableLiveData currentName;
public MutableLiveData getCurrentName(){
if(currentName==null){
currentName=new MutableLiveData<>();
}
return currentName;
}
}
分析入口
1.获取viewModel>>
//获取viewModel
nameViewModel = ViewModelProviders.of(getActivity()).get(NameViewModel.class);
新版本
nameViewModel = new ViewModelProvider.NewInstanceFactory().create(NameViewModel.class);
或者
ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()).create(NameViewModel.class);
2 ViewModelProviders.of() >>
保存了ViewModelStore和Factory并返回ViewModelProvider
参数1:getViewModelStore()方法中
从Activity的NonConfigurationInstances中取ViewModelStore,取不到就new一个
参数2:Factory中反射生成ViewModel实例
3 保存和恢复状态>>
ComponentActivity
onRetainNonConfigurationInstance()保存状态 转屏时自动调用
getLastNonConfigurationInstance()恢复状态
4 保存viewModelStore>>
Activity在横竖屏切换时悄悄保存了viewModelStore,放到了NonConfigurationInstances实例里面,横竖屏切换时保存了又恢复了回来,相当于ViewModel实例就一直在,也就避免了横竖屏切换时的数据丢失.
ROOM使用
表定义 >>
@Entity
1. @PrimaryKey
主键
autoGenerate=true 自增长
2. @ColumnInfo
字段
name="zcwfeng" 字段名
3. @Ignore
表示一个属性不加入生成表的字段,只是临时使用
数据访问对象的定义
@Dao
------ 定义Dao层
@Dao
public interface StudentDao {
.....
}
1. @Query
查询
@Query("select * from Student")
List getAll();
可以把参数加入查询语句
//查询一条记录
@Query("select * from Student where name like:name")
Student findByName(String name);
//查找部份ID号的记录
@Query("select * from Student where uid in (:userIds)")
List getAllId(int[] userIds);
2. @Insert
插入
@Insert
void insert(Student... students);
3. @Delete
删除
@Delete
void delete(Student student);
4. @Update
更新
@Update
void update(Student student);
数据库的定义 >>
@Database
定义数据库中包含的表----entities={Student.class}
数据库版本号------version=1
@Database(entities = {Student.class},version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract StudentDao userDao();
}
返回例的子集 >>
public class NameTuple {
@ColumnInfo(name="first_name")
public String firstName;
@ColumnInfo(name="last_name")
public String lastName;
}
@Dao
public interface MyDao {
@Query("SELECT first_name, last_name FROM user")
public List loadFullName();
}
表与表之间的实体联系 >>
@Entity(foreignKeys = @ForeignKey(entity = User.class,
parentColumns = "id",
childColumns = "user_id"))
public class Book {
@PrimaryKey
public int bookId;
public String title;
@ColumnInfo(name = "user_id")
public int userId;
}
创建嵌套对象 >>
public class Address {
public String street;
public String state;
public String city;
@ColumnInfo(name = "post_code")
public int postCode;
}
@Entity
public class User {
@PrimaryKey
public int id;
public String firstName;
@Embedded
public Address address;
}
传递参数集合 >>
@Dao
public interface MyDao {
@Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
public List loadUsersFromRegions(List regions);
}
可观察的查询 >>
@Dao
public interface MyDao {
@Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
public LiveData> loadUsersFromRegionsSync(List regions);
}
@Dao
public interface MyDao {
@Query("SELECT user.name AS userName, pet.name AS petName "
+ "FROM user, pet "
+ "WHERE user.id = pet.user_id")
public LiveData> loadUserAndPetNames();
// You can also define this class in a separate file, as long as you add the
// "public" access modifier.
static class UserPet {
public String userName;
public String petName;
}
}
支持Rxjava >>
@Dao
public interface MyDao {
@Query("SELECT * from user where id = :id LIMIT 1")
public Flowable loadUserById(int id);
}
返回Cursor >>
@Dao
public interface MyDao {
@Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
public Cursor loadRawUsersOlderThan(int minAge);
}
Room数据库迁移
Room.databaseBuilder(getApplicationContext(), MyDb.class, "database-name")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3).build();
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, "
+ "`name` TEXT, PRIMARY KEY(`id`))");
}
};
static final Migration MIGRATION_2_3 = new Migration(2, 3) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE Book "
+ " ADD COLUMN pub_year INTEGER");
}
};
Jetpack(一)Lifecycle和LiveData
JetPacks之Lifecycles原理
JetPack之 LifeCycle LiveData
Jetpack(二)之DataBinding
Jetpack(三) 之 Room 与 ViewModel
Jetpack 之 ViewModel 原理
Jetpack (四) 之 Navigation
Jetpack Navigation 原理浅析
JetPack (五)之 Paging 分页库
Jetpack(六) 之 WorkManager
Jetpack WorkManager 原理