一、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 类提供了最高精度的时间测量&…