Jetpack - Room(Room 引入、Room 優化)

一、Room 引入

1、基本介紹
  • Room 在 SQLite 上提供了一個抽象層,以便在充分利用 SQLite 的強大功能的同時,能夠流暢地訪問數據庫,官方強烈建議使用 Room 而不是 SQLite
2、演示
(1)Setting
  • 模塊級 build.gradle
dependencies {implementation "androidx.room:room-runtime:2.2.5"annotationProcessor "androidx.room:room-compiler:2.2.5"
}
(2)Entity
  • MyStudent.java
package com.my.jetpackdemo.entity;import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;@Entity(tableName = "my_student")
public class MyStudent {@PrimaryKey(autoGenerate = true)@ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER)public int id;@ColumnInfo(name = "name", typeAffinity = ColumnInfo.TEXT)public String name;@ColumnInfo(name = "age", typeAffinity = ColumnInfo.INTEGER)public int age;public MyStudent(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}@Ignorepublic MyStudent(String name, int age) {this.name = name;this.age = age;}
}
  • 這是一個簡單的 Java 類,并且它被標記為 Room 數據庫的實體
  1. @Entity(tableName = "my_student"):這個注解表明 MyStudent 類是一個 Room 數據庫實體,并且其對應的表名是 my_student

  2. @PrimaryKey(autoGenerate = true):這個注解表明 id 字段是這個實體的主鍵,并且它的值是自動生成的

  3. @ColumnInfo:這個注解用于描述數據庫表中的列信息,它有兩個屬性,name 表示列名,typeAffinity 表示列的數據類型

  4. @Ignore:這個注解表示 Room 在處理這個類或它的字段時應該忽略它,這通常用于構造器或方法,以避免 Room 試圖將它們映射到數據庫列

(3)Dao
  • MyStudentDao.java
package com.my.jetpackdemo.dao;import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;import com.my.jetpackdemo.entity.MyStudent;import java.util.List;@Dao
public interface MyStudentDao {@Insertvoid insert(MyStudent... students);@Deletevoid delete(MyStudent... students);@Updatevoid update(MyStudent... students);@Query("SELECT * FROM my_student")List<MyStudent> getAll();@Query("SELECT * FROM my_student WHERE id = :id")MyStudent getById(int id);
}
  • 這是一個接口,它用于與 Room 數據庫進行交互,以操作 MyStudent 實體,這個接口使用了 Room 提供的注解來定義數據訪問對象(DAO)的方法
  1. insert(MyStudent... students)@Dao:這個注解表明這個接口是一個 Room 數據庫的數據訪問對象

  2. delete(MyStudent... students)@Insert:這個注解表明這個方法用于向數據庫中插入數據,方法接受一個或多個 MyStudent 對象作為參數,并將它們插入到數據庫中

  3. update(MyStudent... students)@Delete:這個注解表明這個方法用于從數據庫中刪除數據,方法接受一個或多個 MyStudent 對象作為參數,并從數據庫中刪除它們

  4. getAll()@Update:這個注解表明這個方法用于更新數據庫中的數據,方法接受一個或多個 MyStudent 對象作為參數,并更新數據庫中對應的記錄

  5. getAll()@Query:這個注解用于定義自定義的 SQL 查詢,這個方法返回一個 MyStudent 對象的列表,它包含了數據庫中所有的學生記錄

  6. getById(int id)@Query:這個注解用于定義自定義的 SQL 查詢,這個方法根據給定的 id 返回對應的 MyStudent 對象,如果沒有找到對應的記錄,它可能會返回 null

(4)Database
  • MyDatabase.java
package com.my.jetpackdemo.database;import android.content.Context;import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;import com.my.jetpackdemo.dao.MyStudentDao;
import com.my.jetpackdemo.entity.MyStudent;@Database(entities = {MyStudent.class}, version = 1, exportSchema = false)
public abstract class MyDatabase extends RoomDatabase {private static final String DATABASE_NAME = "my_db.db";private static MyDatabase myDatabase;public static synchronized MyDatabase getInstance(Context context) {if (myDatabase == null) {myDatabase = Room.databaseBuilder(context.getApplicationContext(), MyDatabase.class, DATABASE_NAME).build();}return myDatabase;}public abstract MyStudentDao getMyStudentDao();
}
  • 這是一個抽象類,它擴展了 Room 的 RoomDatabase 類,這個類代表了你的 Room 數據庫,并且它包含了與數據庫交互的 DAO(數據訪問對象)的抽象方法,@Database 注解標記了這個類為一個 Room 數據庫
  1. entities = {MyStudent.class}:表示這個數據庫包含 MyStudent 實體

  2. version = 1:表示數據庫的版本號,當實體或數據庫結構發生變化時,需要增加這個版本號

  3. exportSchema = false:表示不導出數據庫的 schema

