2013-04-16 9 views
0

У меня есть кнопка, которая запускает AsyncTask для загрузки какой-либо информации из Интернета и помещает эту информацию в локальную переменную в действии, которую можно просмотреть, нажав другую кнопку. Кроме того, я обновляю представление в пользовательском интерфейсе, чтобы указать, работает ли синхронизация или готова ли она.Android - AsyncTask не обновляет активность, как ожидалось

По какой-то причине иногда onPostExecute не обновляет пользовательский интерфейс и локальную переменную, как ожидалось, хотя иногда это происходит. Я проверил с отладчиком, и код, который обновляет переменную (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(); 
    } 
} 

Edit: я заметил, что я отсутствовал onSaveInstanceState и onRestoreInstanceState реализации, и думал, что это может быть причиной, поскольку проблема возникает только при время соединения, которое может привести к перезапуску активности по какой-либо причине. Поэтому я добавил их (также в код выше), но проблема все еще происходит ...

Любые идеи кто-нибудь?

+0

в этом случае является контроль подходит к handleDownloadComplete() метод.? – DroidBot

+0

Да, в соответствии с отладчиком, и все еще после запуска метода setText() представления, графический интерфейс остается неизменным. – tbkn23

+0

Давайте попробуем установить textview непосредственно в метод onPostExecute, не используя интерфейс, скажите мне результат. – DroidBot

ответ

0

Я неправильно,

Но я думаю, что его не раз соединения из проблемы. Это может быть при изменении ориентации устройств. С тех пор, как ориентация меняется, активность воссоздается и появляется новый объект активности с различным текстовым видом.

Но это так, тогда вам следует попробовать добавить android: configChanges = "orientation | keyboardHidden | screenSize" в ваш mainfest.

Это сообщение описывает проблему под рукой хорошо:

Background task, progress dialog, orientation change - is there any 100% working solution?

EDITED

onSaveInstanceState просто сохранить данные, используемые этой деятельности и не мнения. Взгляды будут воссозданы. Поскольку u передает ссылку вашей деятельности через downloader.setHandler (это); поэтому после загрузки полный обработчик укажет на старую активность, а не на новую, а текстовое представление будет принадлежать старой активности. Таким образом, новая активность не завершит загрузку.

Если вы уверены, что handler.handleDownloadComplete (результат); вызывается, тогда это может быть проблемой.

+0

Я думал, что это возможно, но я попытался убедиться, что телефон остался в одной ориентации все время и проблема все еще происходила ... Я попробую так или иначе. – tbkn23

+0

Хорошо, это определенно связано с этим как-то. Не могли бы вы объяснить немного больше? Поскольку я сохраняю информацию в onSaveInstanceState, почему это не работает? Я не хочу переопределять configChanges, если я могу помочь. – tbkn23

0

Вы должны вызвать runOnUiThread обновить виджеты на поток пользовательского интерфейса должным образом, например, так:

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; 
     }  
    }); 
} 
+0

Это не так, поскольку onPostExecute() AsyncTask всегда выполняется в потоке пользовательского интерфейса. – tbkn23

+0

Вы пытались переместить вызов 'handler.handleDownloadComplete (result)' from postExecute to downloadUrl? Также необходим код выше. Возможно, postExecute не вызывает по какой-то причине время ожидания. – ararog

+0

postExecute вызывает, я вижу его в отладчике. Я отслеживаю команды один за другим и вижу, что при запуске команды просмотра обновления ничего не происходит в пользовательском интерфейсе. – tbkn23

Смежные вопросы