java - 条件说列表's 不是 .equal(),即使它们是相同的
问题描述
新列表来自 SQLite 数据库。
oldList,通过android提供的@Embedded接口存储JOINED表的第一行和第二行。
填充它的查询应该只获取那 2 行,因为它们符合特定的 WHERE 子句。
在右表中执行事务时,例如插入外键尚未“指向”(?)的第 3 行指向左表,并且前 2 行(连接行)没有更改,观察者得到调用,并给了我相同的 2 行,但 java 代码告诉我它们是不同的。
可以理解,观察者给我的响应好像数据发生了变化,因为连接表确实整体发生了变化,并且 SQL 查询需要检查插入的第三行是否符合施加的条件(它确实不是),但不清楚的是为什么 java 代码获取相同的 2 行,并告诉我它们与刚才存储的相同 2 行不同。
起初我认为这与列表是 .get() 来自 HashMap<K,V> 的事实有关,也可能是这样。
@Override
protected void onFound(List<X> xes, int liveDataId) {
List<X> xOldList = listHashMap.get(liveDataId);
if (xOldList == null) {
Log.d(TAG, "onFound: list not found on HasMap adding response");
listHashMap.put(liveDataId, xes);
if (listHashMap.size() == sources.size()) {
Log.d(TAG, "onFound: HashMap complete, converting HasMap");
ends(listHashMap);
}
} else {
if (!xOldList.equals(xes)) {
Log.d(TAG, "onFound: oldList not the same as new one!");
if (xes.size() > 0) {
Log.d(TAG, "onFound: new list size greater than 0");
synchronizedSubmitList(xes, xOldList, liveDataId);
} else {
Log.d(TAG, "onFound: newList size is zero");
listHashMap.put(liveDataId, xes);
ends(listHashMap);
}
}
}
}
日志
@Embedded Pojo
公共类 PieceQuantityAndPiece 实现 EntityInterface { private static final String TAG = "PieceQuantityAndPiece";
@Embedded
public PieceQuantity pieceQuantity;
@Relation(
parentColumn = "child_piece_id",
entityColumn = "piece_id"
)
public Piece piece;
public PieceQuantityAndPiece() {
}
}
对左表施加的查询
@Transaction
@Query("SELECT * FROM piece_quantity_table WHERE folder_id = :folderId")
LiveData<List<PieceQuantityAndPiece>> getPieceQuantityAndPiecesAtFolder(int folderId);
在触发 onChanged() 的右表上执行的事务:
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Piece piece);
@Query("UPDATE piece_table SET _total = :total, _date_of_last_edit = :lastEdited WHERE piece_id = :pieceId")
void updatePieceTotalAt(int total, long lastEdited, int pieceId);
解决方案
我设法通过迭代它们的单独元素来比较两个列表的相等性,然后,通过使用我在类中闲逛的 2 个功能接口,如果它们的 Id 相同,则返回一个布尔值,如果一个字段另一份的兴趣(内容)也相同;我分别比较了这两个项目。
这里的一线希望是,关于迭代这么多的优化程度,旧列表和新列表之间的大小差异最多一次始终为 1 项,但如果考虑到我会提出的情况删除更多项目的选项,一切仍然在后台发生,而且我相信,还有足够的条款需要满足,以确保做绝对必要的事情。
项目的顺序并不是真正的问题,因为它们总是会以相同的顺序被获取,如果它们是无序的,列表仍然会直接进入一个列表区分器类,该类可以干净地管理它们。此外,如果内容的顺序不同,则有 100% 的可能性是因为无论如何某些东西确实发生了变化。
至于调试,他们的日志似乎更有帮助,可能是因为我对调试的经验不够。
日志显示,每个字段中的项目确实相同,但它们的哈希码不同,这很明显,LiveData 没有内存,只是 set() 和 fin。
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
即使没有声明该 T 值,new
它仍然“指向”其原始来源吗?我怀疑它的来源是 SQLite。
即使通过将每个元素独立地类型转换为它们各自的子类型,它们仍然不同。
但是深入 List.equal(List) 方法,我发现我的对象永远不会相等,因为:
public boolean equals(Object obj) {
return (this == obj);
}
所以那是一个== ...并且他们总是有不同的哈希码...
这就是我开始一一比较它们的领域(它们是相同的),以及它们的原语最终可比较的地方。
拥有所有 SQLite 实体的超类型接口,我可以比较它们的 id 和它们最重要的字段(在本例中为 last_date_edited),并使用前面提到的 2 个函数接口,我做了一个子句条件:
private boolean verifyEquality(
List<X> oldList, List<X> newList,
@NonNull ListDifferentiator4.AreIdsTheSame<X> areIdsTheSame,
@NonNull ListDifferentiator4.AreContentsTheSame<X> areContentsTheSame
) {
for (int i = 0; i < oldList.size(); i++) {
X oldX = oldList.get(i);
X newX = newList.get(i);
if (!areIdsTheSame.areIdsTheSame(newX, oldX) || !areContentsTheSame.areContentsTheSame(newX, oldX)) {
Log.d(TAG, "verifyEquality: items are different");
return false;
}
}
Log.d(TAG, "verifyEquality: Lists are the same");
return true;
}
onFound 方法()...
@Override
protected void onFound(List<X> xes, int liveDataId) {
List<X> xOldList = listHashMap.get(liveDataId);
if (xOldList == null) {
Log.d(TAG, "onFound: list not found on HasMap adding response");
listHashMap.put(liveDataId, xes);
if (listHashMap.size() == sources.size()) {
Log.d(TAG, "onFound: HashMap complete, converting HasMap");
convertAndSet(listHashMap);
}
} else {
Log.d(TAG, "onFound: livedataId is: " + liveDataId);
if (xOldList.size() == xes.size()) {
Log.d(TAG, "onFound: Lists are the same size!");
if (xOldList.size() != 0) {
Log.d(TAG, "onFound: sizes are not 0");
boolean areEqual = verifyEquality(
xOldList,
xes,
areIdsTheSame,
areContentsTheSame
);
Log.println(Log.ASSERT, TAG, "onFound: are equal boolean 1st is: " + areEqual);
Log.d(TAG, "onFound: list size is: " + xes.size());
if (!areEqual) {
Log.println(Log.ASSERT, TAG, "onFound: oldList not the same as new one!");
listHashMap.put(liveDataId, xes);
convertAndSet(listHashMap);
} else {
Log.println(Log.ASSERT, TAG, "onFound: LISTS WHERE THE SAME!");
}
}
} else {
Log.println(Log.ASSERT, TAG, "onFound: Lists are not the same size");
if (xes.size() > 0) {
Log.d(TAG, "onFound: new list size greater than 0");
synchronizedSubmitList(xes, xOldList, liveDataId);
} else {
Log.d(TAG, "onFound: newList size is zero");
listHashMap.put(liveDataId, xes);
convertAndSet(listHashMap);
}
}
}
}
使用列表微分器接口初始化的整个类...
liveDataListSource = new SourceMergingLiveData<>(
(newX, oldX) -> newX.getPrimaryKey() == oldX.getPrimaryKey(),
(newX, oldX) -> newX.getFieldElement().equals(oldX.getFieldElement())
);
日志...
作为最后的想法,这被证明是一个实例,其中 2 个完全相等的对象每次都有不同的哈希码,这与这个答案所说的相反。
推荐阅读
- laravel - Atomic operation with consistent data in laravel
- php - Check if the time is more than 24h and show it
- android - Getting NumberFormatException in onSavedInstanceState() method
- android - Adding function to foreground service lifecycle methods can create an issue? Is this best practise?
- javascript - HTML/CSS:Firefox 中的网站不显示背景,Chrome 按预期显示
- python - Python在循环中替换文本文件的字符串
- python - 当名称中包含连字符时获取包版本
- docker - The input device is not a TTY when I'm using docker?
- sql - subquery must return only one column , how can i fix it
- swift - Swift function returns Void return type from other function