(5)Activity Layout
  • activity_room_demo.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"tools:context=".RoomDemoActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingTop="20dp"android:paddingBottom="20dp"><Buttonandroid:id="@+id/button1"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginLeft="20dp"android:layout_marginRight="10dp"android:layout_weight="1"android:onClick="add"android:text="新增" /><Buttonandroid:id="@+id/button2"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:layout_marginRight="20dp"android:layout_weight="1"android:onClick="delete"android:text="刪除" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingTop="20dp"android:paddingBottom="20dp"><Buttonandroid:id="@+id/butto3"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginLeft="20dp"android:layout_marginRight="10dp"android:layout_weight="1"android:onClick="update"android:text="修改" /><Buttonandroid:id="@+id/button4"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:layout_marginRight="20dp"android:layout_weight="1"android:onClick="get"android:text="查詢" /></LinearLayout><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/rv_my_student"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
  • room_demo_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="50dp"android:orientation="vertical"><TextViewandroid:id="@+id/tv_id"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:text="TextView" /><TextViewandroid:id="@+id/tv_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:text="TextView" /><TextViewandroid:id="@+id/tv_age"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:text="TextView" />
</RelativeLayout>
(6)Adapter
  • MyStudentRecyclerViewAdapter.java
package com.my.jetpackdemo.adapter;import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;import com.my.jetpackdemo.R;
import com.my.jetpackdemo.entity.MyStudent;import java.util.ArrayList;
import java.util.List;public class MyStudentRecyclerViewAdapter extends RecyclerView.Adapter<MyStudentRecyclerViewAdapter.MyStudentRecyclerViewHolder> {private Context context;private List<MyStudent> myStudentList;public MyStudentRecyclerViewAdapter(Context context) {this.context = context;myStudentList = new ArrayList<>();}public MyStudentRecyclerViewAdapter(Context context, List<MyStudent> myStudentList) {this.context = context;this.myStudentList = myStudentList;}public List<MyStudent> getMyStudentList() {return myStudentList;}public void setMyStudentList(List<MyStudent> myStudentList) {this.myStudentList = myStudentList;}@NonNull@Overridepublic MyStudentRecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view = View.inflate(context, R.layout.room_demo_item, null);MyStudentRecyclerViewHolder myStudentRecyclerViewHolder = new MyStudentRecyclerViewHolder(view);return myStudentRecyclerViewHolder;}@Overridepublic void onBindViewHolder(@NonNull MyStudentRecyclerViewHolder holder, int position) {MyStudent myStudent = myStudentList.get(position);holder.tvId.setText(String.valueOf(myStudent.id));holder.tvName.setText(myStudent.name);holder.tvAge.setText(String.valueOf(myStudent.age));}@Overridepublic int getItemCount() {return myStudentList.size();}static class MyStudentRecyclerViewHolder extends RecyclerView.ViewHolder {TextView tvId;TextView tvName;TextView tvAge;public MyStudentRecyclerViewHolder(@NonNull View itemView) {super(itemView);tvId = itemView.findViewById(R.id.tv_id);tvName = itemView.findViewById(R.id.tv_name);tvAge = itemView.findViewById(R.id.tv_age);}}
}
(7)Activity Code
  • RoomDemoActivity.java
