0

我有一个按钮,它运行 AsyncTask 以从 Web 下载一些信息,并将该信息放入活动中的局部变量中,可以通过按另一个按钮来查看。此外,我在 UI 中更新了一个视图,以说明同步是否正在运行或准备就绪。

出于某种原因,有时 onPostExecute 不会按预期更新 UI 和局部变量,但有时会。我使用调试器进行了检查,更新变量 (handleDownloadComplete) 的代码正在运行,但 UI 和显示数据按钮仍然没有正确更新。注意:问题主要发生在连接超时时,但我仍然使用调试器看到返回值是正确的 - “连接超时”,但活动没有更新。

谢谢!

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实现,并认为这可能是原因,因为问题仅在连接超时时发生,这可能导致活动因某种原因重新启动。所以我添加了它们(也在上面的代码中),但问题仍然存在......

有什么想法吗?

4

2 回答 2

0

我错了,

但我认为它不是连接超时问题。可能是当您更改设备的方向时。因为当方向改变时,活动被重新创建,并且有一个具有不同文本视图的新活动对象。

但情况就是这样,那么你应该尝试将 android:configChanges="orientation|keyboardHidden|screenSize" 添加到你的 mainfest。

这篇文章很好地描述了手头的问题:

后台任务、进度对话框、方向更改 - 是否有任何 100% 可行的解决方案?

已编辑

onSaveInstanceState 只会保存该活动使用的数据,而不是视图。将重新创建视图。由于您正在通过 downloader.setHandler(this); 传递您的活动的引用;所以下载完成后处理程序将指向旧活动而不是新活动,并且文本视图将属于旧活动。因此,新活动不会获得下载完成的事件。

如果你确定 handler.handleDownloadComplete(result); 正在被调用,那么这可能只是问题所在。

于 2013-04-19T13:17:19.083 回答
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;
         }    
     }); 
}
于 2013-04-19T13:19:47.963 回答