@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
binding.ivOk.setVisibility(View.VISIBLE);
} else {
if (binding.etTitle.getText().length() == 0 && binding.etContent.getText().length() == 0 ){
binding.ivOk.setVisibility(View.GONE);
}
}
}
});
}
/**
- 显示键盘
*/
public void showInput() {
binding.etContent.requestFocus();
inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
/**
- 隐藏键盘
*/
public void dismiss() {
if (inputMethodManager != null) {
inputMethodManager.hideSoftInputFromWindow(binding.etContent.getWindowToken(), 0);
}
}
@Override
protected void onPause() {
super.onPause();
dismiss();
}
@Override
public void onBackPressed() {
super.onBackPressed();
dismiss();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_ok://提交
showMsg(“提交”);
break;
}
}
}
这个页面的逻辑当前是这样的,有两个输入框,一个是标题一个是内容,当输入框有输入的时候显示一个提交按钮,当没有输入或者输入框为空的时候隐藏这个提交按钮,还有一个就是一进入当前页面,就显示内容的输入框光标,同时弹出软键盘。
这个页面也需要一个入口,也就是记事本页面点击右下角的按钮跳转过来,在activity_notebook.xml中修改浮动按钮的onClick事件。
这里是一个toEdit,然后在NotebookActivity中新增一个toEdit方法
/**
- 去编辑
*/
public void toEdit(View view) {
jumpActivity(EditActivity.class);
}
当然了,我们的NotebookActivity也需要一个入口,在我的MVVM中我就在侧滑菜单中增加入口,首先增加一个路径图标,在drawable下新增一个icon_notebook.xml,代码如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><vector xmlns:android=“http://schemas.android.com/apk/res/android”
android:width=“24dp”
android:height=“24dp”
android:autoMirrored=“true”
android:tint=“#000000”
android:viewportWidth=“24.0”
android:viewportHeight=“24.0”>
<path
android:fillColor=“@android:color/white”
android:pathData=“M14.17,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V9.83c0,-0.53 -0.21,-1.04 -0.59,-1.41l-4.83,-4.83C15.21,3.21 14.7,3 14.17,3L14.17,3zM8,15h8c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1H8c-0.55,0 -1,-0.45 -1,-1v0C7,15.45 7.45,15 8,15zM8,11h8c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1H8c-0.55,0 -1,-0.45 -1,-1v0C7,11.45 7.45,11 8,11zM8,7h5c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1H8C7.45,9 7,8.55 7,8v0C7,7.45 7.45,7 8,7z” />
然后在nav_menu.xml中新增代码:
<item
android:id=“@+id/item_notebook”
android:icon=“@drawable/icon_notebook”
android:title=“记事本” />
添加位置如下图所示:
最后在HomeActivity中修改一下菜单点击代码,如下图所示:
下面我们运行一下:
编辑页面写好了,需要写具体的功能了,这需要在数据库中一个笔记表。
① Bean
首先在bean包下新增一个Notebook类,代码如下:
@Entity(tableName = “notebook”)
public class Notebook {
@PrimaryKey(autoGenerate = true)
private int uid;
private String title;
private String content;
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Ignore
public Notebook(String title, String content) {
this.title = title;
this.content = content;
}
public Notebook() {}
}
这目前的表中我只设置了两个主要字段,标题和内容,uid自增。
② Dao
下面就是数据表的操作接口类,在dao包下新建一个NotebookDao接口,代码如下:
@Dao
public interface NotebookDao {
@Query(“SELECT * FROM notebook”)
Flowable<List> getAll();
@Update
Completable update(Notebook notebook);
@Insert(onConflict = OnConflictStrategy.REPLACE)
Completable insert(Notebook notebook);
@Delete
Completable delete(Notebook notebook);
}
这里就是增删改查,相信你已经很熟悉了,如果你是从之前的文章一路看过来的话。
③ 数据库升级迁移
打开AppDatabase首先增加表和版本升级,如下图所示:
下面增加刚才的Dao的实现,一行代码搞定,如下图所示:
public abstract NotebookDao notebookDao();
然后是数据库升级迁移,代码如下:
/**
- 版本升级迁移到6 在数据库中新增一个笔记表
*/
static final Migration MIGRATION_5_6 = new Migration(5, 6) {
@Override
public void migrate(@NonNull @NotNull SupportSQLiteDatabase database) {
//创建笔记表
database.execSQL("CREATE TABLE notebook
" +
"(uid INTEGER NOT NULL, " +
"title TEXT, " +
"content TEXT, " +
“PRIMARY KEY(uid
))”);
}
};
最后添加迁移,如下图所示:
数据库搞定了,下面就是存储库了。
④ 新增存储库类
在repository包下新建一个NotebookRepository类,里面的代码如下:
public class NotebookRepository {
private static final String TAG = NotebookRepository.class.getSimpleName();
@Inject
NotebookRepository() {}
private final MutableLiveData notebookLiveData = new MutableLiveData<>();
private final MutableLiveData<List> notebooksMutableLiveData = new MutableLiveData<>();
public final MutableLiveData failed = new MutableLiveData<>();
public final List emptyList = new ArrayList<>();
/**
- 添加笔记
*/
public void saveNotebook(Notebook notebook) {
//保存到数据库
Completable insert = BaseApplication.getDb().notebookDao().insert(notebook);
//RxJava处理Room数据存储
CustomDisposable.addDisposable(insert, () -> Log.d(TAG, “saveNotebook: 笔记数据保存成功”));
}
/**
- 获取所有笔记
*/
public MutableLiveData<List> getNotebooks() {
Flowable<List> listFlowable = BaseApplication.getDb().notebookDao().getAll();
CustomDisposable.addDisposable(listFlowable, notebooks -> {
if (notebooks.size() > 0) {
notebooksMutableLiveData.postValue(notebooks);
} else {
notebooksMutableLiveData.postValue(emptyList);
failed.postValue(“暂无数据”);
}
});
return notebooksMutableLiveData;
}
}
这里存储里面现在是两个方法,一个用于查询,一个用于添加。然后就是新建ViewModel去操作这个存储库。
⑤ 新增ViewModel
这里其实有两个ViewModel,一个对应EditActivity,一个对应NotebookActivity,首先在viewmodels包下创建一个EditViewModel类,代码如下:
public class EditViewModel extends BaseViewModel {
private final NotebookRepository notebookRepository;
@ViewModelInject
EditViewModel(NotebookRepository notebookRepository){
this.notebookRepository = notebookRepository;
}
/**
- 添加笔记
*/
public void addNotebook(Notebook notebook) {
failed = notebookRepository.failed;
notebookRepository.saveNotebook(notebook);
}
}
然后同样在viewmodels包下创建NotebookViewModel类,代码如下:
public class NotebookViewModel extends BaseViewModel {
private final NotebookRepository notebookRepository;
public LiveData<List> notebooks;
@ViewModelInject
NotebookViewModel(NotebookRepository notebookRepository){
this.notebookRepository = notebookRepository;
}
public void getNotebooks() {
failed = notebookRepository.failed;
notebooks = notebookRepository.getNotebooks();
}
}
⑥ 添加笔记
首先需要把EditViewModel与EditActivity进行绑定,如下图所示:
然后就是很简单的时候,在点击右上角按钮时,进行保存笔记,在EditActivity中修改一下代码,如下图所示:
这里我是保存了数据之后关掉当前页面,就会返回到之前的NotebookActivity,那么在这个页面就需要搜索当前数据库的表,然后通过列表加载出来。
既然是一个列表,那么自然就需要有一个item的布局,在layout下新建一个item_notebook.xml,里面的代码如下:
<?xml version="1.0" encoding="utf-8"?><variable
name=“notebook”
type=“com.llw.mvvm.db.bean.Notebook” />
<variable
name=“onClick”
type=“com.llw.mvvm.ui.adapter.NotebookAdapter.ClickBinding” />
<RelativeLayout
android:id=“@+id/detail”
android:foreground=“?attr/selectableItemBackground”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
android:layout_marginBottom=“8dp”
android:background=“@drawable/shape_bg_white_radius_12”
android:onClick=“@{() -> onClick.itemClick(notebook,detail)}”
android:padding=“12dp”>
<TextView
android:id=“@+id/tv_title”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:ellipsize=“end”
android:singleLine=“true”
android:text=“@{notebook.title}”
android:textColor=“@color/black”
android:textSize=“16sp” />
<TextView
android:id=“@+id/tv_content”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_below=“@+id/tv_title”
android:layout_marginTop=“4dp”
android:ellipsize=“end”
android:maxLines=“3”
android:text=“@{notebook.content}”
android:textSize=“14sp” />
布局很简单,就是显示标题和内容,采用databinding的方式赋值,下面创建适配器,在adapter包下新建一个NotebookAdapter类,里面的代码如下:
public class NotebookAdapter extends BaseQuickAdapter<Notebook, BaseDataBindingHolder> {
public NotebookAdapter(@Nullable List data) {
super(R.layout.item_notebook, data);
}
@Override
protected void convert(@NotNull BaseDataBindingHolder bindingHolder, Notebook notebook) {
ItemNotebookBinding binding = bindingHolder.getDataBinding();
if (binding != null) {
binding.setNotebook(notebook);
binding.setOnClick(new NotebookAdapter.ClickBinding());
binding.executePendingBindings();
}
}
public static class ClickBinding {
public void itemClick(Notebook notebook, View view) {
}
}
}
这个代码也是很简单的,就是绑定数据绑定布局,下面就是显示列表了,也很简单,回到NotebookActivity,增加三个变量并添加了一个注解,如下图所示:
修改代码,如下图所示:
首先是绑定ViewModel,然后在onResume的生命周期查询数据库中的数据,在编辑页面对数据进行修改之后会销毁掉,然后就会显示NotebookActivity,会触发onResume,再去查询一次数据。然后监听数据,有数据则加载列表,没有就显示那个空内容布局。下面来运行一下看看效果如何。
还是可以的吧,下面要做的就是修改笔记。
修改笔记的前提是要查询到要修改的笔记,通过id进行查询,然后完成修改,说起来是挺简单的,当然了,实现起来也很简单,我们来实现吧。首先是列表item的点击事件,点击之后传递uid到EditActivity,通过通过uid去得到Notebook。
在NotebookAdapater中增加如下图所示代码:
因为我们的NotebookDao中并没有通过id查询笔记的方法,因此我们在NotebookDao中新加一个,代码如下:
@Query(“SELECT * FROM notebook WHERE uid=:uid”)
Flowable findById(int uid);
然后去NotebookRepository中去对方法进行实现,这里我们需要实现两个方法,一个用于通过id查询,一个用于修改,在NotebookRepository中新增如下代码:
/**
-
根据id获取笔记
-
@param uid id
*/
public MutableLiveData getNotebookById(int uid) {
Flowable flowable = BaseApplication.getDb().notebookDao().findById(uid);
CustomDisposable.addDisposable(flowable, notebook -> {
if (notebook != null) {
notebookLiveData.postValue(notebook);
} else {
failed.postValue(“未查询到笔记”);
}
});
return notebookLiveData;
}
/**
-
更新笔记
-
@param notebook
*/
public void updateNotebook(Notebook notebook) {
Completable update = BaseApplication.getDb().notebookDao().update(notebook);
CustomDisposable.addDisposable(update, () -> {
Log.d(TAG, "updateNotebook: " + “更新成功”);
failed.postValue(“200”);
});
}
存储库的方法写好了,下面就是在EditViewModel中去调用了,进入EditViewModel,新增如下代码:
public LiveData notebook;
/**
- 根据Id搜索笔记
*/
public void queryById(int uid) {
failed = notebookRepository.failed;
notebook = notebookRepository.getNotebookById(uid);
}
/**
- 更新笔记
*/
public void updateNotebook(Notebook notebook) {
failed = notebookRepository.failed;
notebookRepository.updateNotebook(notebook);
}
这个代码就没啥好说的,见过很多类似的了,最后就是在EditActivity。
进入EditActivity中,新增两个变量:
private int uid;
private Notebook mNotebook;
首先要处理uid的问题,因为我们点击新增笔记和笔记笔记都是进入这个页面,所以要分情况处理。
这里我把showInput从移除掉了,根据现在的业务逻辑它不应该在onCreate中调用了,需要在initView方法中,下面我们看看怎么去修改。
如图所示,这里获取uid,如果为-1表示为新增,否则就是更新。是更新的话就通过查询id然后观察返回的数据变化。
这里的binding.setNotebook(mNotebook);是直接通过单向绑定对控件进行赋值,因此这里需要修改一下activity_edit.xml中的代码:
最后我们修改一下确定按钮的业务逻辑,如下图所示:
这个-1是用来做什么的我就不再多说了,这里修改数据之后,依然后关闭当前页面。我们的代码写完了,运行一下吧。
修改就完成了,下面就是删除了。
删除的方法之前就写好了,因此Dao中不需要改动了,只要在NotebookRepository中增加删除的方法即可,代码如下:
/**
- 删除笔记
*/
public void deleteNotebook(Notebook notebook) {
Completable delete = BaseApplication.getDb().notebookDao().delete(notebook);
CustomDisposable.addDisposable(delete, () -> {
Log.d(TAG, "deleteNotebook: " + “删除成功”);
failed.postValue(“200”);
});
}
然后是EditViewModel中去调用,在EditViewModel中新增代码如下所示:
/**
- 删除笔记
*/
public void deleteNotebook(Notebook notebook) {
notebookRepository.deleteNotebook(notebook);
failed = notebookRepository.failed;
}
下面就是在EditActivity中去调用EditViewModel中的deleteNotebook方法,在标题哪里添加一个按钮,修改activity_edit.xml,代码如下:
<ImageView
android:id=“@+id/iv_delete”
android:layout_width=“36dp”
android:layout_height=“36dp”
android:layout_gravity=“end”
android:layout_marginEnd=“16dp”
android:foreground=“?attr/selectableItemBackground”
android:padding=“2dp”
android:src=“@mipmap/ic_delete”
android:visibility=“gone” />
注意添加的位置:
然后是修改EditActivity中的代码,主要就是注册按钮的监听,然后是调用删除的方法。
删除笔记
运行一下:
OK了,本篇文章就到这里了,下一篇可能会对记事本功能进行一个优化,主要是用户体验方面,时隔近一个月,再写文章时花费的时间依然很多,久违了的感觉。今天是周五了,周末愉快啊。
如果对你有所帮助的话,可以Fork or Star
GitHub:MVVM-Demo
CSDN: MVVMDemo_11.rar
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
最后说一下我的学习路线
其实很简单就下面这张图,含概了Android所有需要学的知识点,一共8大板块:
- 架构师筑基必备技能
- Android框架体系架构(高级UI+FrameWork源码)
- 360°Androidapp全方位性能调优
- 设计思想解读开源框架
- NDK模块开发
- 移动架构师专题项目实战环节
- 移动架构师不可不学习微信小程序
- 混合开发的flutter
Android学习的资料
我呢,把上面八大板块的分支都系统的做了一份学习系统的资料和视频,大概就下面这些,我就不全部写出来了,不然太长了影响大家的阅读。
330页PDF Android学习核心笔记(内含上面8大板块)
Android学习的系统对应视频
总结
我希望通过我自己的学习方法来帮助大家去提升技术:
-
1、多看书、看源码和做项目,平时多种总结
-
2、不能停留在一些基本api的使用上,应该往更深层次的方向去研究,比如activity、view的内部运行机制,比如Android内存优化,比如aidl,比如JNI等,并不仅仅停留在会用,而要通过阅读源码,理解其实现原理
-
3、同时对架构是有一定要求的,架构是抽象的,但是设计模式是具体的,所以一定要加强下设计模式的学习
-
4、android的方向也很多,高级UI,移动架构师,数据结构与算法和音视频FFMpeg解码,如果你对其中一项比较感兴趣,就大胆的进阶吧!
希望大家多多点赞,转发,评论加关注,你们的支持就是我继续下去的动力!加油!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
3720397545)]
[外链图片转存中…(img-TJv32E7i-1713720397546)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
[外链图片转存中…(img-o1tFuAbM-1713720397547)]
最后说一下我的学习路线
其实很简单就下面这张图,含概了Android所有需要学的知识点,一共8大板块:
- 架构师筑基必备技能
- Android框架体系架构(高级UI+FrameWork源码)
- 360°Androidapp全方位性能调优
- 设计思想解读开源框架
- NDK模块开发
- 移动架构师专题项目实战环节
- 移动架构师不可不学习微信小程序
- 混合开发的flutter
[外链图片转存中…(img-qSrP2UkP-1713720397548)]
Android学习的资料
我呢,把上面八大板块的分支都系统的做了一份学习系统的资料和视频,大概就下面这些,我就不全部写出来了,不然太长了影响大家的阅读。
330页PDF Android学习核心笔记(内含上面8大板块)
[外链图片转存中…(img-WhgvFNXI-1713720397549)]
Android学习的系统对应视频
总结
我希望通过我自己的学习方法来帮助大家去提升技术:
-
1、多看书、看源码和做项目,平时多种总结
-
2、不能停留在一些基本api的使用上,应该往更深层次的方向去研究,比如activity、view的内部运行机制,比如Android内存优化,比如aidl,比如JNI等,并不仅仅停留在会用,而要通过阅读源码,理解其实现原理
-
3、同时对架构是有一定要求的,架构是抽象的,但是设计模式是具体的,所以一定要加强下设计模式的学习
-
4、android的方向也很多,高级UI,移动架构师,数据结构与算法和音视频FFMpeg解码,如果你对其中一项比较感兴趣,就大胆的进阶吧!
希望大家多多点赞,转发,评论加关注,你们的支持就是我继续下去的动力!加油!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!