Android JetPack架构——结合记事本Demo一篇打通对Sqlite的增删改查结合常 ...

打印 上一主题 下一主题

主题 548|帖子 548|积分 1644

以下是Google官方推荐的架构模式

使用此架构能带来什么好处?



  • UI和业务逻辑解耦。
  • 有用制止生命周期组件内存走漏。
  • 进步模块可测试性。
  • 进步应用稳定性,有用低落以下异常发生概率。
   针对Jetpack架构中繁多的组件,下面我具体介绍一款数据库交互组件Room。其余组件在Demo中使用也会做相应说明
  什么是Room?为什么要使用Room?
==============================================================================
Room是Google提供的一个ORM库。
Room持久性库在 SQLite 的底子上提供了一个抽象层,让用户可以或许在充分使用 SQLite 的强大功能的同时,获享更强健的数据库访问机制。
Room组件架构体系
=====================================================================
Entity,Dao,Database为Room的3大根本组件,不同组件之间的关系如图

Database:包罗数据库持有者,并作为应用已保存的持久关系型数据的底层毗连的重要接入点
使用方法:用@Database来注解类,且使用 @Database注释的类应满意以下条件


  • 是扩展RoomDatabase的抽象类。
  • 在注释中添加与数据库关联的实体列表。
  • 包罗具有 0 个参数且返回使用 @Dao 注释的类的抽象方法。
在运行时,可以通过调用 Room.databaseBuilder() 或 Room.inMemoryDatabaseBuilder() 获取 Database 的实例。
Entity:表示数据库中的表
使用方法:用@Entit来注解实体类。
Dao:提供访问数据库的方法
使用方法:@Dao用来注解一个接口或者抽象方法。
记事本应用讲解
==================================================================
Room作为JetPack架构组件中关于SQLite数据库的架构组件,对应有着自己的知识体系。下面通过记事本Demo对Room本身组件结合MVVM架构所涉及的知识体系做一个总结.
由于涉及到另外一些组件,在有使用到时会做扼要介绍.

记事本Demo效果图:

1.编写Room数据库

1.1 编写数据库实体类

@Data
@Entity(tableName = “note”)
public class Note implements Serializable {
@PrimaryKey(autoGenerate = true)
private int id;
@ColumnInfo(name = “title”)
private String title;
@ColumnInfo(name = “content”)
private String content;
@ColumnInfo(name = “last_update_time”)
private Date lastUpdateTime;
}
1.2 编写数据库管理类Database

   注意:因为实体类中存在复杂数据范例——时间类。以是在数据库管理中需要使用@TypeConverters注入转换类,对复杂范例举行统一的转换处置处罚
  @Database(entities = {Note.class},version = 1,exportSchema = false)
@TypeConverters({Converters.class})
public abstract class NoteDatabase extends RoomDatabase {
private static NoteDatabase INSTANCE;
public synchronized static NoteDatabase getINSTANCE(Context context) {
if (INSTANCE==null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),NoteDatabase.class,“note_datebase”)
.fallbackToDestructiveMigration()
.build();
}
return INSTANCE;
}
/**


  • 在@Database中 多个entity则写多个Dao
*/
public abstract NoteDao getNoteDao();
}
1.3 编写数据库操作接口Dao

@Dao
public interface NoteDao {
@Insert
void insertNotes(Note… notes);
@Update
void updateNotes(Note… notes);
@Delete
void deleteNotes(Note… notes);
@Query(“delete from note”)
void deleteAllNotes();
@Query(“select * from note order by last_update_time desc”)
LiveData<List> queryAllNotes();
@Query(“select * from note where content like :pattern order by last_update_time desc”)
LiveData<List> queryNotesWithPattern(String pattern);
}
2.编写数据仓库(Repository、AsyncTask)

如果此处不引入Repository类会造成什么影响呢?为什么要引入Repository?

对数据库的操作(调用Dao)逻辑将放于ViewModel中(步骤5)。使得ViewModel中代码变得紊乱
引入仓库类,用于对数据库操作并对ViewModel暴露方法。让ViewModel专注于数据处置处罚而非对数据库的调用,对ViewModel和Dao进一步解耦。
什么是AsyncTask?为什么需要引入AsyncTask?


  • 一个Android 已封装好的轻量级异步类,用于实现多线程、异步通信、消息通报
  • 数据库的操作很重,一次读写操作花费 10~20ms 是很常见的,这样的耗时很容易造成界面的卡顿。以是通常情况下,条件允许情况下要制止在主线程中处置处罚数据库。
