Возврат данных из AsyncTask Android - PullRequest
8 голосов
/ 19 января 2012

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

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

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

1.) Каждый раз, когда пользователь открывает какое-либо представление компании, получает символы компании из базы данных

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

3.) Для всех символов, выбранных из базы данных, Извлекает их 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;
            }
        }
    }

Ответы [ 3 ]

8 голосов
/ 19 января 2012

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

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

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

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

3 голосов
/ 19 января 2012

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

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

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

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

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

1 голос
/ 07 марта 2012

Просто для дальнейшего использования, потому что этот пост немного староват:

Я создал класс 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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...