Android Studio中Java代码try-catch出现无限循环问题求助
解决Android Room数据库操作导致的无限循环问题
问题根源
你的代码存在典型的LiveData触发循环:点击按钮后通过userViewModel.getId().observe监听用户数据,执行update操作修改数据库后,Room会通知getId返回的LiveData数据更新,观察者回调会再次被触发,进而再次执行update,形成无限循环。而你用的isUpdating标志只能控制按钮点击触发,无法阻止LiveData数据更新带来的重复回调。
解决方案一:使用一次性观察者
给ViewModel添加只监听一次数据变化的方法,避免数据更新时重复触发回调:
修改ViewModel类
// 添加一次性观察方法 public void observeOnceById(int userId, Observer<List<Users>> observer) { LiveData<List<Users>> userLiveData = getId(userId); userLiveData.observeForever(new Observer<List<Users>>() { @Override public void onChanged(List<Users> users) { observer.onChanged(users); // 数据回调后立即移除观察者,避免后续更新触发 userLiveData.removeObserver(this); } }); }
修改MainActivity的点击事件
final boolean[] isUpdating = {false}; UserViewModel userViewModel = new ViewModelProvider(this).get(UserViewModel.class); btnUpdate.setOnClickListener(view -> { if (!isUpdating[0]) { isUpdating[0] = true; Users user = new Users(5, "kylo", "14", "14"); // 使用一次性观察者替代原observe方法 userViewModel.observeOnceById(user.getId(), users -> { if (users.size() == 1) { logger.LogError(tag, "Checked if exist", "true"); try { int result = userViewModel.update(user); if (result > 0) { logger.LogError(tag, "Update", "success"); } else { logger.LogError(tag, "Update", "failed"); } } catch (ExecutionException | InterruptedException | TimeoutException e) { e.printStackTrace(); } finally { isUpdating[0] = false; } } else { logger.LogError(tag, "Checked if exist", "false"); isUpdating[0] = false; } }); } });
解决方案二:同步查询用户是否存在
如果不需要监听数据变化,只是执行"检查存在→更新"的逻辑,可以改用同步查询,完全避免LiveData的自动回调:
修改ViewModel类
// 添加同步查询方法 public List<Users> getByIdSync(int userId) throws ExecutionException, InterruptedException { Callable<List<Users>> queryCallable = () -> sqlite_room_dao.getById(userId); Future<List<Users>> future = Executors.newSingleThreadExecutor().submit(queryCallable); return future.get(); }
修改MainActivity的点击事件
final boolean[] isUpdating = {false}; UserViewModel userViewModel = new ViewModelProvider(this).get(UserViewModel.class); btnUpdate.setOnClickListener(view -> { if (!isUpdating[0]) { isUpdating[0] = true; new Thread(() -> { Users user = new Users(5, "kylo", "14", "14"); try { List<Users> users = userViewModel.getByIdSync(user.getId()); if (users.size() == 1) { logger.LogError(tag, "Checked if exist", "true"); int result = userViewModel.update(user); runOnUiThread(() -> { if (result > 0) { logger.LogError(tag, "Update", "success"); } else { logger.LogError(tag, "Update", "failed"); } }); } else { logger.LogError(tag, "Checked if exist", "false"); } } catch (ExecutionException | InterruptedException e) { e.printStackTrace(); } finally { runOnUiThread(() -> isUpdating[0] = false); } }).start(); } });
额外优化点
- 避免每次创建新的
Executors.newSingleThreadExecutor(),可以在ViewModel中初始化固定线程池,减少资源消耗。 - Room的
@Update注解可直接接收实体类对象,无需手动传递字段参数,简化sqlite_room_dao.update的实现。
内容的提问来源于stack exchange,提问作者RFlores
相关产品推荐
相关产品推荐