package com.my.jetpackdemo;import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;import com.my.jetpackdemo.adapter.MyStudentRecyclerViewAdapter;
import com.my.jetpackdemo.dao.MyStudentDao;
import com.my.jetpackdemo.database.MyDatabase;
import com.my.jetpackdemo.entity.MyStudent;import java.util.List;public class RoomDemoActivity extends AppCompatActivity {private RecyclerView rvMyStudent;private MyStudentRecyclerViewAdapter myStudentRecyclerViewAdapter;private MyDatabase myDatabase;private MyStudentDao myStudentDao;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_room_demo);rvMyStudent = findViewById(R.id.rv_my_student);myStudentRecyclerViewAdapter = new MyStudentRecyclerViewAdapter(this);rvMyStudent.setAdapter(myStudentRecyclerViewAdapter);rvMyStudent.setLayoutManager(new LinearLayoutManager(this));myDatabase = MyDatabase.getInstance(this);myStudentDao = myDatabase.getMyStudentDao();}public void add(View view) {MyStudent myStudent1 = new MyStudent("jack", 20);MyStudent myStudent2 = new MyStudent("tom", 21);new AddMyStudentTask().execute(myStudent1, myStudent2);}public void delete(View view) {new DeleteMyStudentTask().execute(new MyStudent(1, "", 0));}public void update(View view) {new UpdateMyStudentTask().execute(new MyStudent(2, "my", 100));}public void get(View view) {new GetMyStudentTask().execute();}class AddMyStudentTask extends AsyncTask<MyStudent, Void, Void> {@Overrideprotected Void doInBackground(MyStudent... students) {myStudentDao.insert(students);return null;}}class DeleteMyStudentTask extends AsyncTask<MyStudent, Void, Void> {@Overrideprotected Void doInBackground(MyStudent... students) {myStudentDao.delete(students);return null;}}class UpdateMyStudentTask extends AsyncTask<MyStudent, Void, Void> {@Overrideprotected Void doInBackground(MyStudent... students) {myStudentDao.update(students);return null;}}class GetMyStudentTask extends AsyncTask<Void, Void, Void> {@Overrideprotected Void doInBackground(Void... voids) {List<MyStudent> all = myStudentDao.getAll();myStudentRecyclerViewAdapter.setMyStudentList(all);return null;}@Overrideprotected void onPostExecute(Void unused) {super.onPostExecute(unused);myStudentRecyclerViewAdapter.notifyDataSetChanged();}}
}
3、Room 注解
  1. Entity 使用的注解
注解說明
@Entity用于標記一個類作為數據庫中的表
可以使用 tableName 屬性來指定表名
如果類中的字段需要映射到數據庫中的列,則字段必須有訪問修飾符(public、protected 或默認)
@PrimaryKey用于標記一個字段作為表的主鍵
可以設置 autoGenerate 為 true 來自動生成主鍵值
@ColumnInfo用于標記一個字段并提供額外的列信息
可以使用 name 屬性來指定列名
可以使用 index 屬性來創建索引
@Ignore用于標記一個字段或方法,使其不被 Room 考慮為數據庫的一部分
  1. Dao 使用的注解
注解說明
@Dao用于標記一個接口作為數據訪問對象(DAO)
DAO 接口中定義的方法用于執行數據庫的增刪改查操作
Room 會在編譯時生成這個接口的實現
@Insert、@Update、@Delete、@Query用于在 DAO 接口中標記方法,分別用于插入、更新、刪除和查詢數據
@Query 注解允許編寫自定義的 SQL 查詢語句
  1. Database 使用的注解
注解說明
@Database用于標記一個抽象類作為數據庫的入口點
可以使用 entities 屬性來指定包含在該數據庫中的所有實體類
使用 version 屬性來指定數據庫的版本號,以便進行遷移

二、Room 優化

1、基本介紹
  • 目前每當數據庫數據發生變化時,都需要開啟一個工作線程去重新獲取數據庫中的數據,可以當數據發生變化時,通過 LiveData 通知 View 層,實現數據自動更新
2、演示
(1)Entity
  • MyStudent.java
package com.my.room2.entity;import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;@Entity(tableName = "my_student")
public class MyStudent {@PrimaryKey(autoGenerate = true)@ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER)public int id;@ColumnInfo(name = "name", typeAffinity = ColumnInfo.TEXT)public String name;@ColumnInfo(name = "age", typeAffinity = ColumnInfo.INTEGER)public int age;public MyStudent(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}@Ignorepublic MyStudent(String name, int age) {this.name = name;this.age = age;}
}
(2)Dao
  • MyStudentDao.java
