|
|
@@ -85,6 +85,8 @@ public class MainAbilitySlice extends AbilitySlice {
|
|
|
private boolean hasMore = true; // 是否还有更多数据
|
|
|
private int filterType = 2; // 筛选类型:2=全部,1=推荐
|
|
|
private List<ParkNearRes> parkingList = new ArrayList<>(); // 停车场列表数据
|
|
|
+ private long lastLoadTime = 0; // 上次加载时间,用于防抖
|
|
|
+ private static final long LOAD_THROTTLE_MS = 500; // 防抖时间间隔(毫秒)
|
|
|
|
|
|
DataAbilityHelper dataAbilityHelper;
|
|
|
IDataAbilityObserver dataAbilityObserver;
|
|
|
@@ -544,10 +546,6 @@ public class MainAbilitySlice extends AbilitySlice {
|
|
|
}
|
|
|
|
|
|
// 获取组件
|
|
|
- tabAll = (Text) findParkingPage.findComponentById(ResourceTable.Id_tab_all);
|
|
|
- tabRecommended = (Text) findParkingPage.findComponentById(ResourceTable.Id_tab_recommended);
|
|
|
- tabAllUnderline = findParkingPage.findComponentById(ResourceTable.Id_tab_all_underline);
|
|
|
- tabRecommendedUnderline = findParkingPage.findComponentById(ResourceTable.Id_tab_recommended_underline);
|
|
|
btnDistanceSort = (Button) findParkingPage.findComponentById(ResourceTable.Id_btn_distance_sort);
|
|
|
parkingListScroll = (ScrollView) findParkingPage.findComponentById(ResourceTable.Id_parking_list_scroll);
|
|
|
parkingListContainer = (DirectionalLayout) findParkingPage.findComponentById(ResourceTable.Id_parking_list_container);
|
|
|
@@ -575,13 +573,46 @@ public class MainAbilitySlice extends AbilitySlice {
|
|
|
parkingListScroll.addScrolledListener(new Component.ScrolledListener() {
|
|
|
@Override
|
|
|
public void onContentScrolled(Component component, int x, int y, int oldX, int oldY) {
|
|
|
+ // 防抖:避免频繁触发
|
|
|
+ long currentTime = System.currentTimeMillis();
|
|
|
+ if (currentTime - lastLoadTime < LOAD_THROTTLE_MS) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果正在加载或没有更多数据,直接返回
|
|
|
+ if (isLoading || !hasMore) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
// 计算是否滚动到底部
|
|
|
- int scrollHeight = parkingListScroll.getScrollValue(1);
|
|
|
- int contentHeight = parkingListScroll.getEstimatedHeight();
|
|
|
-// int contentHeight = parkingListScroll.getContentHeight();
|
|
|
+ int scrollY = parkingListScroll.getScrollValue(1);
|
|
|
int viewHeight = parkingListScroll.getHeight();
|
|
|
|
|
|
- if (scrollHeight + viewHeight >= contentHeight - 100 && !isLoading && hasMore) {
|
|
|
+ // 获取内容高度(使用容器的高度)
|
|
|
+ int contentHeight = 0;
|
|
|
+ if (parkingListContainer != null) {
|
|
|
+ contentHeight = parkingListContainer.getHeight();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果容器高度为0,尝试使用EstimatedHeight
|
|
|
+ if (contentHeight == 0) {
|
|
|
+ contentHeight = parkingListScroll.getEstimatedHeight();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果内容高度或视图高度为0,无法计算,直接返回
|
|
|
+ if (contentHeight == 0 || viewHeight == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算剩余滚动距离
|
|
|
+ int remainingDistance = contentHeight - scrollY - viewHeight;
|
|
|
+
|
|
|
+ // 计算阈值(50像素,约等于50vp),当剩余距离小于等于阈值时触发加载
|
|
|
+ int threshold = 50;
|
|
|
+
|
|
|
+ // 当滚动到底部(剩余距离小于等于阈值)时,触发加载
|
|
|
+ if (remainingDistance <= threshold && remainingDistance >= 0) {
|
|
|
+ lastLoadTime = currentTime;
|
|
|
// 加载下一页
|
|
|
loadParkingData(false);
|
|
|
}
|
|
|
@@ -600,6 +631,7 @@ public class MainAbilitySlice extends AbilitySlice {
|
|
|
filterType = filter;
|
|
|
currentPage = 1;
|
|
|
hasMore = true;
|
|
|
+ lastLoadTime = 0; // 重置防抖时间
|
|
|
parkingList.clear();
|
|
|
if (parkingListContainer != null) {
|
|
|
parkingListContainer.removeAllComponents();
|
|
|
@@ -639,6 +671,7 @@ public class MainAbilitySlice extends AbilitySlice {
|
|
|
if (isRefresh) {
|
|
|
currentPage = 1;
|
|
|
hasMore = true;
|
|
|
+ lastLoadTime = 0; // 重置防抖时间
|
|
|
parkingList.clear();
|
|
|
if (parkingListContainer != null) {
|
|
|
parkingListContainer.removeAllComponents();
|
|
|
@@ -649,6 +682,8 @@ public class MainAbilitySlice extends AbilitySlice {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ // 锁定当前页码,避免并发问题
|
|
|
+ final int requestPage = currentPage;
|
|
|
isLoading = true;
|
|
|
|
|
|
// 获取定位坐标
|
|
|
@@ -659,80 +694,130 @@ public class MainAbilitySlice extends AbilitySlice {
|
|
|
longitude = currentLocation.getLongitude();
|
|
|
}
|
|
|
|
|
|
- // 构建请求URL
|
|
|
+ // 构建请求URL(使用锁定的页码)
|
|
|
String url = String.format("/park/near/page?filter=%d&latitude=%f&longitude=%f¤t=%d&size=%d",
|
|
|
- filterType, latitude, longitude, currentPage, pageSize);
|
|
|
+ filterType, latitude, longitude, requestPage, pageSize);
|
|
|
|
|
|
- // 发送请求
|
|
|
+ // 发送请求(网络请求已在后台线程)
|
|
|
CompletableFuture<R<Object>> future = api.http(getContext(), url, "GET", null, null, null);
|
|
|
future.thenAccept(response -> {
|
|
|
- getUITaskDispatcher().asyncDispatch(() -> {
|
|
|
- isLoading = false;
|
|
|
-
|
|
|
+ // 在后台线程解析数据,避免阻塞UI
|
|
|
+ try {
|
|
|
if (response == null || !response.isSuccess()) {
|
|
|
String errorMsg = response != null ? response.getMsg() : "请求失败";
|
|
|
Log.error("加载停车场数据失败: " + errorMsg);
|
|
|
+ getUITaskDispatcher().asyncDispatch(() -> {
|
|
|
+ isLoading = false;
|
|
|
+ // 请求失败,保持currentPage不变,允许重试
|
|
|
+ });
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- try {
|
|
|
- // 解析响应数据
|
|
|
- Object dataObj = response.getData();
|
|
|
- if (dataObj == null) {
|
|
|
- Log.error("响应数据为空");
|
|
|
- return;
|
|
|
- }
|
|
|
+ // 解析响应数据(在后台线程)
|
|
|
+ Object dataObj = response.getData();
|
|
|
+ if (dataObj == null) {
|
|
|
+ Log.error("响应数据为空");
|
|
|
+ getUITaskDispatcher().asyncDispatch(() -> {
|
|
|
+ isLoading = false;
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 将data转换为ZSONObject
|
|
|
+ ZSONObject pageObj;
|
|
|
+ if (dataObj instanceof ZSONObject) {
|
|
|
+ pageObj = (ZSONObject) dataObj;
|
|
|
+ } else {
|
|
|
+ pageObj = ZSONObject.stringToZSON(dataObj.toString());
|
|
|
+ }
|
|
|
|
|
|
- // 将data转换为ZSONObject
|
|
|
- ZSONObject pageObj;
|
|
|
- if (dataObj instanceof ZSONObject) {
|
|
|
- pageObj = (ZSONObject) dataObj;
|
|
|
+ // 解析Page对象(在后台线程)
|
|
|
+ Page<ParkNearRes> page = parsePageData(pageObj);
|
|
|
+ if (page == null || page.getRecords() == null) {
|
|
|
+ Log.error("解析分页数据失败");
|
|
|
+ getUITaskDispatcher().asyncDispatch(() -> {
|
|
|
+ isLoading = false;
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<ParkNearRes> records = page.getRecords();
|
|
|
+ if (records.isEmpty()) {
|
|
|
+ getUITaskDispatcher().asyncDispatch(() -> {
|
|
|
+ isLoading = false;
|
|
|
+ hasMore = false;
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新分页信息(在后台线程计算)
|
|
|
+ boolean hasMoreData = true;
|
|
|
+ int nextPage = requestPage + 1;
|
|
|
+ if (page.getCurrent() != null && page.getPages() != null) {
|
|
|
+ int serverCurrent = page.getCurrent();
|
|
|
+ int totalPages = page.getPages();
|
|
|
+ if (serverCurrent >= totalPages) {
|
|
|
+ hasMoreData = false;
|
|
|
} else {
|
|
|
- pageObj = ZSONObject.stringToZSON(dataObj.toString());
|
|
|
+ // 使用服务器返回的current值+1作为下一页
|
|
|
+ nextPage = serverCurrent + 1;
|
|
|
}
|
|
|
-
|
|
|
- // 解析Page对象
|
|
|
- Page<ParkNearRes> page = parsePageData(pageObj);
|
|
|
- if (page == null || page.getRecords() == null) {
|
|
|
- Log.error("解析分页数据失败");
|
|
|
- return;
|
|
|
+ } else {
|
|
|
+ if (records.size() < pageSize) {
|
|
|
+ hasMoreData = false;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- List<ParkNearRes> records = page.getRecords();
|
|
|
- if (records.isEmpty()) {
|
|
|
- hasMore = false;
|
|
|
+ // 保存最终的分页信息
|
|
|
+ final boolean finalHasMore = hasMoreData;
|
|
|
+ final int finalNextPage = nextPage;
|
|
|
+ final List<ParkNearRes> finalRecords = records;
|
|
|
+
|
|
|
+ // 只在UI线程更新界面
|
|
|
+ getUITaskDispatcher().asyncDispatch(() -> {
|
|
|
+ isLoading = false;
|
|
|
+
|
|
|
+ // 检查currentPage是否已经被其他请求更新(防止旧请求覆盖新数据)
|
|
|
+ // 如果currentPage > requestPage,说明有更新的请求已经完成,忽略这个旧请求的结果
|
|
|
+ if (currentPage > requestPage) {
|
|
|
+ Log.info("忽略过期请求,当前页码: " + currentPage + ", 请求页码: " + requestPage);
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 添加到列表
|
|
|
- parkingList.addAll(records);
|
|
|
+ parkingList.addAll(finalRecords);
|
|
|
|
|
|
- // 渲染列表项
|
|
|
- for (ParkNearRes park : records) {
|
|
|
- addParkingItem(park);
|
|
|
+ // 批量渲染列表项(减少UI更新次数,延迟批量添加)
|
|
|
+ if (parkingListContainer != null && !finalRecords.isEmpty()) {
|
|
|
+ // 先批量创建所有组件
|
|
|
+ List<Component> items = new ArrayList<>();
|
|
|
+ for (ParkNearRes park : finalRecords) {
|
|
|
+ Component item = createParkingItem(park);
|
|
|
+ if (item != null) {
|
|
|
+ items.add(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 批量添加到容器(减少UI重绘次数)
|
|
|
+ for (Component item : items) {
|
|
|
+ parkingListContainer.addComponent(item);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 更新分页信息
|
|
|
- if (page.getCurrent() != null && page.getPages() != null) {
|
|
|
- if (page.getCurrent() >= page.getPages()) {
|
|
|
- hasMore = false;
|
|
|
- } else {
|
|
|
- currentPage++;
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 如果没有分页信息,根据返回数量判断
|
|
|
- if (records.size() < pageSize) {
|
|
|
- hasMore = false;
|
|
|
- } else {
|
|
|
- currentPage++;
|
|
|
- }
|
|
|
+ hasMore = finalHasMore;
|
|
|
+ if (finalHasMore) {
|
|
|
+ currentPage = finalNextPage;
|
|
|
}
|
|
|
+ });
|
|
|
|
|
|
- } catch (Exception e) {
|
|
|
- Log.error("解析停车场数据失败: " + e.getMessage());
|
|
|
- e.printStackTrace();
|
|
|
- }
|
|
|
- });
|
|
|
+ } catch (Exception e) {
|
|
|
+ Log.error("解析停车场数据失败: " + e.getMessage());
|
|
|
+ e.printStackTrace();
|
|
|
+ getUITaskDispatcher().asyncDispatch(() -> {
|
|
|
+ isLoading = false;
|
|
|
+ });
|
|
|
+ }
|
|
|
});
|
|
|
}
|
|
|
|
|
|
@@ -844,11 +929,11 @@ public class MainAbilitySlice extends AbilitySlice {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 添加停车场列表项
|
|
|
+ * 创建停车场列表项组件(不添加到容器)
|
|
|
*/
|
|
|
- private void addParkingItem(ParkNearRes park) {
|
|
|
+ private Component createParkingItem(ParkNearRes park) {
|
|
|
if (parkingListContainer == null) {
|
|
|
- return;
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
@@ -913,7 +998,7 @@ public class MainAbilitySlice extends AbilitySlice {
|
|
|
}
|
|
|
|
|
|
// 设置导航按钮点击事件
|
|
|
- Button navButton = (Button) item.findComponentById(ResourceTable.Id_btn_navigate);
|
|
|
+ Image navButton = item.findComponentById(ResourceTable.Id_btn_navigate);
|
|
|
if (navButton != null) {
|
|
|
navButton.setClickedListener(component -> {
|
|
|
// 导航功能
|
|
|
@@ -922,12 +1007,22 @@ public class MainAbilitySlice extends AbilitySlice {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- // 添加到容器
|
|
|
- parkingListContainer.addComponent(item);
|
|
|
+ return item;
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
- Log.error("添加停车场列表项失败: " + e.getMessage());
|
|
|
+ Log.error("创建停车场列表项失败: " + e.getMessage());
|
|
|
e.printStackTrace();
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加停车场列表项(兼容方法,内部调用createParkingItem)
|
|
|
+ */
|
|
|
+ private void addParkingItem(ParkNearRes park) {
|
|
|
+ Component item = createParkingItem(park);
|
|
|
+ if (item != null && parkingListContainer != null) {
|
|
|
+ parkingListContainer.addComponent(item);
|
|
|
}
|
|
|
}
|
|
|
|