public class NoteRepository {
private NoteDao noteDao;
private LiveData<List> allNoteLive;
public NoteRepository(Context context){
NoteDatabase database = NoteDatabase.getINSTANCE(context);
noteDao = database.getNoteDao();
allNoteLive = noteDao.queryAllNotes();
}
public LiveData<List> getAllWordLive() {
return allNoteLive;
}
public LiveData<List> queryNotesWithPattern(String pattern){
//暗昧匹配注意百分号
return noteDao.queryNotesWithPattern(“%”+pattern+“%”);
}
public void insertNotes(Note… notes){
new InsertAsyncTask(noteDao).execute(notes);
}
public void updateNotes(Note… notes){
new UpdateAsyncTask(noteDao).execute(notes);
}
public void deleteNotes(Note… notes){
new DeleteAsyncTask(noteDao).execute(notes);
}
public void deleteAllNotes(){
new DeleteAllAsyncTask(noteDao).execute();
}
//创建副线程类,继承AsyncTask实现
static class InsertAsyncTask extends AsyncTask<Note, Void, Void>{
private NoteDao noteDao;
InsertAsyncTask(NoteDao noteDao) {
this.noteDao = noteDao;
}
@Override
protected Void doInBackground(Note… notes) {
noteDao.insertNotes(notes);
return null;
}
}
static class UpdateAsyncTask extends AsyncTask<Note, Void, Void>{
private NoteDao noteDao;
UpdateAsyncTask(NoteDao noteDao) {
this.noteDao = noteDao;
}
@Override
protected Void doInBackground(Note… notes) {
noteDao.updateNotes(notes);
return null;
}
}
static class DeleteAllAsyncTask extends AsyncTask<Note, Void, Void>{
private NoteDao noteDao;
DeleteAllAsyncTask(NoteDao noteDao) {
this.noteDao = noteDao;
}
@Override
protected Void doInBackground(Note… notes) {
noteDao.deleteAllNotes();
return null;
}
}
static class DeleteAsyncTask extends AsyncTask<Note, Void, Void>{
private NoteDao noteDao;
DeleteAsyncTask(NoteDao noteDao) {
this.noteDao = noteDao;
}
@Override
protected Void doInBackground(Note… notes) {
noteDao.deleteNotes(notes);
return null;
}
}
}
3.编写ViewModel+LiveData

为什么要使用ViewModel?

ViewModel 是数据与 UI 分离的中间层,提供了一个将数据转换为 UI 友爱型数据的场所。其次,它也提供了多 Fragment 复用类似 ViewModel 的机制。
为什么要使用LiveData?

LiveData 是一个可以感知 Activity 、Fragment生命周期的数据容器。当 LiveData 所持有的数据改变时,它会通知相应的界面代码举行更新。
此处为了方便,数据和界面的交互放在了Activity中,读者有需要可以使用Databinding对Activity举行进一步解耦.
public class NoteViewModel extends AndroidViewModel {
/**


  • 使用数据仓库处置处罚好的数据库交互逻辑
*/
private NoteRepository repository;
public NoteViewModel(@NonNull Application application) {
super(application);
repository = new NoteRepository(application);
}
public LiveData<List> getAllNoteLive() {
return repository.getAllWordLive();
}
public LiveData<List> queryNotesWithPattern(String pattern){
return repository.queryNotesWithPattern(pattern);
}
public void insertNotes(Note… notes){
repository.insertNotes(notes);
}
public void updateNotes(Note… notes){
repository.updateNotes(notes);
}
public void deleteNotes(Note… notes){
repository.deleteNotes(notes);
}
public void deleteAllNotes(){
repository.deleteAllNotes();
}
}
4.编写界面

   界面引入了RecyclerView,代替了传统ListView。如果没有使用过RecyclerView可以参照
  Android 控件 RecyclerView
   其中涉及到矢量图的使用,如果没有使用过矢量图可以参照
  Android中使用矢量图(快速运用)
4.1 编写主页的Fragment

fragment_notes.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayout 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:id=“@+id/mainFragment”
android:layout_width=“match_parent”
android:layout_height=“match_parent”
tools:context=“.base.NotesFragment”>
  <androidx.recyclerview.widget.RecyclerView
