Android使用Realm数据库实现App中的收藏功能(代码详解)
作者:_彼岸雨敲窗_ 发布时间:2022-11-01 02:00:45
前 言
App数据持久化功能是每个App必不可少的功能,而Android最常用的数据持久化方式主要有以下的五种方式:
使用SharedPreferences存储数据;
文件存储数据;
SQLite数据库存储数据;
使用ContentProvider存储数据;
网络存储数据。
其中前四种都是缓存数据到本地,这篇主要讲的是使用第三种方式来实现App中的收藏功能,不过不用Android原生自带SQLite数据库来存储数据,而是使用第三方的Realm数据库来来存储数据。
Realm 本质上是一个嵌入式数据库,他并不是基于SQLite所构建的。它拥有自己的数据库存储引擎,可以高效且快速地完成数据库的构建操作。和SQLite不同的是,它允许你在持久层直接和数据对象工作。在它之上是一个函数式风格的查询api,众多的努力让它比传统的SQLite 操作更快 。
Realm不仅支持Android的接入,还支持IOS的接入。那么接下来就使用Realm数据库实现Android App中的收藏功能吧。
需求分析
要使用Realm数据库实现App中的收藏功能,需要实现以下几个功能和步骤:
在Android项目接入Realm数据库;
创建收藏数据库表;
实现对收藏数据库表进行增删查的操作;
数据库表增删查时界面实时渲染和更新。
接入Realm数据库
然后在AS的外层build.gradle里的buildscript.dependencies
添加Realm数据库相关的依赖
buildscript {
dependencies {
...
classpath "io.realm:realm-gradle-plugin:6.0.1"
}
}
然后在AS的内层build.gradle里添加Realm数据库相关的依赖
在顶部 apply plugin: ‘com.android.application' 下添加 apply plugin: ‘realm-android' 的声明,如下图
在定义的Application里初始化数据库相关的配置(包括数据库名称和版本号,具体代码看Demo源码)
/**
* 数据库相关的配置
*
* @param context
*/
private void initRealm(Context context) {
try {
Realm.init(context);
RealmConfiguration config = new RealmConfiguration.Builder()
.name(RealmConstant.REALM_DB_NAME)
.schemaVersion(RealmConstant.REALM_DB_VERSION)
.build();
Realm.setDefaultConfiguration(config);
} catch (Exception e) {
e.printStackTrace();
}
}
创建收藏数据库表
首先先创建一张收藏数据库表,代码如下:
/**
* 电影收藏数据库表名
*/
public class MovieCollectDBModel extends RealmObject {
// 影视id,主键
@Required
@PrimaryKey
@Index
private String movieId;
// 影视名称
@Required
private String movieName;
// 影视海报、封面
@Required
private String poster;
// 影视标签
@Required
private String movieLabel;
// 影视类型
@Required
private String videoType;
// 添加到数据的时间
@Required
private String createdTime;
// 以下省略字段的 set 和 get
}
该类继承于Realm的RealmObject类,其中字段movieId作为该表的主键,也是数据在表里的唯一性。
收藏数据库表的增删查
添加影视数据到到数据库的操作(增)
/**
* 添加收藏数据到本地数据库
*
* @param mvId
* @param mvName
* @param movieImg
* @param movieLabel
* @param videoType
*/
public void addCollectToDB(String mvId, String mvName, String movieImg, String movieLabel, String videoType) {
MovieCollectDBModel movieCollectDBModel = new MovieCollectDBModel();
movieCollectDBModel.setMovieId(mvId);
movieCollectDBModel.setMovieName(mvName);
movieCollectDBModel.setPoster(movieImg);
movieCollectDBModel.setMovieLabel(movieLabel);
movieCollectDBModel.setVideoType(videoType);
movieCollectDBModel.setCreatedTime(BaseUtil.getNowDateTimeFormat());
mTransaction = mRealm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
realm.copyToRealmOrUpdate(movieCollectDBModel);
}
}, new Realm.Transaction.OnSuccess() {
@Override
public void onSuccess() {
L.i("收藏数据添加成功!");
ToastUtil.showToast(String.format("%s 已收藏", mvName));
}
}, new Realm.Transaction.OnError() {
@Override
public void onError(Throwable error) {
L.i("收藏数据添加失败:" + error.toString());
ToastUtil.showToast(String.format("%s 收藏失败", mvName));
}
});
}
上面的代码是Realm数据插入数据到数据库的操作,这是一样异步插入数据的方式。在业务场景的需要,可以改新增和更新数据的插入方式,比如插入数据时如果数据库中已经存在了该数据则进行更新操作,否则进行了新增操作。
从数据库中删除一条影视数据的操作(删)
/**
* 通过键值对来删除指定收藏数据
*
* @param key
* @param value
*/
public void deleteByKeyCollectData(String key, String value) {
RealmResults<MovieCollectDBModel> movieCollectDBModels = mRealm.where(MovieCollectDBModel.class)
.equalTo(key, value)
.findAllAsync();
movieCollectDBModels.addChangeListener(new RealmChangeListener<RealmResults<MovieCollectDBModel>>() {
@Override
public void onChange(RealmResults<MovieCollectDBModel> movieCollectDBModels1) {
if (movieCollectDBModels1.isEmpty()) return;
mRealm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
movieCollectDBModels1.deleteFromRealm(0);
}
});
}
});
}
从数据库中删除全部影视数据的操作(删)
/**
* 清除全部收藏的数据库内容
*/
public void deleteAllCollectData() {
RealmResults<MovieCollectDBModel> movieCollectDBModels = mRealm.where(MovieCollectDBModel.class)
.findAll();
mRealm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
if (movieCollectDBModels.isEmpty()) {
ToastUtil.showToast("暂无收藏数据可删除");
return;
}
movieCollectDBModels.deleteAllFromRealm();
ToastUtil.showToast("收藏数据已全部清空");
}
});
}
从数据库中查询全部影视数据的操作(查)
/**
* 查询所有的收藏数据
*
* @param listener
*/
public void queryAllCollectData(RealmChangeListener<RealmResults<MovieCollectDBModel>> listener) {
RealmResults<MovieCollectDBModel> movieCollectDBModels = mRealm.where(MovieCollectDBModel.class)
.sort("createdTime", Sort.DESCENDING)
.findAllAsync();
movieCollectDBModels.addChangeListener(listener);
}
当前用户进入收藏界面的时候,需要从数据库中拉取全部的收藏数据,可以刚才添加收藏时间进行倒序排序。
数据库表增删查时界面的渲染和更新
当用户进入主页的时候,首次从网络获取数据,然后遍历一下网络获取数据是否已经有数据操作收藏数据库中,如果有的话则需要提示用户该数据已经被收藏并更改收藏图标。
public class MainActivity extends AppCompatActivity {
private MovieAdapter adapter;
private List<MovieDataModel.DataBean> mList = new ArrayList<>();
private RealmDBHelp mRealmDBHelp;
private boolean refreshType;
@BindView(R.id.mTitleBar)
TitleBar mTitleBar;
@BindView(R.id.homeMovieList)
RecyclerView homeMovieList;
@BindView(R.id.refreshLayout)
RefreshLayout refreshLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initRefresh();
}
private void initView() {
ButterKnife.bind(this);
mTitleBar.setOnTitleBarListener(new OnTitleBarListener() {
@Override
public void onLeftClick(View v) {
}
@Override
public void onTitleClick(View v) {
}
@Override
public void onRightClick(View v) {
// 跳转至我的收藏界面
startActivity(new Intent(MainActivity.this, MovieCollectActivity.class));
}
});
// 初始化本地数据库帮助类
mRealmDBHelp = new RealmDBHelp();
}
private void initRefresh() {
// 开启自动加载功能(非必须)
refreshLayout.setEnableAutoLoadMore(true);
refreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(@NonNull final RefreshLayout refreshLayout) {
refreshLayout.getLayout().postDelayed(new Runnable() {
@Override
public void run() {
refreshType = true;
// 加载数据
initData();
refreshLayout.finishRefresh();
refreshLayout.resetNoMoreData();//setNoMoreData(false);
}
}, 2000);
}
});
refreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore(@NonNull final RefreshLayout refreshLayout) {
refreshLayout.getLayout().postDelayed(new Runnable() {
@Override
public void run() {
refreshType = false;
ToastUtil.showToast("暂无更多的数据啦");
// 将不会再次触发加载更多事件
refreshLayout.finishLoadMoreWithNoMoreData();
refreshLayout.setEnableLoadMore(false);
refreshLayout.finishLoadMore();
}
}, 2000);
}
});
//触发自动刷新
refreshLayout.autoRefresh();
}
private void initData() {
// 模拟从网络获取到json数据 app\src\main\assets\movieData.json
String jsonData = BaseUtil.getAssetsJson(this, "movieData.json");
// L.i("jsonData:" + jsonData);
if (TextUtils.isEmpty(jsonData)) {
ToastUtil.showToast("Json数据为空");
return;
}
if (mList != null) mList.clear();
// 将json数据解析为Java实体对象
MovieDataModel movieDataModel = new Gson().fromJson(jsonData, MovieDataModel.class);
List<MovieDataModel.DataBean> dataBeanList = movieDataModel.getData();
for (MovieDataModel.DataBean dataBean : dataBeanList) {
MovieDataModel.DataBean data = new MovieDataModel.DataBean();
data.setMvid(dataBean.getMvid());
data.setName(dataBean.getName());
data.setPoster(dataBean.getPoster());
data.setUpdateStatus(dataBean.getUpdateStatus());
data.setTag(dataBean.getTag());
data.setVideo_type(dataBean.getVideo_type());
mList.add(data);
}
// 查询本地收藏数据库中是否存在收藏的数据(更改收藏图标用的)
queryAllCollectData();
try {
// 设置适配器
homeMovieList.setLayoutManager(new GridLayoutManager(this, 3));
adapter = new MovieAdapter(this, mList);
homeMovieList.setAdapter(adapter);
} catch (Exception e) {
e.printStackTrace();
}
// 设置条目的点击事件
adapter.setItemClikListener(new MovieAdapter.OnItemClikListener() {
@Override
public void onItemClik(View view, int position) {
String mvId = mList.get(position).getMvid();
String mvName = mList.get(position).getName();
String movieImg = mList.get(position).getPoster();
String movieTag = mList.get(position).getTag();
String videoType = mList.get(position).getVideo_type();
boolean isCollect = mList.get(position).isCollect();
if (isCollect) {
// 如果已经收藏了则清除该条收藏
// 根据Id来删除一条数据
mRealmDBHelp.deleteByKeyCollectData("movieId", mvId);
mList.get(position).setCollect(false);
ToastUtil.showToast(String.format("%s 已取消收藏", mvName));
} else {
// 添加收藏数据到本地数据库
mRealmDBHelp.addCollectToDB(mvId, mvName, movieImg, movieTag, videoType);
mList.get(position).setCollect(true);
}
// 通知适配器数据改变重新更新界面
adapter.notifyDataSetChanged();
}
@Override
public void onItemLongClik(View view, int position) {
}
});
}
/**
* 查询本地收藏数据库中是否存在收藏的数据(更改收藏图标用的)
*/
private void queryAllCollectData() {
mRealmDBHelp.queryAllCollectData(new RealmChangeListener<RealmResults<MovieCollectDBModel>>() {
@Override
public void onChange(RealmResults<MovieCollectDBModel> movieCollectDBModels) {
if (movieCollectDBModels.isEmpty()) {
return;
}
for (MovieCollectDBModel movieCollectDBModel : movieCollectDBModels) {
for (int i = 0; i < mList.size(); i++) {
if (mList.get(i).getMvid().equals(movieCollectDBModel.getMovieId())) {
mList.get(i).setCollect(true);
break;
}
}
}
}
});
}
@Override
protected void onStop() {
super.onStop();
mRealmDBHelp.closeTransaction();
}
@Override
protected void onDestroy() {
super.onDestroy();
mRealmDBHelp.close();
}
}
收藏界面的代码,包括查询和删除操作。
public class MovieCollectActivity extends AppCompatActivity {
private RealmDBHelp mRealmDBHelp;
private List<MovieCollectModel> mList = new ArrayList<>();
private MovieCollectAdapter adapter;
private boolean refreshType;
@BindView(R.id.mTitleBar)
TitleBar mTitleBar;
@BindView(R.id.movieCollectList)
RecyclerView movieCollectList;
@BindView(R.id.empty_view)
RelativeLayout empty_view;
@BindView(R.id.refreshLayout)
RefreshLayout refreshLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_movie_collect);
initView();
initRefresh();
}
private void initView() {
ButterKnife.bind(this);
mTitleBar.setOnTitleBarListener(new OnTitleBarListener() {
@Override
public void onLeftClick(View v) {
finish();
}
@Override
public void onTitleClick(View v) {
}
@Override
public void onRightClick(View v) {
deleteRealmDB();
}
});
mRealmDBHelp = new RealmDBHelp();
}
private void initRefresh() {
// 开启自动加载功能(非必须)
refreshLayout.setEnableAutoLoadMore(true);
refreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(@NonNull final RefreshLayout refreshLayout) {
refreshLayout.getLayout().postDelayed(new Runnable() {
@Override
public void run() {
refreshType = true;
// 加载数据
initData();
refreshLayout.finishRefresh();
refreshLayout.resetNoMoreData();//setNoMoreData(false);
}
}, 2000);
}
});
refreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore(@NonNull final RefreshLayout refreshLayout) {
refreshLayout.getLayout().postDelayed(new Runnable() {
@Override
public void run() {
refreshType = false;
ToastUtil.showToast("暂无更多的数据啦");
// 将不会再次触发加载更多事件
refreshLayout.finishLoadMoreWithNoMoreData();
refreshLayout.setEnableLoadMore(false);
refreshLayout.finishLoadMore();
}
}, 2000);
}
});
//触发自动刷新
refreshLayout.autoRefresh();
}
private void initData() {
queryAllCollectData();
}
/**
* 查询本地收藏数据库中所有的数据
*/
private void queryAllCollectData() {
mRealmDBHelp.queryAllCollectData(new RealmChangeListener<RealmResults<MovieCollectDBModel>>() {
@Override
public void onChange(RealmResults<MovieCollectDBModel> movieCollectDBModels) {
if (movieCollectDBModels.isEmpty()) {
return;
}
if (mList != null) mList.clear();
for (MovieCollectDBModel movieCollectDBModel : movieCollectDBModels) {
MovieCollectModel data = new MovieCollectModel();
data.setMovieId(movieCollectDBModel.getMovieId());
data.setMovieName(movieCollectDBModel.getMovieName());
data.setPoster(movieCollectDBModel.getPoster());
data.setMovieTag(movieCollectDBModel.getMovieLabel());
data.setVideoType(movieCollectDBModel.getVideoType());
data.setCreatedTime(movieCollectDBModel.getCreatedTime());
mList.add(data);
}
runOnUiThread(new Runnable() {
@Override
public void run() {
parsingMovieList();
}
});
}
});
}
private void parsingMovieList() {
movieCollectList.setLayoutManager(new GridLayoutManager(this, 3));
adapter = new MovieCollectAdapter(this, mList);
movieCollectList.setAdapter(adapter);
if (mList.isEmpty()) {
empty_view.setVisibility(View.VISIBLE);
movieCollectList.setVisibility(View.GONE);
} else {
movieCollectList.setVisibility(View.VISIBLE);
empty_view.setVisibility(View.GONE);
}
adapter.setItemClikListener(new MovieCollectAdapter.OnItemClikListener() {
@Override
public void onItemClik(View view, int position) {
// 根据Id来删除一条数据
deleteByKeyCollectData(position);
}
@Override
public void onItemLongClik(View view, int position) {
}
});
}
/**
* 根据Id来删除一条数据
*
* @param position
*/
private void deleteByKeyCollectData(int position) {
IOSMsgDialog.Companion.init(getSupportFragmentManager())
.setTitle("清除影视提示")
.setMessage("是否要清除该条影视收藏的数据?")
.setAnimStyle(R.style.LDialogScaleAnimation)
.setNegativeButton("否", new View.OnClickListener() {
@Override
public void onClick(View v) {
}
})
.setPositiveButton("是", new View.OnClickListener() {
@Override
public void onClick(View v) {
// 根据Id来删除一条数据
mRealmDBHelp.deleteByKeyCollectData("movieId", mList.get(position).getMovieId());
mList.remove(position);
adapter.notifyDataSetChanged();
}
}, Color.RED)
.setDismissListener(new OnDialogDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
}
}).setCancelableOutside(true).show();
}
/**
* 删除本地数据库中全部的收藏数据
*/
private void deleteRealmDB() {
IOSMsgDialog.Companion.init(getSupportFragmentManager())
.setTitle("清空全部收藏数据提示")
.setMessage("是否要立即清空全部我的收藏的数据?如果要清除单条数据的话请点击单条数据列表。")
.setAnimStyle(R.style.LDialogScaleAnimation)
.setNegativeButton("否", new View.OnClickListener() {
@Override
public void onClick(View v) {
}
})
.setPositiveButton("是", new View.OnClickListener() {
@Override
public void onClick(View v) {
// 清除全部收藏的数据库内容
mRealmDBHelp.deleteAllCollectData();
mList.clear();
empty_view.setVisibility(View.VISIBLE);
movieCollectList.setVisibility(View.GONE);
adapter.notifyDataSetChanged();
}
}, Color.RED)
.setDismissListener(new OnDialogDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
}
}).setCancelableOutside(true).show();
}
@Override
protected void onDestroy() {
super.onDestroy();
mRealmDBHelp.close();
}
}
界面运行效果图如下:
apk安装包下载体验地址:
可以扫描以下二维码进行下载安装,或者点击以下链接 http://app.fukaimei.top/MovieCollect 进行下载安装体验。
来源:https://blog.csdn.net/fukaimei/article/details/105089870


