Room and ViewModel of jetpack (III)

Time:2022-1-9

Source code analysis:ViewModel principle of jetpack

ViewModel

  1. Manage the data and manage the data in view separately
  2. Manage the saving and recovery of data, such as screen rotation, user clicking the back button, or switching languages
  3. It is very convenient to monitor the data changes on the UI
  4. 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

Databinding of jetpack (II)

Room and ViewModel of jetpack (III)
ViewModel principle of jetpack

Navigation of jetpack (IV)
Analysis of jetpack navigation principle

Paging Library of jetpack (V)

Workmanager of jetpack (VI)
Jetpack workmanager principles

Recommended Today

Tutorial on sending e-mail using net:: SMTP class in Ruby

Simple Mail Transfer Protocol(SMTP)SendE-mailAnd routing protocol processing between e-mail servers. RubyIt provides the connection of simple mail transfer protocol (SMTP) client of net:: SMTP class, and provides two new methods: new and start New takes two parameters: Server name defaults to localhost Port number defaults to 25 The start method takes these parameters: Server – […]