android:id=“@+id/recyclerView”
android:layout_width=“match_parent”
android:layout_height=“match_parent” />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id=“@+id/floatingActionButton”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_gravity=“bottom|center”
android:layout_margin=“16dp”
android:clickable=“true”
app:srcCompat=“@drawable/ic_add_white_24dp” />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
cell_card.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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=“wrap_content”
android:clickable=“true”
androidrientation=“vertical”>
<androidx.cardview.widget.CardView
android:layout_width=“match_parent”
android:layout_height=“match_parent”
android:layout_marginLeft=“8dp”
android:layout_marginTop=“8dp”
android:layout_marginRight=“8dp”
android:foreground=“?selectableItemBackground”>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width=“match_parent”
android:layout_height=“match_parent”>
<androidx.constraintlayout.widget.Guideline
android:id=“@+id/guideline1”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
androidrientation=“vertical”
app:layout_constraintGuide_percent=“0.85” />
<ImageView
android:id=“@+id/imageView”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
app:layout_constraintBottom_toBottomOf=“parent”
app:layout_constraintEnd_toEndOf=“parent”
app:layout_constraintStart_toStartOf=“@+id/guideline1”
app:layout_constraintTop_toTopOf=“parent”
app:srcCompat=“@drawable/ic_keyboard_arrow_right_black_24dp” />
<TextView
android:id=“@+id/textView_title”
android:layout_width=“0dp”
android:layout_height=“wrap_content”
android:layout_marginStart=“8dp”
android:layout_marginLeft=“8dp”
android:layout_marginTop=“8dp”
android:text=“TextView”
android:textSize=“24sp”
app:layout_constraintBottom_toTopOf=“@+id/textView_time”
app:layout_constraintEnd_toStartOf=“@+id/guideline1”
app:layout_constraintHorizontal_bias=“0.05”
app:layout_constraintStart_toStartOf=“parent”
app:layout_constraintTop_toTopOf=“parent” />
<TextView
android:id=“@+id/textView_time”
android:layout_width=“0dp”
android:layout_height=“wrap_content”
android:layout_marginBottom=“8dp”
android:text=“TextView”
app:layout_constraintBottom_toBottomOf=“parent”
app:layout_constraintEnd_toStartOf=“@+id/guideline1”
app:layout_constraintStart_toStartOf=“@+id/textView_title”
app:layout_constraintTop_toBottomOf=“@+id/textView_title” />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
4.2 编写主界面映射Fragment界面

为什么要这样处置处罚?

在fragment中编写好界面后,只需要在main_activity将界面映射过来,之后页面的切换与数据通报交由Navigation作为导航管理Fragment。期间你的路径与与数据设置只需在可视化中简单操作即可。在main_activity只需要做很少的处置处罚即可

main_activity.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=“.MainActivity”>
<fragment
android:id=“@+id/fragment”
android:name=“androidx.navigation.fragment.NavHostFragment”
android:layout_width=“0dp”
android:layout_height=“0dp”
app:defaultNavHost=“true”
app:layout_constraintBottom_toBottomOf=“parent”
app:layout_constraintEnd_toEndOf=“parent”
app:layout_constraintStart_toStartOf=“parent”
app:layout_constraintTop_toTopOf=“parent”
app:navGraph=“@navigation/navigation” />
</androidx.constraintlayout.widget.ConstraintLayout>
5.编写RecyclerView的适配器

