【发布时间】:2013-06-03 20:44:17
【问题描述】:
所以我有这些长时间运行的服务器调用,这些调用基本上是在我的 Android 应用程序中进行的 OData。调用的消费者使用.execute().get() 等待来自网络线程的响应(我知道正确的方法是使整个事情异步和基于回调,但是如果没有这些数据,应用程序将无法以任何方式运行,并且完全重新设计它以这种方式工作似乎并没有带来任何好处)。
所以我在网上发现了许多 sn-ps,其中将ProgressDialog 与onPreExecute() 和onPostExecute() 结合使用,如下面的代码示例所示,可用于在AsyncTask 执行时显示进度对话框。我正在使用提供的示例,但发生的情况是调用开始,它等待网络事务,然后 very 快速闪烁并隐藏进度对话框。它可以在事务上等待整整几秒钟,我知道它在 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();
}
}
我还尝试了 SO 上其他地方建议的略有不同的版本(如下所示),结果完全相同:
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;
【问题讨论】:
-
如果您遵循此处描述的修复方法会发生什么? (stackoverflow.com/questions/11943133/…)
-
@Ken Wolf:同样的行为。可以看到 UI 响应(即:加载从服务器提取的数据的微调器)在进度对话框快速弹出然后消失之前发生。
-
您通过将其置于任务之外进行的修复将不起作用,因为执行会立即返回。这意味着它将立即调用dismiss。为此,您将在执行之前调用 show 并在 onPostExecute 中调用dismiss。
-
此外,休眠也无济于事,因为要显示对话框,您需要进入事件循环的绘图部分 - 在您完成 onPostExecute 或 onPreExecute 函数之前不会发生。跨度>
标签: android android-asynctask progressdialog