package com.my.room2.dao;import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;import com.my.room2.entity.MyStudent;import java.util.List;@Dao
public interface MyStudentDao {@Insertvoid insert(MyStudent... students);@Deletevoid delete(MyStudent... students);@Query("DELETE FROM my_student")void deleteAll();@Updatevoid update(MyStudent... students);@Query("SELECT * FROM my_student")LiveData<List<MyStudent>> getAllLive();
}
(3)Database
  • MyDatabase.java
package com.my.room2.database;import android.content.Context;import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;import com.my.room2.dao.MyStudentDao;
import com.my.room2.entity.MyStudent;@Database(entities = {MyStudent.class}, version = 1, exportSchema = false)
public abstract class MyDatabase extends RoomDatabase {private static final String DATABASE_NAME = "my_db.db";private static MyDatabase myDatabase;public static synchronized MyDatabase getInstance(Context context) {if (myDatabase == null) {myDatabase = Room.databaseBuilder(context.getApplicationContext(), MyDatabase.class, DATABASE_NAME).build();}return myDatabase;}public abstract MyStudentDao getMyStudentDao();
}
(4)Repository
  • MyStudentRepository.java
package com.my.room2.repository;import android.content.Context;
import android.os.AsyncTask;
import android.view.View;import androidx.lifecycle.LiveData;import com.my.room2.RoomDemoActivity;
import com.my.room2.dao.MyStudentDao;
import com.my.room2.database.MyDatabase;
import com.my.room2.entity.MyStudent;import java.util.List;public class MyStudentRepository {private MyStudentDao myStudentDao;public MyStudentRepository(Context context) {myStudentDao = MyDatabase.getInstance(context).getMyStudentDao();}// ----------------------------------------------------------------------------------------------------public void add(MyStudent... myStudents) {new AddMyStudentTask().execute(myStudents);}public void delete(MyStudent myStudent) {new DeleteMyStudentTask().execute(myStudent);}public void deleteAll() {new DeleteAllMyMyStudentTask().execute();}public void update(MyStudent myStudent) {new UpdateMyStudentTask().execute(myStudent);}public LiveData<List<MyStudent>> getAll() {return myStudentDao.getAllLive();}// ----------------------------------------------------------------------------------------------------class AddMyStudentTask extends AsyncTask<MyStudent, Void, Void> {@Overrideprotected Void doInBackground(MyStudent... students) {myStudentDao.insert(students);return null;}}class DeleteMyStudentTask extends AsyncTask<MyStudent, Void, Void> {@Overrideprotected Void doInBackground(MyStudent... students) {myStudentDao.delete(students);return null;}}class DeleteAllMyMyStudentTask extends AsyncTask<Void, Void, Void> {@Overrideprotected Void doInBackground(Void... voids) {myStudentDao.deleteAll();return null;}}class UpdateMyStudentTask extends AsyncTask<MyStudent, Void, Void> {@Overrideprotected Void doInBackground(MyStudent... students) {myStudentDao.update(students);return null;}}
}
(5)ViewModel
  • MyStudentViewModel.java
package com.my.room2.viewmodel;import android.app.Application;import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;import com.my.room2.entity.MyStudent;
import com.my.room2.repository.MyStudentRepository;import java.util.List;public class MyStudentViewModel extends AndroidViewModel {private MyStudentRepository myStudentRepository;public MyStudentViewModel(@NonNull Application application) {super(application);myStudentRepository = new MyStudentRepository(application);}public void add(MyStudent... myStudents) {myStudentRepository.add(myStudents);}public void delete(MyStudent myStudent) {myStudentRepository.delete(myStudent);}public void deleteAll() {myStudentRepository.deleteAll();}public void update(MyStudent myStudent) {myStudentRepository.update(myStudent);}public LiveData<List<MyStudent>> getAll() {return myStudentRepository.getAll();}
}
(6)Activity Layout
  • activity_room_demo.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"tools:context=".RoomDemoActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingTop="20dp"android:paddingBottom="20dp"><Buttonandroid:id="@+id/button1"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginLeft="20dp"android:layout_marginRight="10dp"android:layout_weight="1"android:onClick="add"android:text="新增" /><Buttonandroid:id="@+id/button2"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_weight="1"android:onClick="delete"android:text="刪除" /><Buttonandroid:id="@+id/butto3"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:layout_marginRight="20dp"android:layout_weight="1"android:onClick="update"android:text="修改" /></LinearLayout><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/rv_my_student"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
  • room_demo_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="50dp"android:orientation="vertical"><TextViewandroid:id="@+id/tv_id"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:text="TextView" /><TextViewandroid:id="@+id/tv_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:text="TextView" /><TextViewandroid:id="@+id/tv_age"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:text="TextView" />
