源碼分析: Jetpack 之 ViewModel 原理
ViewModel
- 管理數(shù)據(jù),把VIEW中的數(shù)據(jù)獨(dú)出來,單獨(dú)進(jìn)行管理
- 管理數(shù)據(jù)的保存與恢復(fù),比如屏幕轉(zhuǎn)動(dòng)问芬,用戶點(diǎn)回退按鈕收擦,或切換語言等操作
- 可以很方便的監(jiān)聽到UI上的數(shù)據(jù)變化
- 主要和LiveData與Room組合使用
注意:ViewModel只是用來管理UI的數(shù)據(jù)的,千萬不要讓它持有View、Activity或者Fragment的引用(小心內(nèi)存泄露)掘托。
ViewModel數(shù)據(jù)恢復(fù)原理
public class NameViewModel extends ViewModel {
public int i = 0;
private MutableLiveData<String> currentName;
public MutableLiveData<String> 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
參數(shù)1:getViewModelStore()方法中
從Activity的NonConfigurationInstances中取ViewModelStore,取不到就new一個(gè)
參數(shù)2:Factory中反射生成ViewModel實(shí)例
3 保存和恢復(fù)狀態(tài)>>
ComponentActivity
onRetainNonConfigurationInstance()保存狀態(tài) 轉(zhuǎn)屏?xí)r自動(dòng)調(diào)用
getLastNonConfigurationInstance()恢復(fù)狀態(tài)
4 保存viewModelStore>>
Activity在橫豎屏切換時(shí)悄悄保存了viewModelStore,放到了NonConfigurationInstances實(shí)例里面,橫豎屏切換時(shí)保存了又恢復(fù)了回來,相當(dāng)于ViewModel實(shí)例就一直在,也就避免了橫豎屏切換時(shí)的數(shù)據(jù)丟失.
ROOM使用
表定義 >>
@Entity
1. @PrimaryKey
主鍵
autoGenerate=true 自增長
2. @ColumnInfo
字段
name="zcwfeng" 字段名
3. @Ignore
表示一個(gè)屬性不加入生成表的字段卦睹,只是臨時(shí)使用
數(shù)據(jù)訪問對(duì)象的定義
@Dao
------ 定義Dao層
@Dao
public interface StudentDao {
.....
}
1. @Query
查詢
@Query("select * from Student")
List<Student> getAll();
可以把參數(shù)加入查詢語句
//查詢一條記錄
@Query("select * from Student where name like:name")
Student findByName(String name);
//查找部份ID號(hào)的記錄
@Query("select * from Student where uid in (:userIds)")
List<Student> getAllId(int[] userIds);
2. @Insert
插入
@Insert
void insert(Student... students);
3. @Delete
刪除
@Delete
void delete(Student student);
4. @Update
更新
@Update
void update(Student student);
數(shù)據(jù)庫的定義 >>
@Database
定義數(shù)據(jù)庫中包含的表----entities={Student.class}
數(shù)據(jù)庫版本號(hào)------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<NameTuple> loadFullName();
}
表與表之間的實(shí)體聯(lián)系 >>
@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;
}
創(chuàng)建嵌套對(duì)象 >>
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;
}
傳遞參數(shù)集合 >>
@Dao
public interface MyDao {
@Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
public List<NameTuple> loadUsersFromRegions(List<String> regions);
}
可觀察的查詢 >>
@Dao
public interface MyDao {
@Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
public LiveData<List<User>> loadUsersFromRegionsSync(List<String> 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<List<UserPet>> 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<User> loadUserById(int id);
}
返回Cursor >>
@Dao
public interface MyDao {
@Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
public Cursor loadRawUsersOlderThan(int minAge);
}
Room數(shù)據(jù)庫遷移
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(三) 之 Room 與 ViewModel
Jetpack 之 ViewModel 原理