历史记录
- 前言
- 正文
-
- 一、建表
- 二、新增历史记录页面
- 三、列表适配器
- 四、历史记录页面初始化
- 五、保存历史记录
- 六、删除历史记录
- 七、源码
前言
??本文将是这个垃圾分类APP的暂定最后一篇,后面可能有,可能没有,就像薛定谔的猫一样。
正文
??本文讲述垃圾分类的历史记录,为什么要这个记录呢?因为可能有时候我查询过某一件物品的分类,然后我不记得了,再查询一次我觉得麻烦,我就希望能看到以往的查询记录。这是一个很合理的要求,不是吗?
一、建表
??要保存历史数据,首先要有一个表,在上一篇文章中,我们已经建过一个News了,下面再建一个History表,在model包下新建一个History类,里面的代码如下:
package com.llw.goodtrash.model;import org.litepal.crud.LitePalSupport;/*** 历史记录实体** @author llw*/
public class History extends LitePalSupport {
private int id;private String name;private int type;private int aipre;private String explain;private String contain;private String tip;private String dateTime;public int getId() {
return id;}public void setId(int id) {
this.id = id;}public String getName() {
return name;}public void setName(String name) {
this.name = name;}public int getType() {
return type;}public void setType(int type) {
this.type = type;}public int getAipre() {
return aipre;}public void setAipre(int aipre) {
this.aipre = aipre;}public String getExplain() {
return explain;}public void setExplain(String explain) {
this.explain = explain;}public String getContain() {
return contain;}public void setContain(String contain) {
this.contain = contain;}public String getTip() {
return tip;}public void setTip(String tip) {
this.tip = tip;}public String getDateTime() {
return dateTime;}public void setDateTime(String dateTime) {
this.dateTime = dateTime;}
}
然后在litepal.xml中配置一下。
注意一下,当你的数据库已经创建之后,如果要使新增的表生效,则需要数据库的版本进行升级,比如之前是1,现在我新增了一个表,那么改成2,这样拟新增的表才会生效。或者你不升级,还是1,你只要把原来的APP卸载重装就可以。
二、新增历史记录页面
在ui包下新建一个HistoryActivity,布局是activity_history.xml。下面对于这个也页面的布局还是要想一下该怎么做,首先肯定要有一个列表用来展示这个数据吧。其次要是没有数据的时候显示一片空白好像也不合适。所以还需要一个显示空数据的布局。
好的,目前先搞定这两步。先写空数据布局,在layout下新建一个layout_empty_data.xml,里面的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:orientation="vertical"><ImageViewandroid:src="@mipmap/icon_empty_data"android:layout_width="@dimen/dp_100"android:layout_height="@dimen/dp_100" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="@dimen/dp_12"android:text="空空如也"android:textSize="@dimen/sp_16" />
</LinearLayout>
这里用到的icon_empty_data图标如下:
下面来写这个activity_history.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="match_parent"android:fitsSystemWindows="true"android:orientation="vertical"tools:context=".ui.HistoryActivity"><androidx.appcompat.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:background="@color/white"app:navigationIcon="@mipmap/icon_back"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="历史记录"android:textColor="@color/black"android:textSize="@dimen/sp_18" /></androidx.appcompat.widget.Toolbar><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginTop="@dimen/dp_2"><includeandroid:id="@+id/lay_empty_data"layout="@layout/layout_empty_data"android:layout_width="match_parent"android:layout_height="match_parent" /><!--历史记录列表--><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/rv_history"android:layout_width="match_parent"android:layout_height="match_parent"android:visibility="gone" /></RelativeLayout></LinearLayout>
布局写好了,但是还有列表的item需要写布局和适配器。
三、列表适配器
首先写item的布局,在layout下新建item_history_rv.xml,里面的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="@dimen/dp_1"android:background="@color/white"android:orientation="vertical"android:padding="@dimen/dp_12"><TextViewandroid:id="@+id/tv_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="物品名称"android:textColor="@color/black"android:textSize="@dimen/sp_16" /><TextViewandroid:id="@+id/tv_datetime"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentEnd="true"android:text="保存时间"android:textColor="@color/black"android:textSize="@dimen/sp_14" /><TextViewandroid:id="@+id/tv_type"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/tv_name"android:layout_marginTop="@dimen/dp_8"android:text="垃圾类型"android:textColor="@color/hint_color"android:textSize="@dimen/sp_14" /><TextViewandroid:id="@+id/tv_explain"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/tv_type"android:layout_marginTop="@dimen/dp_8"android:text="解释"android:textColor="@color/hint_color"android:textSize="@dimen/sp_14" /></RelativeLayout>
然后就是写适配器了,在adapter包下新建一个HistoryAdapter类,里面的代码如下:
package com.llw.goodtrash.adapter;import android.widget.TextView;import androidx.annotation.Nullable;import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.llw.goodtrash.R;
import com.llw.goodtrash.model.History;import java.util.List;/*** 历史记录列表适配器* @author llw*/
public class HistoryAdapter extends BaseQuickAdapter<History, BaseViewHolder> {
public HistoryAdapter(int layoutResId, @Nullable List<History> data) {
super(layoutResId, data);}@Overrideprotected void convert(BaseViewHolder helper, History item) {
helper.setText(R.id.tv_name, item.getName()).setText(R.id.tv_datetime,item.getDateTime()).setText(R.id.tv_explain, item.getExplain());TextView tvType = helper.getView(R.id.tv_type);switch (item.getType()) {
case 0:tvType.setText("可回收垃圾");break;case 1:tvType.setText("有害垃圾");break;case 2:tvType.setText("厨余垃圾");break;case 3://干垃圾即其他垃圾tvType.setText("干垃圾");break;default:tvType.setText("可回收垃圾");break;}}
}
四、历史记录页面初始化
修改HistoryActivity页面代码如下:
package com.llw.goodtrash.ui;import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;import com.llw.goodtrash.R;
import com.llw.goodtrash.adapter.HistoryAdapter;
import com.llw.goodtrash.model.History;
import com.llw.mvplibrary.base.BaseActivity;import org.litepal.LitePal;import java.util.List;/*** 历史记录* @author llw*/
public class HistoryActivity extends BaseActivity {
//工具栏private Toolbar toolbar;//空数据布局private LinearLayout layEmptyData;//历史列表private RecyclerView rvHistory;//适配器private HistoryAdapter mAdapter;//历史数据列表private List<History> mList;@Overridepublic void initData(Bundle savedInstanceState) {
initView();}/*** 页面初始化*/private void initView() {
toolbar = findViewById(R.id.toolbar);//设置页面状态栏setStatubar(this, R.color.white, true);back(toolbar,false);layEmptyData = findViewById(R.id.lay_empty_data);rvHistory = findViewById(R.id.rv_history);//获取数据库中的历史数据mList = LitePal.findAll(History.class);if (mList.size() > 0) {
//设置列表的数据mAdapter = new HistoryAdapter(R.layout.item_history_rv, mList);rvHistory.setLayoutManager(new LinearLayoutManager(context));rvHistory.setAdapter(mAdapter);layEmptyData.setVisibility(View.GONE);rvHistory.setVisibility(View.VISIBLE);} else {
//隐藏列表layEmptyData.setVisibility(View.VISIBLE);rvHistory.setVisibility(View.GONE);}}@Overridepublic int getLayoutId() {
return R.layout.activity_history;}
}
下面我们增加一个进入历史记录页面的入口。
修改activity_main.xml。在NestedScrollView下面加上一个浮动按钮:
<!--浮动按钮 历史记录--><com.google.android.material.floatingactionbutton.FloatingActionButtonandroid:id="@+id/btn_history"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="bottom|end"android:layout_margin="@dimen/dp_20"android:src="@mipmap/icon_history"android:onClick="jumpHistory"app:backgroundTint="@color/white"app:backgroundTintMode="screen"app:fabSize="mini"app:hoveredFocusedTranslationZ="@dimen/dp_18"app:pressedTranslationZ="@dimen/dp_18" />
位置如下图所示:
icon_history图标
然后在MainActivity中写一个jumpHistory方法,代码如下:
/*** 进入历史记录页面*/public void jumpHistory(View view) {
gotoActivity(HistoryActivity.class);}
运行一下;
嗯,现在是空空如也,下面来添加记录,进行垃圾分类结果返回的第三有三个,分别是文字输入进行垃圾分类,语音输入进行垃圾分类,还有图像输入进行垃圾分类。下面先来看看怎么保存这个垃圾分类的信息。
五、保存历史记录
在前面的文章中当进行分类时,会关联出很多物品,而我们要保存和我输入物品的一致性才行,比如当我搜索水杯时,会出现的结果有:水杯、保温杯、汽车杯等一些物品。而我只需要保存水杯的结果到历史记录就可以了。那么在写保存方法时首先要比对这个搜索结果。一致才保存。
下面来写代码,这里我还是写一个帮助类。在utils下新建一个HistoryHelper类,里面的代码如下:
package com.llw.goodtrash.utils;import android.util.Log;import com.google.gson.Gson;
import com.llw.goodtrash.model.History;
import com.llw.goodtrash.model.TrashResponse;
import com.llw.mvplibrary.network.utils.DateUtil;import org.litepal.LitePal;import java.util.List;/*** 历史记录帮助类** @author llw*/
public class HistoryHelper {
public static final String TAG = "HistoryHelper";/*** 查询所有历史记录** @return 结果列表*/public static List<History> queryAllHistory() {
return LitePal.findAll(History.class);}/*** 是否存在历史记录** @param name 物品名* @return true or false*/public static boolean isHaveHistory(String name) {
List<History> histories = LitePal.where("name = ?", name).find(History.class);return histories.size() > 0;}/*** 保存历史记录** @param list 需要保存的数据* @param word 物品名称*/public static void saveHistory(List<TrashResponse.NewslistBean> list, String word) {
for (TrashResponse.NewslistBean bean : list) {
//遍历返回数据,找出返回结果中与搜索内容一致的数据,保存到数据表中if (bean.getName().equals(word)) {
//保存数据前先查询是否存在数据List<History> historyList = queryAllHistory();//有数据则遍历检查保存if (historyList.size() > 0) {
if (!isHaveHistory(bean.getName())) {
//不存在则直接保存saveHistory(bean);} else {
Log.d(TAG, "记录已存在");}} else {
//没有数据则直接保存saveHistory(bean);}} else {
Log.d(TAG, "没有匹配到相关结果,无法保存");}}Log.d(TAG,new Gson().toJson(queryAllHistory()));}/*** 保存历史* @param bean*/private static void saveHistory(TrashResponse.NewslistBean bean) {
History historyBean = new History();historyBean.setName(bean.getName());historyBean.setType(bean.getType());historyBean.setAipre(bean.getAipre());historyBean.setExplain(bean.getExplain());historyBean.setContain(bean.getContain());historyBean.setTip(bean.getTip());//添加历史记录的保存时间historyBean.setDateTime(DateUtil.getDateTime());historyBean.save();if (historyBean.save()) {
Log.d(TAG, "保存历史记录成功");} else {
Log.d(TAG, "保存历史记录失败");}}
}
下面去使用一下这个方法。
首先是文字输入页面TextInputActivity。
将之前的word变成成员变量:
private String word;//输入的物品
当点击软键盘的搜索按钮时会将输入框的内容赋值给word。
然后只要在getSearchResponse方法中保存就好了。
下面进入声音输入页面VoiceInputActivity。
private String word;//输入的物品
进行赋值
保存结果。
然后是图像输入页面ImageInputActivity。
private String word;//输入的物品
然后赋值:
最后保存。
下面基本上都有了保存,运行一下:
嗯,效果还是不错的吧。
既然有保存,那就应该有删除,理论上来说,删除也是有学问的,单项删除、多选删除、全删。而删除的方法也是多种多样的,比如点击弹窗删除,侧滑删除,编辑列表删除。各种各样的,这里我就弄一个滑动删除和全选删除吧。
六、删除历史记录
先来看看侧滑删除,这里需要用到一个第三方依赖库,打开mvplibrary下的build.gradle。
在dependencies{}闭包下添加如下依赖:
//列表item侧滑删除api 'com.github.mcxtzhang:SwipeDelMenuLayout:V1.3.0'
添加位置如下:
下面修改历史列表的item布局。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="@dimen/dp_1"android:background="@color/white"><!--支持侧滑的布局--><com.mcxtzhang.swipemenulib.SwipeMenuLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:clickable="true"android:paddingBottom="1dp"><!--显示文本--><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:padding="@dimen/dp_12"><TextViewandroid:id="@+id/tv_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="物品名称"android:textColor="@color/black"android:textSize="@dimen/sp_16" /><TextViewandroid:id="@+id/tv_datetime"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentEnd="true"android:text="保存时间"android:textColor="@color/black"android:textSize="@dimen/sp_14" /><TextViewandroid:id="@+id/tv_type"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/tv_name"android:layout_marginTop="@dimen/dp_8"android:text="垃圾类型"android:textColor="@color/hint_color"android:textSize="@dimen/sp_14" /><TextViewandroid:id="@+id/tv_explain"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/tv_type"android:layout_marginTop="@dimen/dp_8"android:text="解释"android:textColor="@color/hint_color"android:textSize="@dimen/sp_14" /></RelativeLayout><!-- 侧滑菜单的内容 删除 --><Buttonandroid:id="@+id/btn_delete"android:layout_width="@dimen/dp_100"android:layout_height="match_parent"android:background="@color/red"android:text="删除"android:textColor="@color/white" /></com.mcxtzhang.swipemenulib.SwipeMenuLayout></RelativeLayout>
这里有一个red的颜色,在app模块的colors.xml中添加
<color name="red">#FF0000</color>
然后修改适配器HistoryAdapter,添加侧滑菜单的点击事件。
然后回到HistoryActivity页面去设置适配器的点击事件。
//列表item点击事件mAdapter.setOnItemChildClickListener((adapter, view, position) -> {
});
添加位置如下图所示:
由于现在只给适配器中的一个控件设置了点击事件,因此可以直接写代码,而不需要去判断控件id了。
那么下面在HistoryHelper中添加如下两个删除方法:
/*** 根据id删除数据* @param id id */public static void deleteHistoryById(long id){
LitePal.delete(History.class,id);}/*** 根据所有历史记录*/public static void deleteAllHistory() {
LitePal.deleteAll(History.class);}
下面我要修改一下HistoryActivity页面的代码:
package com.llw.goodtrash.ui;import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;import com.chad.library.adapter.base.BaseQuickAdapter;
import com.llw.goodtrash.R;
import com.llw.goodtrash.adapter.HistoryAdapter;
import com.llw.goodtrash.model.History;
import com.llw.goodtrash.utils.HistoryHelper;
import com.llw.mvplibrary.base.BaseActivity;import org.litepal.LitePal;import java.util.ArrayList;
import java.util.List;/*** 历史记录** @author llw*/
public class HistoryActivity extends BaseActivity {
//工具栏private Toolbar toolbar;//空数据布局private LinearLayout layEmptyData;//历史列表private RecyclerView rvHistory;//适配器private HistoryAdapter mAdapter;//历史数据列表private List<History> mList = new ArrayList<>();@Overridepublic void initData(Bundle savedInstanceState) {
initView();showListData();}/*** 页面初始化*/private void initView() {
toolbar = findViewById(R.id.toolbar);//设置页面状态栏setStatubar(this, R.color.white, true);back(toolbar, false);layEmptyData = findViewById(R.id.lay_empty_data);rvHistory = findViewById(R.id.rv_history);mAdapter = new HistoryAdapter(R.layout.item_history_rv, mList);rvHistory.setLayoutManager(new LinearLayoutManager(context));rvHistory.setAdapter(mAdapter);//列表item点击事件mAdapter.setOnItemChildClickListener((adapter, view, position) -> {
});}/*** 显示列表*/private void showListData() {
List<History> historyList = HistoryHelper.queryAllHistory();if (historyList.size() > 0) {
//设置列表的数据mList.clear();mList.addAll(historyList);mAdapter.notifyDataSetChanged();layEmptyData.setVisibility(View.GONE);rvHistory.setVisibility(View.VISIBLE);} else {
//隐藏列表layEmptyData.setVisibility(View.VISIBLE);rvHistory.setVisibility(View.GONE);}}@Overridepublic int getLayoutId() {
return R.layout.activity_history;}
}
这样改写是为了方便后面的删除操作。
下面运行一下:
下面来看看全部删除,这里我们就写的简单一些,打开activity_history.xml,在toolbar控件中,增加一个全删,如下所示:
<TextViewandroid:id="@+id/tv_all_delete"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="right"android:onClick="deleteAll"android:textColor="@color/black"android:textSize="@dimen/sp_16"android:layout_marginEnd="@dimen/dp_4"android:text="全删"android:padding="@dimen/dp_12"/>
回到HistoryActivity中。
//全删private TextView tvAllDelete;
绑定控件id。
控制是否显示这个按钮。
点击全删的实现代码。
/*** 全删* @param view*/public void deleteAll(View view) {
HistoryHelper.deleteAllHistory();showListData();}
下面运行一下:
那么这个APP的第一版功能就差不多了,虽然很简单吧,但也是需要花点时间去做的。
再给App弄一个桌面图标吧。
如下图修改即可。
七、源码
GitHub源码地址如下:GoodTrash
CSDN资源地址:GoodTrash.rar
APK下载:GoodTrash1.0.apk
我是初学者-Study,山高水长,后会有期~