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();
    }
}

編集:実装が欠落onSaveInstanceStateしていることに気付きonRestoreInstanceState、接続がタイムアウトしたときにのみ問題が発生し、何らかの理由でアクティビティが再開される可能性があるため、それが原因である可能性があると考えました。だから私はそれらを(上記のコードでも)追加しましたが、問題はまだ発生しています...

アイデアはありますか?

4

2 に答える 2

0

私は間違っている、

しかし、接続タイムアウトの問題ではないと思います。デバイスの向きを変えたときかもしれません。方向が変わると、アクティビティが再作成され、異なるテキストビューを持つ新しいアクティビティ オブジェクトが作成されるためです。

しかし、そうであれば、メインフェストに android:configChanges="orientation|keyboardHidden|screenSize" を追加してみてください。

この投稿では、当面の問題についてよく説明しています。

バックグラウンド タスク、進行状況ダイアログ、向きの変更 - 100% 有効な解決策はありますか?

編集済み

onSaveInstanceState は、ビューではなく、そのアクティビティで使用されるデータを保存するだけです。ビューが再作成されます。アクティビティの参照を downloader.setHandler(this); を介して渡しているためです。したがって、ダウンロード完了後、ハンドラーは新しいアクティビティではなく古いアクティビティを指し、テキストビューは古いアクティビティに属します。そのため、新しいアクティビティはダウンロード完了のイベントを取得しません。

もしあなたが確実に handler.handleDownloadComplete(result); が呼び出されている場合、これだけが問題になる可能性があります。

于 2013-04-19T13:17:19.083 に答える