猜你喜欢
- [ThreadStatic] static char[]
- 一、DES加密和解密package com.itjh.javaUtil;import java.io.UnsupportedEncoding
- 页面:上传文件时的关键词:enctype="multipart/form-data"<%@ page langua
- 1.什么是线程安全性当多个线程访问某个类时,不管运行时环境采用何种调用方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或
- 本文实例为大家分享了Unity实现ScrollView滑动吸附的具体代码,供大家参考,具体内容如下最近在做一个展示模块的时候遇到了一个需要实
- 应用场景:在Android开发过程中,有时需要调用手机自身设备的功能,上篇文章主要侧重摄像头拍照功能的调用。本篇文章将综合实现拍照与视频的操
- 主要是因为GZipStream的构造函数中第一个需要传入一个Stream,第二个是指定操作方式:压缩还是解压缩。当时的疑问点主要有:1.我传
- SWF Tools 是一组用来处理 Flash 的 swf 文件的工具包,包括:1. 合并工具 swfcombine2. 抽取工具 swfe
- SpringMVC文件上传中要解决的问题一、中文文件名编码问题通过过滤器解决二、文件位置存储问题放在当前项目下,作为静态资源,这样可以通过U
- 目录一.什么是负载均衡二.负载均衡的简单分类三.为什么需要做负载均衡四.springCloud如何开启负载均衡五.IRule1.Random
- 本文实例讲述了WPF中的ListBox实现按块显示元素的方法。分享给大家供大家参考,具体如下:注意:需要设置ListBox的属性 Scrol
- Android插件开启对新Api的支持这一天小王导入了一个库,上线之后直接崩了一大片? 找到其中的问题:什么鬼哦?安卓8.0一下无法使用?
- 在C#的List集合操作中,有时候需要查找到List集合中的最大值,此时可以使用List集合的扩展方法Max方法,Max方法有2种形式,一种
- 栈(Stack)和队列是非常类似的一个容器,只是栈是一个后进先出(LIFO)的容器。栈用Push()方法在栈中添加元素,用Pop()方法获取
- 这篇文章主要介绍了Spring Batch批处理框架使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需
- 本文实例分析了win7中C#的winForm编程使用savefiledialog不能弹出保存窗体的解决方法。分享给大家供大家参考。具体分析如
- 顺序结构按照代码书写的顺序一行一行执行分支结构if 语句基本语法形式:if(布尔表达式){ //条件满足时执行代码
- 安装方式:使用vs自带的nuget管理工具,搜索AutoMapper ,选择第一个安装到你的项目即可。先说说DTODTO是个什么东东?DTO
- 前言在实际工作中,重处理是一个非常常见的场景,比如:发送消息失败。调用远程服务失败。争抢锁失败。这些错误可能是因为网络波动造成的,等待过后重
- 使用WPF做的一个简单的操作文件的demo,包括复制和移动文件夹,核心思想就是使用递归,如果只是移动或者复制单一文件,直接使用File.Co