public class MyAdapt extends ListAdapter<Note, MyAdapt.MyViewHolder> {
public MyAdapt() {
super(new DiffUtil.ItemCallback() {
@Override
public boolean areItemsTheSame(@NonNull Note oldItem, @NonNull Note newItem) {
return oldItem.getId() == newItem.getId();
}
@Override
public boolean areContentsTheSame(@NonNull Note oldItem, @NonNull Note newItem) {
return oldItem.getContent().equals(newItem.getContent()) &&
oldItem.getLastUpdateTime().equals(newItem.getLastUpdateTime());
}
});
}
/**


  • 在适配器中创建 ViewHolder,选择item注入
*/
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View itemView = layoutInflater.inflate(R.layout.cell_card, parent, false);
return new MyViewHolder(itemView);
}
/**


  • 对每条item举行数据绑定
  • 经常被呼叫,每次滚入滚出都会调用,以是监听绑定放入onCreateViewHolder中
*/
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Note note = getItem(position);
holder.textView_title.setText(note.getTitle());
//对日期格式化再输出
@SuppressLint(“SimpleDateFormat”) SimpleDateFormat simpleDateFormat = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
holder.textView_time.setText(simpleDateFormat.format(note.getLastUpdateTime()));
holder.itemView.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putSerializable(“note”, note);
//通报参数
NavController navController = Navigation.findNavController(v);
navController.navigate(R.id.action_notesFragment_to_addFragment, bundle);
});
}
/**


  • 自定义 holder对应 item
  • 内部类最好使用static修饰,防止内存走漏
*/
static class MyViewHolder extends RecyclerView.ViewHolder {
TextView textView_title, textView_time;
MyViewHolder(@NonNull View itemView) {
super(itemView);
textView_title = itemView.findViewById(R.id.textView_title);
textView_time = itemView.findViewById(R.id.textView_time);
}
}
}
6.编写Fragment(对不同Fragment功能举行扼要介绍)

6.1 编写主界面Fragment逻辑

自我介绍一下,小编13年上海交大结业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到如今。
深知大多数Android工程师,想要提拔技能,往往是自己探索发展或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技能停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是渴望可以或许帮助到想自学提拔又不知道该从何学起的朋侪,同时减轻各人的负担。







既有得当小白学习的零底子资料,也有得当3年以上履历的小搭档深入学习提拔的进阶课程,根本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比力大,这里只是将部门目录大纲截图出来,每个节点里面都包罗大厂面经、学习笔记、源码课本、实战项目、讲解视频,并且后续会连续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)

【延伸Android必备知识点】

【Android部门高级架构视频学习资源】
**Android精讲视频学习后更加是如虎添翼!**进军BATJ大厂等(备战)!如今都说互联网隆冬,实在无非就是你上错了车,且穿的少(技能),要是你上对车,自身技能能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上低级步伐员泛滥,这套教程针对Android开发工程师1-6年的职员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水!
**任何市场都是优胜略汰适者生存,只要你技能过硬,到哪里都不存在饱和不饱和的问题,以是重要的还是提拔自己。懂得多是自己的加分项 而不是必须项。门槛高了只能证明这个市场在不绝成熟化!**另外一千个读者就有一千个哈姆雷特,以是以上只是自己的关键,不喜勿喷!
如果你是卡在缺少学习资源的瓶颈上,那么刚刚好我能帮到你。接待关注会连续更新和分享的。
《2024年Android移动开发全套学习资料》,初衷也很简单,就是渴望可以或许帮助到想自学提拔又不知道该从何学起的朋侪,同时减轻各人的负担。**
[外链图片转存中…(img-naSDg8vn-1711617414348)]
[外链图片转存中…(img-umhK8pBm-1711617414349)]
[外链图片转存中…(img-yqXPIBX8-1711617414349)]
[外链图片转存中…(img-pY0f54jd-1711617414349)]
[外链图片转存中…(img-WA81IFE9-1711617414350)]
[外链图片转存中…(img-k9oROOZn-1711617414350)]

既有得当小白学习的零底子资料,也有得当3年以上履历的小搭档深入学习提拔的进阶课程,根本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比力大,这里只是将部门目录大纲截图出来,每个节点里面都包罗大厂面经、学习笔记、源码课本、实战项目、讲解视频,并且后续会连续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-H0QWTyw5-1711617414350)]
【延伸Android必备知识点】
[外链图片转存中…(img-OxLrr8LF-1711617414351)]
【Android部门高级架构视频学习资源】
**Android精讲视频学习后更加是如虎添翼!**进军BATJ大厂等(备战)!如今都说互联网隆冬,实在无非就是你上错了车,且穿的少(技能),要是你上对车,自身技能能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上低级步伐员泛滥,这套教程针对Android开发工程师1-6年的职员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水!
**任何市场都是优胜略汰适者生存,只要你技能过硬,到哪里都不存在饱和不饱和的问题,以是重要的还是提拔自己。懂得多是自己的加分项 而不是必须项。门槛高了只能证明这个市场在不绝成熟化!**另外一千个读者就有一千个哈姆雷特,以是以上只是自己的关键,不喜勿喷!
如果你是卡在缺少学习资源的瓶颈上,那么刚刚好我能帮到你。接待关注会连续更新和分享的。
   本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

怀念夏天

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表