我有一个运行AsyncTask的按钮,用于从网上下载一些信息,并将该信息放入活动中的本地变量,可以通过按另一个按钮查看。 此外,我更新了UI中的视图,以说明同步是在运行还是准备好。
出于某种原因,有时onPostExecute不会按预期更新UI和局部变量,但有时会这样做。我检查了调试器,更新变量的代码(handleDownloadComplete)正在运行,但UI和show data按钮仍然无法正确更新。 注意:问题主要发生在连接超时时,但我仍然看到调试器返回值是正确的 - “连接超时”,但活动没有更新。
谢谢!
AsyncTask类:
public class DownloadDataTask extends AsyncTask<String, Integer, String> {
public interface DownloadCompleteHandler
{
void handleDownloadComplete(String result);
}
private DownloadCompleteHandler handler;
@Override
protected String doInBackground(String... urls) {
try {
return downloadUrl(urls[0]);
} catch (IOException e) {
return "Unable to retrieve web page. URL may be invalid.";
}
}
@Override
protected void onPostExecute(String result) {
handler.handleDownloadComplete(result);
}
private String downloadUrl(String urlStr) throws IOException
{
InputStream is = null;
String result = new String();
try {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.connect();
int response = conn.getResponseCode();
is = conn.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(is));
String inputLine;
while ((inputLine = in.readLine()) != null) {
result += inputLine;
}
}
catch (MalformedURLException ex) {
result = "Malformed URL: " + urlStr;
}
catch (SocketTimeoutException ex) {
result = "Connection timed out";
}
finally {
if (is != null)
is.close();
}
return result;
}
public void setHandler(DownloadCompleteHandler handler) {
this.handler = handler;
}
}
活动:
public class MainActivity extends Activity implements DownloadDataTask.DownloadCompleteHandler{
private String downloadResult = "";
private Boolean isSyncing = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void onResume() {
super.onResume();
checkNetworkConnection();
}
@Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putString(KEY_DOWNLOAD_RESULT, downloadResult);
savedInstanceState.putBoolean(KEY_IS_SYNCING, isSyncing);
super.onSaveInstanceState(savedInstanceState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
downloadResult = savedInstanceState.getString(KEY_DOWNLOAD_RESULT);
isSyncing = savedInstanceState.getBoolean(KEY_IS_SYNCING);
updateAppDataView();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_settings:
settingsMenu();
return true;
case R.id.action_show_result:
showUrlResultDialog();
return true;
case R.id.action_sync:
getHttpData();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
void settingsMenu() {
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
}
private void checkNetworkConnection() {
ConnectivityManager connMgr = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
// test app connection
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(R.string.titleNoNetwork).setMessage(R.string.msgNoNetwork);
builder.setCancelable(false);
builder.setNegativeButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
}
private void getHttpData()
{
if (isSyncing) return;
isSyncing = true;
TextView view = (TextView)findViewById(R.id.textWebResult);
view.setText("Syncing");
String serverId = PreferenceManager.getDefaultSharedPreferences(this).getString(getString(R.string.keyServerIp), "");
String url = "https://" + serverId;
DownloadDataTask downloader = new DownloadDataTask();
downloader.setHandler(this);
downloader.execute(url);
}
public void handleDownloadComplete(String result)
{
downloadResult = result;
TextView view = (TextView)findViewById(R.id.textWebResult);
view.setText("Ready");
isSyncing = false;
}
private void showUrlResultDialog()
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(R.string.titleUrlResultData).setMessage(downloadResult);
builder.setNeutralButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
}
编辑:我注意到我缺少onSaveInstanceState
和onRestoreInstanceState
实现,并且认为它可能是原因,因为问题只发生在连接超时时,这可能会导致活动重新启动原因。所以我添加了它们(也在上面的代码中),但问题仍然存在......
任何想法?
答案 0 :(得分:0)
我错了,
但我认为它不是连接超时问题。可能是你改变设备的方向。因为当方向改变时,重新创建活动并且存在具有不同文本视图的新活动对象。
但是就是这样,那么你应该尝试将android:configChanges =“orientation | keyboardHidden | screenSize”添加到你的主要节目中。
这篇文章很好地描述了这个问题:
Background task, progress dialog, orientation change - is there any 100% working solution?
<强> EDITED 强>
onSaveInstanceState将只保存该活动使用的数据,而不保存视图。视图将重新创建。因为你通过downloader.setHandler(this)传递你的活动的引用;所以下载完成处理程序将指向旧活动而不是新活动,textview将属于旧活动。因此,新活动无法完成下载事件。
如果你确定handler.handleDownloadComplete(结果);正在被召唤然后这可能只是问题。
答案 1 :(得分:0)
您必须调用runOnUiThread才能正确更新ui线程上的小部件,如下所示:
public void handleDownloadComplete(final String result)
{
runOnUiThread(new Runnable() {
public void run() {
downloadResult = result;
TextView view = (TextView)findViewById(R.id.textWebResult);
view.setText("Ready");
isSyncing = false;
}
});
}