Source code analysis:ViewModel principle of jetpack
ViewModel
- Manage the data and manage the data in view separately
- Manage the saving and recovery of data, such as screen rotation, user clicking the back button, or switching languages
- It is very convenient to monitor the data changes on the UI
- It is mainly used in combination with livedata and room
Note: ViewModel is only used to manage UI data. Never let it hold a reference to view, activity or fragment (beware of memory leakage).
ViewModel data recovery principle
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;
}
}
Analysis entrance
1. Get ViewModel > >
//Get ViewModel
nameViewModel = ViewModelProviders.of(getActivity()).get(NameViewModel.class);
New version
nameViewModel = new ViewModelProvider.NewInstanceFactory().create(NameViewModel.class);
perhaps
ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()).create(NameViewModel.class);
2 ViewModelProviders.of() >>
Saves the viewmodelstore and factory and returns the viewmodelprovider
Parameter 1: in getviewmodelstore() method
Get the viewmodelstore from the nonconfigurationinstances of the activity. If you can’t get it, just new
Parameter 2: generate ViewModel instance from reflection in factory
3 save and restore status > >
ComponentActivity
Onretainnonconfigurationinstance() is called automatically when saving the status and turning the screen
Getlastnonconfigurationinstance() restore state
4 save viewmodelstore > >
The activity quietly saves the viewmodelstore during the horizontal and vertical screen switching and puts it in the nonconfigurationinstances instance. When the horizontal and vertical screen switching is saved and restored, it is equivalent to that the ViewModel instance is always there, which avoids the data loss during the horizontal and vertical screen switching
Room usage
Table definition > >
@Entity
1. @PrimaryKey
Primary key
Autogenerate = true self growth
2. @ColumnInfo
field
Name = “zcwfeng” field name
3. @Ignore
Indicates that an attribute is not added to the field of the generated table, but is only used temporarily
Definition of data access object
@Dao
——Define Dao layer
@Dao
public interface StudentDao {
.....
}
1. @Query
query
@Query("select * from Student")
List<Student> getAll();
Parameters can be added to query statements
//Query a record
@Query("select * from Student where name like:name")
Student findByName(String name);
//Find records of partial ID numbers
@Query("select * from Student where uid in (:userIds)")
List<Student> getAllId(int[] userIds);
2. @Insert
insert
@Insert
void insert(Student... students);
3. @Delete
delete
@Delete
void delete(Student student);
4. @Update
to update
@Update
void update(Student student);
Definition of Database > >
@Database
Define the tables contained in the database —– entities = {student. Class}
Database version number —— version = 1
@Database(entities = {Student.class},version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract StudentDao userDao();
}
Returns a subset of instances > >
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();
}
Physical relationships between tables > >
@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;
}
Create nested objects > >
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;
}
Pass parameter set > >
@Dao
public interface MyDao {
@Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
public List<NameTuple> loadUsersFromRegions(List<String> regions);
}
Observable queries > >
@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;
}
}
Support rxjava > >
@Dao
public interface MyDao {
@Query("SELECT * from user where id = :id LIMIT 1")
public Flowable<User> loadUserById(int id);
}
Return to cursor > >
@Dao
public interface MyDao {
@Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
public Cursor loadRawUsersOlderThan(int minAge);
}
Room database migration
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 (I) lifecycle and livedata
Lifecycle principles of jetpacks
Lifecycle livedata of jetpack
Room and ViewModel of jetpack (III)
ViewModel principle of jetpack
Navigation of jetpack (IV)
Analysis of jetpack navigation principle