SQLite读取仅返回最后元素,Firestore位置对比异常求助
问题分析与解决方案
你遇到的核心问题是全局变量被循环覆盖,导致仅保留SQLite数据库中最后一条收藏位置的数据。我们来拆解问题并修复它:
问题根源
在listFavoriteLocation()方法的最后,你用一个for循环把全局变量List_FAVCurrentLocationLAT和List_FAVCurrentLocationLONG反复赋值为每个收藏位置的经纬度:
for (DataModel mo:data ) { this.List_FAVCurrentLocationLAT = mo.getFAVCurrentLocationLAT(); this.List_FAVCurrentLocationLONG = mo.getFAVCurrentLocationLONG(); // ...日志输出 }
循环结束后,这两个全局变量只会保存最后一次循环的赋值结果(也就是最后一条收藏位置)。当你在readFirestore()的文档循环里调用listFavoriteLocation()时,拿到的自然永远是最后一条数据。
修复方案
我们需要直接使用listFavoriteLocation()返回的完整收藏位置列表,而不是依赖全局变量。同时优化逻辑,避免重复读取SQLite数据库:
- 先缓存所有收藏位置:在Firestore查询成功后,先一次性获取所有收藏位置,不要在每个文档循环里重复调用
listFavoriteLocation() - 遍历每个收藏位置与Firestore位置对比:对每个Firestore的活动位置,遍历所有收藏位置计算距离,符合条件就写入数据库
修改后的readFirestore()代码如下:
public void readFirestore() { FirebaseFirestore db = FirebaseFirestore.getInstance(); // 先获取所有收藏位置,缓存起来 List<DataModel> favoriteLocations = listFavoriteLocation(); db.collection("campaigns") .get() .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() { @Override public void onComplete(@NonNull Task<QuerySnapshot> task) { if (task.isSuccessful() && task.getResult() != null) { for (QueryDocumentSnapshot document : task.getResult()) { String name = document.getString("name"); String cityLAT = document.getString("cityLAT"); String cityLONG = document.getString("cityLONG"); String campaignStartDate = document.getString("campaignStartDate"); String campaignEndDate = document.getString("campaignEndDate"); // 遍历所有收藏位置,逐个对比距离 for (DataModel favLoc : favoriteLocations) { String favLatStr = favLoc.getFAVCurrentLocationLAT(); String favLongStr = favLoc.getFAVCurrentLocationLONG(); try { double favLat = Double.parseDouble(favLatStr); double favLong = Double.parseDouble(favLongStr); double campaignLat = Double.parseDouble(cityLAT); double campaignLong = Double.parseDouble(cityLONG); // 计算距离(保留你的原有计算逻辑) double theta = campaignLong - favLong; double dist = Math.sin(Math.toRadians(favLat)) * Math.sin(Math.toRadians(campaignLat)) + Math.cos(Math.toRadians(favLat)) * Math.cos(Math.toRadians(campaignLat)) * Math.cos(Math.toRadians(theta)); dist = Math.acos(dist); dist = Math.toDegrees(dist); dist = dist * 60 * 1.1515; dist = dist * 1.609344; if (dist <= 0.5) { // 500米以内 // 建议使用参数化SQL防止注入 ContentValues values = new ContentValues(); values.put("FAVCampaignName", name); values.put("FAVCampaigncampaignStartDate", campaignStartDate); values.put("FAVCampaigncampaignEndDate", campaignEndDate); // 使用replace代替execSQL更安全 SQLITEDATABASEFavCampaign.replace("myTable3", null, values); Log.i("helloname","符合条件的活动:"+name); } } catch (NumberFormatException e) { // 处理字符串转数字失败的情况 Log.e("LocationError", "经纬度格式错误:" + e.getMessage()); } } } Toast.makeText(CampaignActivity.this,"完成位置匹配", Toast.LENGTH_SHORT).show(); } else { Log.e("FirestoreError", "读取数据失败:" + task.getException()); Toast.makeText(CampaignActivity.this,"读取数据失败", Toast.LENGTH_SHORT).show(); } } }); }
同时,你可以移除listFavoriteLocation()里的全局变量赋值循环,因为已经不需要了:
public List<DataModel> listFavoriteLocation(){ db = new DatabaseHelper(this); SQLiteDatabase mydb = db.getWritableDatabase(); List<DataModel> data=new ArrayList<>(); Cursor csr = mydb.rawQuery("select * from "+TABLE+" ;",null); DataModel dataModel = null; while (csr.moveToNext()) { dataModel= new DataModel(); String FAVCurrentLocationLAT = csr.getString(csr.getColumnIndexOrThrow("FAVCurrentLocationLAT")); String FAVCurrentLocationLONG = csr.getString(csr.getColumnIndexOrThrow("FAVCurrentLocationLONG")); dataModel.setFAVCurrentLocationLAT(FAVCurrentLocationLAT); dataModel.setFAVCurrentLocationLONG(FAVCurrentLocationLONG); data.add(dataModel); } csr.close(); // 记得关闭Cursor,避免资源泄漏 mydb.close(); // 关闭数据库连接 // 移除这个全局变量赋值的循环 /*for (DataModel mo:data ) { this.List_FAVCurrentLocationLAT = mo.getFAVCurrentLocationLAT(); this.List_FAVCurrentLocationLONG = mo.getFAVCurrentLocationLONG(); Log.i("helloLAT",""+List_FAVCurrentLocationLAT); Log.i("helloLONG",""+List_FAVCurrentLocationLONG); }*/ return data; }
额外优化建议
- 关闭Cursor和数据库连接:在
listFavoriteLocation()里记得关闭Cursor和SQLiteDatabase,避免资源泄漏 - 参数化SQL语句:使用
ContentValues和replace()方法代替直接拼接SQL字符串,防止SQL注入攻击 - 异常处理:添加
NumberFormatException的捕获,处理经纬度字符串格式错误的情况 - Toast时机调整:把Toast放在Firestore回调内部,确保操作完成后再提示用户
内容的提问来源于stack exchange,提问作者user11416323
相关产品推荐
相关产品推荐