</RelativeLayout>
(7)Adapter
  • MyStudentRecyclerViewAdapter.java
package com.my.room2.adapter;import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;import com.my.room2.R;
import com.my.room2.entity.MyStudent;import java.util.ArrayList;
import java.util.List;public class MyStudentRecyclerViewAdapter extends RecyclerView.Adapter<MyStudentRecyclerViewAdapter.MyStudentRecyclerViewHolder> {private Context context;private List<MyStudent> myStudentList;public MyStudentRecyclerViewAdapter(Context context) {this.context = context;myStudentList = new ArrayList<>();}public MyStudentRecyclerViewAdapter(Context context, List<MyStudent> myStudentList) {this.context = context;this.myStudentList = myStudentList;}public List<MyStudent> getMyStudentList() {return myStudentList;}public void setMyStudentList(List<MyStudent> myStudentList) {this.myStudentList = myStudentList;}@NonNull@Overridepublic MyStudentRecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view = View.inflate(context, R.layout.room_demo_item, null);MyStudentRecyclerViewHolder myStudentRecyclerViewHolder = new MyStudentRecyclerViewHolder(view);return myStudentRecyclerViewHolder;}@Overridepublic void onBindViewHolder(@NonNull MyStudentRecyclerViewHolder holder, int position) {MyStudent myStudent = myStudentList.get(position);holder.tvId.setText(String.valueOf(myStudent.id));holder.tvName.setText(myStudent.name);holder.tvAge.setText(String.valueOf(myStudent.age));}@Overridepublic int getItemCount() {return myStudentList.size();}static class MyStudentRecyclerViewHolder extends RecyclerView.ViewHolder {TextView tvId;TextView tvName;TextView tvAge;public MyStudentRecyclerViewHolder(@NonNull View itemView) {super(itemView);tvId = itemView.findViewById(R.id.tv_id);tvName = itemView.findViewById(R.id.tv_name);tvAge = itemView.findViewById(R.id.tv_age);}}
}
(8)Activity Code
  • RoomDemoActivity.java
package com.my.room2;import android.os.Bundle;
import android.view.View;import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import com.my.room2.adapter.MyStudentRecyclerViewAdapter;
import com.my.room2.dao.MyStudentDao;
import com.my.room2.database.MyDatabase;
import com.my.room2.entity.MyStudent;
import com.my.room2.viewmodel.MyStudentViewModel;import java.util.List;public class RoomDemoActivity extends AppCompatActivity {private RecyclerView rvMyStudent;private MyStudentRecyclerViewAdapter myStudentRecyclerViewAdapter;private MyStudentViewModel myStudentViewModel;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_room_demo);rvMyStudent = findViewById(R.id.rv_my_student);myStudentRecyclerViewAdapter = new MyStudentRecyclerViewAdapter(this);rvMyStudent.setAdapter(myStudentRecyclerViewAdapter);rvMyStudent.setLayoutManager(new LinearLayoutManager(this));myStudentViewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(MyStudentViewModel.class);myStudentViewModel.getAll().observe(this, new Observer<List<MyStudent>>() {@Overridepublic void onChanged(List<MyStudent> myStudents) {myStudentRecyclerViewAdapter.setMyStudentList(myStudents);myStudentRecyclerViewAdapter.notifyDataSetChanged();}});}public void add(View view) {MyStudent myStudent1 = new MyStudent("jack", 20);MyStudent myStudent2 = new MyStudent("tom", 21);myStudentViewModel.add(myStudent1, myStudent2);}public void delete(View view) {MyStudent myStudent = new MyStudent(1, "", 0);myStudentViewModel.delete(myStudent);}public void update(View view) {MyStudent myStudent = new MyStudent(2, "my", 100);myStudentViewModel.update(myStudent);}public void getAll(View view) {}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/93393.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/93393.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/93393.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【江科大CAN】2.1 STM32 CAN外設(上)

