Android - AsyncTask没有按预期更新活动

时间:2013-04-16 06:52:17

标签: android android-asynctask

我有一个运行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();
    }
}

编辑:我注意到我缺少onSaveInstanceStateonRestoreInstanceState实现,并且认为它可能是原因,因为问题只发生在连接超时时,这可能会导致活动重新启动原因。所以我添加了它们(也在上面的代码中),但问题仍然存在......

任何想法?

2 个答案:

答案 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;
         }    
     }); 
}
相关问题