2012-01-19 10 views
8

Я попытался передать аналогичный вопрос на SO, но не получил никакой помощи.Возвращаемые данные от AsyncTask Android

В моем приложении для Android я планирую реализовать Недавнее цитирование Пользователь посетил i.e., Как и недавно посещенные страницы в Интернете.

Ниже приведены шаги, которые я отслеживаю:

1.) Всякий раз, когда пользователь открывает любой вид компании, выборки символов компании из базы данных

2.) Затем магазин текущий символ вдоль с dateTime в базе данных.

3.) Для всех символов, извлекаемых из базы данных, Fetch их current value и %Change и дисплей название компании, текущее значение и% Изменение в списке.

Проблема возникает в классе ASyncTask, так как метод postExecute не позволяет его возвращать тип, отличный от void.

Я делаю что-то неправильно?

Любая помощь будет спасателем жизни!

String[] rsym,rcmp,rchg; 
rdbM = new RecentDBManager(CompanyView.this); 
try { 
Calendar date1 = Calendar.getInstance(); 
SimpleDateFormat dateformatter = new SimpleDateFormat(
          "dd/MM/yyyy HH:mm:ss"); 

String currentdate = dateformatter.format(date1.getTime()); 

rdbM.openDB(); 

//STEP 1 
rsym = rdbM.getRecent_sym(); 

//STEP 2     
rdbM.setData(currentsymbol, currentdate); 

rdbM.closeDB(); 

} catch (Exception e) { 
throw new Error(" *** ERROR in DB Access *** "+ e.toString()); 
} 

//STEP 3 
     for(int i=0;i<rsym.length;i++) 
     { 
      DownloadRecentQuote quotetask = new DownloadRecentQuote(); 
      recentquotetask 
      .execute(new String[] { "http://abc.com/stockquote.aspx?id=" 
         + rsym[i] }); 

//CURRENT VALUE and %CHANGE which should be returned from ASyncTask class 

      rcmp[i]=valuearr[0]; 
      rchg[i]=valuearr[1]; 
      } 

      list1 = new ArrayList<HashMap<String, String>>(); 
      HashMap<String, String> addList1; 

      for (int i = 0; i < limit; i++) 
      { 
       addList1 = new HashMap<String, String>(); 
       addList1.put(RecentSym_COLUMN, rsym[i]); 
       addList1.put(RecentCMP_COLUMN, rcmp[i]); 
       addList1.put(RecentChg_COLUMN, rchg[i]); 

       list1.add(addList1); 

       RecentAdapter adapter1 = new RecentAdapter(
        CompanyView.this, CompanyView.this, list1); 
       listrecent.setAdapter(adapter1); 
      } 


