BasicSample项目说明
private void subscribeUi(LiveData<List<ProductEntity>> liveData) {
// Update the list when the data changes
liveData.observe(getViewLifecycleOwner(), myProducts -> {
if (myProducts != null) {
mBinding.setIsLoading(false);
mProductAdapter.setProductList(myProducts);
} else {
mBinding.setIsLoading(true);
}
// espresso does not know how to wait for data binding's loop so we execute changes
// sync.
mBinding.executePendingBindings();
});
}
public ProductListViewModel(@NonNull Application application,
@NonNull SavedStateHandle savedStateHandle) {
super(application);
mSavedStateHandler = savedStateHandle; mRepository = ((BasicApp) application).getRepository(); // Use the savedStateHandle.getLiveData() as the input to switchMap,
// allowing us to recalculate what LiveData to get from the DataRepository
// based on what query the user has entered
//LiveData<String> query,数据发生变化,就会触发执行向数据库查询的动作,将查询结果添加到已有的LiveData中
mProducts = Transformations.switchMap(
savedStateHandle.getLiveData("QUERY", null),
(Function<CharSequence, LiveData<List<ProductEntity>>>) query -> {
if (TextUtils.isEmpty(query)) {
return mRepository.getProducts();
}
return mRepository.searchProducts("*" + query + "*");
});
} public void setQuery(CharSequence query) {
// Save the user's query into the SavedStateHandle.
// This ensures that we retain the value across process death
// and is used as the input into the Transformations.switchMap above
//保存在SavedStateHandler的数据,即使进程销毁重建都会存在
mSavedStateHandler.set(QUERY_KEY, query);
}
实际的数据获取实现,封装在DataRepository mRepository;中。
public void setProductList(final List<? extends Product> productList) {
if (mProductList == null) {
mProductList = productList;
notifyItemRangeInserted(0, productList.size());
} else {
DiffUtil.DiffResult result = DiffUtil.calculateDiff(new DiffUtil.Callback() {
@Override
public int getOldListSize() {
return mProductList.size();
}
@Override
public int getNewListSize() {
return productList.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return mProductList.get(oldItemPosition).getId() ==
productList.get(newItemPosition).getId();
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
Product newProduct = productList.get(newItemPosition);
Product oldProduct = mProductList.get(oldItemPosition);
return newProduct.getId() == oldProduct.getId()
&& TextUtils.equals(newProduct.getDescription(), oldProduct.getDescription())
&& TextUtils.equals(newProduct.getName(), oldProduct.getName())
&& newProduct.getPrice() == oldProduct.getPrice();
}
});
mProductList = productList;
result.dispatchUpdatesTo(this);
}
}
public abstract static class Callback {
/**
* 旧数据 size
*/
public abstract int getOldListSize();
/**
* 新数据 size
*/
public abstract int getNewListSize();
/**
* DiffUtil 调用判断两个 itemview 对应的数据对象是否一样. 由于 DiffUtil 是对两个不同数据集合的对比, 所以比较对象引用肯定是不行的, 一般会使用 id 等具有唯一性的字段进行比较.
* @param oldItemPosition 旧数据集合中的下标
* @param newItemPosition 新数据集合中的下标
* @return True 返回 true 即判断两个对象相等, 反之则是不同的两个对象.
*/
public abstract boolean areItemsTheSame(int oldItemPosition, int newItemPosition);
/**
* Diffutil 调用判断两个相同对象之间的数据是否不同. 此方法仅会在 areItemsTheSame() 返回 true 的情况下被调用.
*
* @param oldItemPosition 旧数据集合中的下标
* @param newItemPosition 新数据集合中用以替换旧数据集合数据项的下标
* @return True 返回 true 代表 两个对象的数据相同, 反之则有差别.
*/
public abstract boolean areContentsTheSame(int oldItemPosition, int newItemPosition);
/**
* 当 areItemsTheSame() 返回true areContentsTheSame() 返回 false 时, 此方法将被调用, 来完成局部刷新功能.
*/
@Nullable
public Object getChangePayload(int oldItemPosition, int newItemPosition);
}
DataBinding,数据绑定
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable name="product"
type="com.example.android.persistence.model.Product"/>
<variable name="callback"
type="com.example.android.persistence.ui.ProductClickCallback"/>
</data> <androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/product_item_min_height"
android:onClick="@{() -> callback.onClick(product)}"
android:orientation="horizontal"
android:layout_marginStart="@dimen/item_horizontal_margin"
android:layout_marginEnd="@dimen/item_horizontal_margin"
app:cardUseCompatPadding="true"> <RelativeLayout
android:layout_marginStart="@dimen/item_horizontal_margin"
android:layout_marginEnd="@dimen/item_horizontal_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"> <TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/cd_product_name"
android:text="@{product.name}"/> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginEnd="5dp"
android:text="@{@string/product_price(product.price)}"/> <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/name"
android:text="@{product.description}"/>
</RelativeLayout> </androidx.cardview.widget.CardView>
</layout>
@Override
@NonNull
public ProductViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ProductItemBinding binding = DataBindingUtil
.inflate(LayoutInflater.from(parent.getContext()), R.layout.product_item,
parent, false);
binding.setCallback(mProductClickCallback);
return new ProductViewHolder(binding);
} @Override
public void onBindViewHolder(@NonNull ProductViewHolder holder, int position) {
holder.binding.setProduct(mProductList.get(position));
//立即刷新数据
holder.binding.executePendingBindings();
}
=================================================================================================================================
@Dao
public interface CommentDao {
@Query("SELECT * FROM comments where productId = :productId")
LiveData<List<CommentEntity>> loadComments(int productId); @Query("SELECT * FROM comments where productId = :productId")
List<CommentEntity> loadCommentsSync(int productId); @Insert(onConflict = OnConflictStrategy.REPLACE)
void insertAll(List<CommentEntity> comments);
}
public class Converters {
@TypeConverter
public static Date fromTimestamp(Long value) {
return value == null ? null : new Date(value);
}
@TypeConverter
public static Long dateToTimestamp(Date date) {
return date == null ? null : date.getTime();
}
}
public static AppDatabase getInstance(final Context context, final AppExecutors executors) {
if (sInstance == null) {
synchronized (AppDatabase.class) {
if (sInstance == null) {
sInstance = buildDatabase(context.getApplicationContext(), executors);
sInstance.updateDatabaseCreated(context.getApplicationContext());
}
}
}
return sInstance;
}
/**
* Build the database. {@link Builder#build()} only sets up the database configuration and
* creates a new instance of the database.
* The SQLite database is only created when it's accessed for the first time.
*/
private static AppDatabase buildDatabase(final Context appContext,
final AppExecutors executors) {
return Room.databaseBuilder(appContext, AppDatabase.class, DATABASE_NAME)
.addCallback(new Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
executors.diskIO().execute(() -> {
// Add a delay to simulate a long-running operation
addDelay();
// Generate the data for pre-population
AppDatabase database = AppDatabase.getInstance(appContext, executors);
List<ProductEntity> products = DataGenerator.generateProducts();
List<CommentEntity> comments =
DataGenerator.generateCommentsForProducts(products); insertData(database, products, comments);
// notify that the database was created and it's ready to be used
database.setDatabaseCreated();
});
}
})
.addMigrations(MIGRATION_1_2)
.build();
}
private static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("CREATE VIRTUAL TABLE IF NOT EXISTS `productsFts` USING FTS4("
+ "`name` TEXT, `description` TEXT, content=`products`)");
database.execSQL("INSERT INTO productsFts (`rowid`, `name`, `description`) "
+ "SELECT `id`, `name`, `description` FROM products");
}
};
BasicSample项目说明的更多相关文章
- Android开发学习总结(三)——appcompat_v7项目说明
一.appcompat_v7项目说明 今天来说一下appcompat_v7项目的问题,使用eclipse创建Android项目时,发现project列表中会多创建出一个appcompat_v7项目,这 ...
- VUE (vue-cli)脚手架项目说明
1. 概述 1.1 说明 使用vue-cli快速创建的vue项目目录如下: build -- webpack相关配置以及服务启动文件,配置多依赖于下边的config文件夹中内容 config -- ...
- 基于 Vue+Mint-ui 的 Mobile-h5 的项目说明
Vue作为前端三大框架之一,其已经悄然成为主流,学会用vue相关技术来开发项目会相当轻松. 对于还没学习或者还没用过vue的初学者,基础知识这里不作详解,推荐先去相关官网,学习一下vue相关的基础知识 ...
- Django---图书管理系统,一对多(外键设置),__str__和__repr__的区别,进阶版项目说明简介.模版语言if ... else ..endif
Django---图书管理系统,一对多(外键设置),__str__和__repr__的区别,进阶版项目说明简介.模版语言if ... else ..endif 一丶__str__ 和 __repr__ ...
- day01-家具网购项目说明
家具网购项目说明 1.项目前置技术 Java基础 正则表达式 Mysql JDBC 数据库连接池技术 满汉楼项目(包括框架图) JavaWeb 2.相关说明 这里先使用原生的servlet/过滤器,后 ...
- TchApp项目说明
概述 使用Web做UI,csharp编程,构建跨平台桌面软件,项目目标是打造一个框架,做完相关的基础设施,让使用者能够只关注业务开发,而不需要重新构建基础设施. 项目应该包括:窗口管理API,跨语言( ...
- Android开发之搜Ya项目说明(3)
项目 搜芽移动client ----seller,app,base三个包的简单说明 作者 曾金龙 Tel:18664312687 QQ :470910357@qq.com 时间 2014-10-14 ...
- 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十║Vue基础终篇:传值+组件+项目说明
缘起 新的一天又开始啦,大家也应该看到我的标题了,是滴,Vue基础基本就到这里了,咱们回头看看这一路,如果你都看了,并且都会写了,那么现在你就可以自己写一个Demo了,如果再了解一点路由,ajax请求 ...
- net core体系-web应用程序-4asp.net core2.0 项目实战(任务管理系统)-1项目说明
https://www.bug2048.com/netcore20180313/ 最近公司的一个小项目尝试使用 .net core作为服务端进行开发,并顺利上线运行了一段时间,整体效果还是比较满意的. ...
- net core体系-web应用程序-4asp.net core2.0 项目实战(1)-2项目说明和源码下载
本文目录1. 摘要2. Window下运行 3.linux下运行4. 开发记录5. 总结 1.概要 写<Asp.Net Core 2.0 项目实战>系列断断续续已经很长时间了,期间很多朋友 ...
随机推荐
- 9 时序数据库M3DB架构与原理
一.M3DB介绍 M3DB是Uber开源的一款分布式时序数据库,已在Uber内部使用多年.M3DB有以下特性: 分布式的时序数据库,可以水平扩展存储. 支持Pormetheus的查询语言PromQL, ...
- Spring Cloud 系列:Seata 中TCC模式具体实现
概述 https://seata.io/zh-cn/docs/dev/mode/tcc-mode https://seata.io/zh-cn/docs/user/mode/tcc TCC模式与AT模 ...
- 《OnJava》——11内部类
内部类 利用内部类,可以将逻辑上存在关联的类组织在一起,而且可以控制一个类在另一个类中的可见性. 内部类和组合不同,内部类是一种代码隐藏机制:将代码放在其他类的内部. 11.1 创建内部类 创建内部类 ...
- 银河麒麟安装多版本gcc的方式方法
银河麒麟安装多版本gcc的方式方法 背景 最近想升级一下gcc 但是发现自己编译的话非常麻烦 记得之前CentOS7的时候有一个scl的处理 发现CentOS8 已经没有scl的仓库了 简单验证了一下 ...
- [转帖]使用 TiUP cluster 在单机上安装TiDB
https://zhuanlan.zhihu.com/p/369414808 TiUP 是 TiDB 4.0 版本引入的集群运维工具,TiUP cluster 是 TiUP 提供的使用 Golan ...
- [转帖]goproxy 使用说明
Go 版本要求 建议您使用 Go 1.13 及以上版本, 可以在这里下载最新的 Go 稳定版本. 配置 Goproxy 环境变量 Bash (Linux or macOS) export GOPROX ...
- 我们开源了一个轻量的 Web IDE UI 框架
我们开源了一个轻量的 Web IDE UI 框架 Molecule 一个轻量的 Web IDE UI 框架 简介 Molecule 是一个受 VS Code 启发,使用 React.js 构建的 We ...
- Mybatis 拦截器实现单数据源内多数据库切换 | 京东物流技术团队
物流的分拣业务在某些分拣场地只有一个数据源,因为数据量比较大,将所有数据存在一张表内查询速度慢,也为了做不同设备数据的分库管理,便在这个数据源内创建了多个不同库名但表完全相同的数据库,如下图所示: 现 ...
- ChatGPT背后的AI背景、技术门道和商业应用(万字长文,建议收藏)
作者:京东科技 李俊兵 各位看官好,我是球神(江湖代号). 自去年11月30日ChatGPT问世以来,迅速爆火出圈. 起初我依然以为这是和当年Transformer, Bert一样的"热点& ...
- elementui出现展开后子菜单宽度多出1px问题
添加 就可以解决了 .el-menu { border-right-width: 0; } <template> <div class="compen-left-men&q ...