Android AsyncTask中的ProgressDialog无法在正确的时间显示

时间:2013-06-03 20:44:17

标签: android android-asynctask progressdialog

所以我已经在我的Android应用程序中进行了长时间运行的服务器调用。调用的使用者使用.execute().get()等待来自网络线程的响应(我知道正确的方法是使整个事情异步和基于回调,但是如果没有这些数据,应用程序无法以任何方式运行,并且完全重新架构它以这种方式工作似乎没有提供任何好处。)

因此,我在网上找到了许多代码段,其中ProgressDialogonPreExecute()onPostExecute()结合使用,如下面的代码示例所示,可用于显示进度对话框AsyncTask 1}}执行。我正在使用提供的样本,但是会发生的是呼叫开始,它等待网络事务,然后非常快速闪烁并隐藏进度对话框。它可以在整个交易过程中等待整整秒钟,我知道它正在等待doInBackground(),但对话框直到最后都不会弹出,使其无效。

在下面的代码中,DoEvents()位基本上只是一个非常短暂的睡眠。我曾尝试使用和不使用它,似乎没有什么区别,但似乎值得尝试。

class GetFromServerTask extends AsyncTask<String, Void, String>
    {
        private Context context;
        private ProgressDialog dialog;

        public GetFromServerTask(Context ctx) {
            context = ctx;
            dialog = new ProgressDialog(ctx);
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            dialog.setMessage("Loading...");
            dialog.show();
            DoEvents();
        }

        @Override
        protected String doInBackground(String... parms) {
            if(InOfflineMode)
                return "notdeserializable";

            String url = parms[0]; 
            HttpURLConnection urlConnection = null;
            try {
                URL typedUrl = new URL(url);
                urlConnection = (HttpURLConnection) typedUrl.openConnection();

                //Add Authorization token
                if(InDebugMode) {
                    urlConnection.addRequestProperty("AuthToken", AuthToken);
                } else {
                    urlConnection.addRequestProperty("Authorization", "Bearer " + AuthToken);
                }
                urlConnection.addRequestProperty("Accept", "application/json");

                DoEvents();
                InputStream in = new BufferedInputStream(urlConnection.getInputStream());
                byte[] contents = new byte[in.available()];

                int bytesRead = 0;
                String strContents = ""; 
                while((bytesRead = in.read(contents)) != -1){ 
                    strContents += new String(contents, 0, bytesRead);
                    DoEvents();
                }

                if(strContents.startsWith("<HTML>"))
                    return "Error: Received unexpected HTML when connecting to service.  Make sure you are not connected to a WIFI that requires authentication.";

                return strContents;
            } catch(UnknownHostException hex) {
                return "Error: Could not find server address.  Make sure you are connected to the internet.  If you just changed connections (ie: turning WIFI on or off) it make take a minute to refresh";
            }
            catch(Exception ex) {
                String msg = "Error: " + ex.getClass().getName() + ": " + ex.getMessage();
                Log.e("TE", msg);
                return msg;
            } finally {
                if(urlConnection != null)
                    urlConnection.disconnect();
            }
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            if(dialog != null && dialog.isShowing())
                dialog.dismiss();
            DoEvents();
        }
    }

我也尝试过在其他地方建议的略有不同的版本(如下所示),结果相同:

protected void onPreExecute() {
    dialog=ProgressDialog.show(context, "", "Loading...", true, false);
    super.onPreExecute();
}

我还尝试将ProgressDialog全部放在AsyncTask之外并在任务外“显示”,如下所示。在这种情况下,它甚至不会出现。

ProgressDialog dialog = ProgressDialog.show(ServerAccessLayer.m_context, "", "Loading...", true, false);
String retVal = new GetFromServerTask(ServerAccessLayer.m_context).execute(url).get();
dialog.dismiss();

return retVal; 

2 个答案:

答案 0 :(得分:3)

好的,您的问题是.get().get是阻止通话。这意味着您不会返回事件循环(Android框架中调用onCreateonPause,事件处理程序,onPostExecuteonPreExecute等的代码),直到在它返回后。如果不返回事件循环,则不会进入绘图代码,也不会显示进度对话框。如果要显示对话框,则需要重新构建应用程序以实际异步使用该任务。旁注 - 如果您在UI线程上调用.get(),那么整个应用程序将会冻结并且看起来很糟糕。这就是为什么他们强迫人们首先不在UI线程上做网络IO。

答案 1 :(得分:1)

正如@ Gabe-Sechan所说,.get()是你的用户界面冻结而你的ProgressDialog没有按照你想要的方式显示的原因。另一方面,当他说:

时,我不同意他的观点
  

如果要显示对话框,则需要将应用重新架构为   实际上是异步使用任务。

如果您只是移除了.get()并在onPreExecute()中显示对话框并在onPostExecute(String result)中解雇,那么您将获得所需内容:在显示的同时显示ProgressDialog任务执行。

更新:

我根据使用Android的AsyncTask类的get()方法的意义/用途开始了question