2.1 STM32 CAN外設&#xff08;上&#xff09;2.1.1 STM32 CAN外設簡介2.1.2 外圍電路設計2.1.3 STM32 CAN內部結構2.1.4 發送流程詳解2.1.5 接收流程詳解2.1.6 關鍵配置位總結STM32 CAN外設講解 大家好&#xff0c;歡迎繼續觀看CAN總線入門教程。本節開始&#xff0c;我們正式…

人工智能技術革命:AI工具與大模型如何重塑開發者工作模式與行業格局

引言&#xff1a;AI技術爆發的時代背景過去五年間&#xff0c;人工智能領域經歷了前所未有的爆發式增長。從2020年GPT-3的橫空出世到2023年多模態大模型的全面突破&#xff0c;AI技術已經從實驗室走向了產業應用的前沿。開發者作為技術生態的核心推動者&#xff0c;其工作模式正…

傅里葉變換

傅里葉變換:運用頻域的出發點就是能夠將波形從時域變換到頻域&#xff0c;用傅里葉變換可以做到這一點。有如下3種傅里葉變換類型&#xff1a;1.傅里葉積分(FI); 2.離散傅里葉變換(DFT); 3.快速傅里葉變換(FFT)。傅里葉積分是一種將時域的理想數學表達變換成頻域描述的數學技術…

【IQA技術專題】紋理相似度圖像評價指標DISTS

紋理一致性圖像評價指標: Image Quality Assessment: Unifying Structure and Texture Similarity&#xff08;2020 PAMI&#xff09;專題介紹一、研究背景二、方法總覽2.1 初始變換2.2 紋理表示和結構表示2.3 DISTS指標2.4 優化DISTS指標三、實驗結果四、總結本文將對統一圖像…

windows下Docker安裝路徑、存儲路徑修改

一、命令行指定安裝路徑? ??下載安裝包??&#xff1a;從Docker官網獲取安裝程序&#xff08;如Docker Desktop Installer.exe&#xff09;。??運行PowerShell??&#xff1a; & "H:\Docker Desktop Installer.exe" install --installation-dir"F:…

thingsboard 自定義動作JS編程

在 ThingsBoard 中實現 自定義動作&#xff08;Custom Action&#xff09;的 JavaScript 編程&#xff0c;主要通過“Custom action (with HTML template&#xff09;”方式完成&#xff0c;適用于創建彈窗、編輯實體、控制設備等交互行為。 實現步驟&#xff08;以添加設備或資…

Spring Boot 簡單接口角色授權檢查實現

一、背景與目標在Spring Boot應用開發中&#xff0c;接口級別的權限控制是系統安全的重要組成部分。本文將介紹一種簡單直接的接口角色授權檢查實現方案&#xff0c;適合快速開發和安全合規檢查場景。二、技術方案概述本方案采用自定義注解攔截器的方式實現&#xff0c;具有以下…

PytorchLightning最佳實踐日志篇

在 PyTorch Lightning&#xff08;PL&#xff09;中&#xff0c;日志系統是 “煉丹” 過程中復現實驗、對比效果、排查問題的核心工具。結合實際工程經驗&#xff0c;總結以下最佳實踐和技巧&#xff0c;幫助提升實驗效率&#xff1a; 一、日志工具的選擇與配置 PL 通過統一的s…

基于JavaWeb的兼職發布平臺的設計與實現

開發語言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服務器&#xff1a;tomcat7數據庫&#xff1a;mysql 5.7數據庫工具&#xff1a;Navicat12開發軟件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;Maven3.6系統展示系統首頁用戶登錄招聘信…

Linux學習--C語言(指針3)

1.指針函數和函數指針1.1 指針函數指針函數是函數&#xff0c;函數的返回值是指針不能返回局部變量的地址指針函數返回的地址可以作為下一個函數調用的參數1.2 函數指針函數指針是指針&#xff0c;指針指向一個函數#include <stdio.h>int Add(int x, int y) {return x y…

【JAVA EE初階】多線程(上)

