Android:点击刷新按钮后ProgressDialog未即时显示问题排查(不使用AsyncTask)
问题出在哪
你的代码里future.get()是阻塞式调用,会把主线程死死卡住:
- 虽然你用
ExecutorService开了子线程跑HTTP请求,但调用future.get()时,主线程会一直等子线程把整个请求做完才继续干活。 - ProgressDialog的显示是UI操作,得靠主线程的消息队列来渲染,主线程被卡住的时候,根本腾不出手处理Dialog的显示请求,只能等Search方法全执行完了才会去处理,所以对话框才会在搜索结束后才弹出来。
怎么改
得把阻塞主线程的future.get()去掉,改用异步回调的方式处理子线程的结果,同时保证UI操作(比如关Dialog)在主线程做。
修改后的代码示例
- 先定义一个回调接口,用来通知主线程搜索结果:
public interface OnSearchDoneListener { void onSuccess(Map<String, Object> result); void onFail(Exception e); }
- 修改Search方法,去掉阻塞调用,换成异步执行逻辑:
public void Search(int idx, OnSearchDoneListener listener) { NetCheck nc = new NetCheck(this, false); if (!nc.checkNetwork()) { listener.onFail(new Exception("网络不可用")); return; } final NetTask nt = new NetTask(); ExecutorService executor = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() ); executor.submit(new Runnable() { @Override public void run() { try { Map<String, Object> result = nt.call(); // 回到主线程通知搜索成功 runOnUiThread(() -> { listener.onSuccess(result); }); } catch (Exception e) { // 回到主线程通知搜索失败 runOnUiThread(() -> { listener.onFail(e); }); } finally { executor.shutdown(); } } }); }
- 在点击事件里调用修改后的Search,正确处理Dialog的显示与关闭:
// 把ProgressDialog设为Activity成员变量,避免局部变量被提前回收 private ProgressDialog progressDialog; @Override public void onClick(View view) { switch (view.getId()) { case R.id.tool_btnRefresh: progressDialog = new ProgressDialog(MainActivity.this); progressDialog.setMessage("正在搜索..."); progressDialog.setCancelable(true); progressDialog.setProgressStyle(android.R.style.Widget_ProgressBar_Horizontal); progressDialog.show(); // 现在能立刻弹出对话框了 Search(0, new OnSearchDoneListener() { @Override public void onSuccess(Map<String, Object> result) { // 处理搜索到的结果 List<Object> list = new ArrayList<>(); list.add(result); // 关闭对话框 if (progressDialog != null && progressDialog.isShowing()) { progressDialog.dismiss(); } } @Override public void onFail(Exception e) { // 处理错误情况 if (progressDialog != null && progressDialog.isShowing()) { progressDialog.dismiss(); } } }); break; } }
额外提醒
- 绝对不能在主线程里执行耗时操作(包括网络请求、阻塞等待子线程),否则会导致UI卡顿甚至触发ANR(应用无响应)。
- ProgressDialog在Android 8.0及以上版本已被废弃,推荐使用
DialogFragment结合ProgressBar或Material Design组件替代,避免兼容性问题。 - 记得在Activity销毁时检查并关闭Dialog,防止内存泄漏。
内容的提问来源于stack exchange,提问作者js u
相关产品推荐
相关产品推荐