private class DownloadRecentQuote extends AsyncTask<String, Void, String> { 
    /* Fetching data for RecentQuote information */ 
    @Override 
    protected String doInBackground(String... urls) { 
     String response = ""; 
     for (String url : urls) { 
      DefaultHttpClient client = new DefaultHttpClient(); 
      HttpGet httpGet = new HttpGet(url); 
      try { 
       HttpResponse execute = client.execute(httpGet); 
       InputStream content = execute.getEntity().getContent(); 

       BufferedReader buffer = new BufferedReader(
         new InputStreamReader(content)); 
       String s = ""; 
       while ((s = buffer.readLine()) != null) { 
        response += s; 
       } 

      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
     return response; 
    } 

    @Override 
    protected void onPostExecute(String result) { 

     arr1 = result.split("@"); 

     if (arr1[0].length() != 0) { 

      if (arr1[0].equals("1")) { 

       arr = arr1[1].split(";"); 

      //RETURN 2 STRINGS 
          String valuearr[]; 
       valuearr[0] = arr[3]; 
       valuearr[1] = arr[6].concat("%"); 
       //return valuearr; 
      } 
     } 
    } 
+0

Это будет лучше, если вы используете BroadCasteReceiver http://developer.android.com/reference/android/content/BroadcastReceiver .html .. Он позволяет передавать данные через намерение. – ngesh

ответ

8

postExecute() не может возвращать значение, потому что, кто или что бы он вернуться? Исходный метод, вызывающий AsyncTask, исчез, потому что ваш AsyncTask работает в фоновом режиме. Это асинхронное значение, когда AsyncTask.execute() возвращает его по-прежнему в фоновом режиме, и поэтому postExecute() не может вернуть значение, потому что ему нечего возвращать.

Вместо этого ваша AsyncTask нуждается в ссылке на вашу деятельность или какой-либо другой объект, чтобы он мог возвращать ваши значения обратно. В вашем коде строки после вызова функции execute() не могут быть там, потому что ваша задача еще не закончена. Вместо этого вы должны создать метод под названием updateSymbol (currentPrice, percentChange), переместить весь этот код ниже execute(), а в вашей AsyncTask вы должны передать ссылку на Activity. Затем вызовите updateSymbol (currentPrice, percentChange) из метода onPostExecute().

Но будьте осторожны, если у вас есть ссылка на действие, оно может быть уничтожено во время выполнения doInBackground(), а при запуске postExecute() следует просто отказаться от результатов или не попытаться обновить интерфейс. Например, пользователь поворачивает свой телефон, вызывая уничтожение Activity. Я считаю, что лучше всего держать ссылку на AsyncTask в активности, чтобы она могла отменить(), если активность уничтожена. Вы можете позвонить AsyncTask.cancel(), а затем проверьте, если ваша задача была отменена, как:

public void postExecute(String result) { 
    if(!isCanceled()) { 
     // do your updating here 
     activity.setSymbol(result); 
    } 
} 

Это действительно легко создать базовый класс для всех видов деятельности, так что вы можете легко отслеживать AsyncTasks работы:

public class BaseActivity extends Activity { 

    List<AsyncTask> runningTasks; 

    public void onStop() { 
     for(AsyncTask task : runningTasks) { 
      task.cancel(true); 
     } 
    } 

    public AsyncTask start(AsyncTask task) { 
     runningTasks.add(task); 
     return task; 
    } 

    public void done(AsyncTask task) { 
     runningTasks.remove(task); 
    } 
} 

Некоторые быстрые указатели. Вам не нужно выполнять (новый String [] {"blah" + blah}). Varargs на Java позволяет это сделать. выполнить («бла» + бла). Вы также перехватываете исключения и продолжаете, не справляясь с ними. Это будет сложно, если что-то действительно произойдет, потому что ваше приложение поймает их и просто продолжается, как будто ничего не произошло.Если вы получите сообщение об ошибке, возможно, вам захочется предоставить некоторую обратную связь пользователю и перестать пытаться выполнить этот процесс. Остановитесь, покажите пользователю ошибку и позвольте им сделать следующее. Переместите блоки захвата в нижнюю часть методов.

+0

Thnx так много. Я новичок в разработке Android и пытаюсь понять это. Что вы подразумеваете под ** в своей AsyncTask, вы должны передать ссылку на Activity ** ???? – GAMA

+0

DownloadRecentQuote task = new DownloadRecentQuote (this), предполагая, что вы выполняете это изнутри действия.Если вы не выполняете DownloadRecentQuote в действии, вы можете передать ссылку на экземпляр, создающий экземпляр DownloadRecentQuote, а затем выяснить, каким образом обновить пользовательский интерфейс оттуда. Похоже, вы создаете DownloadRecentQuote в действии, потому что я вижу переменную списка с адаптером. – chubbsondubs

3

По существу, AsyncTask.onPostExecute() выполняет то, что вы хотите делать после выполнения doInBackground() AsyncTask, и результат выполнения возвращается. Это следует рассматривать как наилучшую практику.

Когда вызывается вызов asyncTask(). Execute() из потока пользовательского интерфейса (обратите внимание, что этот метод должен вызываться из потока пользовательского интерфейса), инфраструктура Android создает рабочий поток и запускает все, что вы написали в AsyncTask.doInBackground () в этом рабочем потоке. На этом этапе (после вызова нового AsyncTask(). Execute()) поток пользовательского интерфейса продолжает выполнять код после нового AsyncTask(). Execute(). Итак, теперь во время выполнения у вас есть два потока (пользовательский интерфейс и рабочий поток), которые работают одновременно.

Но где и когда результат выполнения AsyncTask возвращается из рабочего потока обратно в поток пользовательского интерфейса?

Точка, в которой рабочий поток (doInBackground()) заканчивается и возвращается к потоку пользовательского интерфейса, представляет собой AysncTask.onPostExecute(). Этот метод гарантированно будет вызываться каркасом в потоке пользовательского интерфейса, как только AsyncTask закончит. Другими словами, нам все равно, когда и когда AsyncTask.onPostExecute() вызывается во время выполнения, нам просто нужно гарантировать, что он будет называться в конечном счете на каком-то этапе в будущем. Именно по этой причине этот метод не возвращает результат выполнения - вместо этого он требует, чтобы результат выполнения передавался как единственный параметр метода из doInBackground().

Кроме того, Android API предоставляет возможность возвращать результат выполнения AsyncTask на время кодирования, AsyncTask.get():

MyAsyncTask myAsyncTask = new MyAsyncTask(); 

// This must be called from the UI thread: 
myAsyncTask.execute(); 

// Calling this will block UI thread execution: 
ExecutionResult result = myAsyncTask.get(); 

Имейте в виду, что AsyncTask.get() будет блокировать выполнение вызывающего потока, и вы, вероятно, получите исключение ANR, если вы вызываете его в потоке пользовательского интерфейса. Это полезная нагрузка с помощью AsyncTask.get(), вызвав ее в потоке пользовательского интерфейса, вы фактически делаете свой AsyncTask (рабочий поток) синхронно запуском с потоком пользовательского интерфейса (путем создания ожидания потока пользовательского интерфейса). Подводя итог, это выполнимо, но не рекомендуется.

+0

Я не думаю, что 'myAsyncTask.get()' будет блокировать пользовательский интерфейс в течение длительного времени, поскольку он просто получает вычисленные данные из 'onPostExecute()'. –

+0

За исключением части в строке 14 «Будущее», ваш ответ прекрасен. –

1

Просто на будущее, потому что этот пост немного устаревают:

Я создал класс Activity, который имеет метод OnStart() и отдельный класс для AsyncTask. Основываясь на моем тесте, после метода doInbackground() результат будет сначала отправлен в действие, после чего будет выполняться операция onPostExecute(). Это связано с тем, что на основе logcat я сначала получил свои первые данные ответа (отправленные сервером), затем этот ответ снова отобразится из активности, и последнее сообщение в onPostExecute() будет показано.

Код для деятельности: Код

@Override 
    protected void onStart() { 
     super.onStart(); 
     String str = "***"; 
     if(isConnectedToInternet()){ 
      myAsyncTask.execute(); 

      try { 
       if(myAsyncTask.get()) 
        str = myAsyncTask.getResponseMsg(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } catch (ExecutionException e) { 
       e.printStackTrace(); 
      } catch (CancellationException e) { 
       e.printStackTrace(); 
      } 
     } 
     Log.i("Data returned by server2:", str); 
    } 

AsyncTask:

public class MyAsyncTask extends AsyncTask<Void, Void, Boolean> { 

    private URL url; 
    private HttpURLConnection conn; 
    private String strResponseMsg; 

    public MyAsyncTask(String url) throws MalformedURLException{ 
     this.url = new URL(url); 
    } 


    @Override 
    protected void onPreExecute() { 
     Log.i("Inside AsyncTask", "myAsyncTask is abut to start..."); 
    } 

    @Override 
    protected Boolean doInBackground(Void... params) { 
     boolean status = false; 

     try { 
      conn = (HttpURLConnection) url.openConnection(); 
      conn.setConnectTimeout(Manager.ConnTimeout); 
      conn.setReadTimeout(Manager.ReadTimeout); 

      int responseCode = conn.getResponseCode(); 
      Log.i("Connection oppened", "Response code is:" + responseCode); 
      if (responseCode == HttpURLConnection.HTTP_OK) { 
       BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); 
       if (in != null) { 
        StringBuilder strBuilder = new StringBuilder(); 
        // Read character by character    
        int ch = 0; 
        while ((ch = in.read()) != -1) 
         strBuilder.append((char) ch); 

        // Showing returned message 
        strResponseMsg = strBuilder.toString(); 
        Log.i("Data returned by server:", strResponseMsg); 

        status = true; 
       } 
       in.close(); 
      } 

     } catch (IOException e) { 
      e.printStackTrace(); 
     }  

     return status; 
    } 

    @Override 
    protected void onPostExecute(Boolean result) { 
     Log.i("Inside AsyncTask", "myAsyncTask finished its task. Returning data to caller..."); 
    } 

    public String getResponseMsg(){ 
     return strResponseMsg; 
    } 
}