目錄 1.預備知識 1.1 馮諾依曼體系結構&#xff1a; 1.2 現代CPU主要關心指標&#xff08;和日常開發密切相關的&#xff09; 1.3 計算機中&#xff0c;一個漢字占幾個字節&#xff1f; 1.4 Windows和Linux的區別 1.5 PCB的一些關鍵要點 2.線程和進程 2.1 創建線程的寫法…

用互聯網思維擴展電商后臺的 CRUD 功能

一、自定義實現MyBatis-Plus逆向工程 多數據源的問題解決了&#xff0c;接下來開始進行實際開發時&#xff0c;你會發現&#xff0c;最麻煩的一件事情就是要創建與數據庫表對應的POJO了。這些沒什么難度&#xff0c;但是繁瑣的內容會占據大量的開發時間。比如一個PmsProducr對…

無代碼測試平臺ATECLOUD全場景測試方案

ATECLOUD 智能云測試平臺是有納米軟件開發的一款以無代碼架構與彈性擴展體系為核心的自動化測試平臺&#xff0c;通過數據模型驅動的創新設計&#xff0c;為研發、產線等多場景提供高效可控的測試解決方案。?無代碼架構 ATECLOUD 打破傳統技術壁壘&#xff0c;構建完全可視化的…

當 AI 重構審計流程,CISA 認證為何成為破局關鍵

在南京審計大學最新發布的《面向審計行業 DeepSeek 大模型操作指南》中&#xff0c;一組數據引發行業深思&#xff1a;通過自動化數據處理、智能風險識別和定制化報告生成&#xff0c;AI 大模型能幫助審計人員降低 40% 以上的人工成本&#xff0c;同時將風險識別準確率提升至 9…

NAT技術、代理服務器

NAT/NAPT技術NAT的全稱是network address translation&#xff0c;網絡地址轉換。NAT 能在對外通信時夠將源 IP 轉為新源 IP&#xff0c;對內通信時將目的ip轉換成新目的ip&#xff0c;實現這個操作&#xff0c;靠的是地址轉換表但NAT的說法其實是不準確的&#xff0c;因為多個…

【硬件-筆試面試題】硬件/電子工程師,筆試面試題-45,(知識點:負反饋的作用,基礎理解,干擾和噪聲的抑制)

目錄 1、題目 2、解答 步驟一&#xff1a;明確負反饋的作用原理 步驟二&#xff1a;逐一分析選項 3、相關知識點 一、負反饋的基本原理 二、負反饋對干擾和噪聲的抑制機制 三、選項分析與答案 四、擴展思考&#xff1a;如何抑制不同位置的干擾&#xff1f; 總結 題目…

Flutter藍牙BLE開發完全指南(內含高級功能擴展)

Flutter藍牙BLE開發完全指南 我將為您提供一個完整的Flutter藍牙BLE實現方案,包含UI設計、權限處理、設備掃描、連接通信等完整功能。 完整實現方案 1. 添加依賴與權限配置 pubspec.yaml dependencies:flutter:sdk: flutterflutter_blue_plus: ^1.10.0permission_handler…

使用 Canvas 替代 <video> 標簽加載并渲染視頻

在部分瀏覽器環境或業務場景下&#xff0c;直接使用 <video> 標簽加載視頻會出現首幀延遲的情況。以下方法通過 WebGPU Canvas 2D 將視頻幀繪制到自定義 Canvas 上&#xff0c;讓 <video> 只做解碼&#xff0c;WebGPU 接管渲染&#xff0c;通過最小化對象創建 精…

基于Flask的智能停車場管理系統開發實踐

在現代城市中&#xff0c;停車難已成為一個普遍問題。為了解決這一問題&#xff0c;我開發了一個基于Python Flask框架的智能停車場管理系統。該系統集成了車牌識別、車位狀態監控、收費管理等多項功能&#xff0c;為停車場的智能化管理提供了完整的解決方案。系統功能概述該停…

【C#獲取高精度時間】

在C#中&#xff0c;有幾種方法可以獲取高精度時間&#xff08;高分辨率時間戳&#xff09;&#xff0c;適用于性能測量、計時等需要高精度的場景。以下是幾種常用方法&#xff1a; 1. 使用 Stopwatch 類&#xff08;推薦&#xff09; Stopwatch 類提供了最高精度的時間測量&…