вложенные AsyncTask и onPostExecute

Я использую AsyncTask (1) в другом AsyncTask (2). AsyncTask 1 извлекает пользовательские данные из сети, подсчитывает количество записей в ответе и для каждой записи в onPostExecute отображает имя пользователя и запускает новую AsyncTask (2), чтобы получить изображение с сервера и загрузить его в ImageView. Все это происходит в onPostExecute. Это работает безупречно, пользовательские данные извлекаются и отображаются, а изображения отображаются одно за другим для каждой записи.

Однако итерация по массиву и обновление TextView в AsyncTask 1 в onPostExecute происходит так быстро, что в основном отображается только последнее имя пользователя в массиве, остальные загружаются, но их невозможно обнаружить человеческим глазом :)

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

Итак, вопрос в том, как синхронизировать 2 AsyncTasks?

немного кода для уточнения, если он все еще нужен

    //instantiate first AsyncTask
    new AsyncRequest().execute(bundle);

    private class AsyncRequest extends AsyncTask<Bundle, Void, String> {
    protected String doInBackground(Bundle... bundle) {
        String data = null;
        try {
            data = request(null, bundle[0]); //request the data
            return data;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }// end method

    protected void onPostExecute(String response) {
        JSONArray data = null;
        try {
            JSONObject response2 = Util.parseJson(response);
            data        = response2.optJSONArray("data");
            int amount  = data.length();
            TextView s1 = (TextView) findViewById(R.id.some_id);
            s1.setText("" + amount); //displays number of items

            //display the data
            for(int i=0; i<amount; i++){
                String email        = "";
                String id           = "";
                JSONObject json_obj = data.getJSONObject(i);
                Log.d("JSONObject ", ""+json_obj);
                String name         = json_obj.getString("name");
                if (json_obj.has("email")){
                    email           = json_obj.getString("email");
                }
                if (json_obj.has("id")){
                    id          = json_obj.getString("id");
                }
                String picture  = "http://www.domain.com/"+id+"/picture";
                TextView s2     = (TextView) findViewById(R.id.name_placeholder);
                s2.setText(name);
                //here we do a new AsynTask for each entry and wait until the data is fetched
                new DownloadProfileImageTask().execute(picture, name).get(); 
            }
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }// end method

person slinden77    schedule 09.06.2012    source источник


Ответы (1)


Не совсем понятно, почему вы называете setText из одного TextView именем нескольких имен. Как вы упомянули, хотя у вас было setText всех имен, вы видите только одно имя. Возможно, вам нужно использовать ListView или что-то в этом роде.

Теперь о вашем вопросе: возможно, вам не нужны два AsyncTask. Вы можете делать все в одном AsyncTask. Код будет примерно таким:

//Create a Holder class as a data holder. 
//For simplicity, public attributes are used
class Holder{
  public String name;
  public String email;
  public String id;
  public BitmapDrawable imageDrawable;
}

//instantiate the AsyncTask
new AsyncRequest().execute(bundle);

private class AsyncRequest extends AsyncTask<Bundle, Holder, Integer> {
protected Integer doInBackground(Bundle... bundle) {
    int amount = 0;
    try {
        data = request(null, bundle[0]); //request the data

        JSONArray data = null;
        JSONObject response2 = Util.parseJson(response);
        data        = response2.optJSONArray("data");
        amount  = data.length();

        //display the data
        for(int i=0; i<amount; i++){
            Holder holder = new Holder();
            holder.email        = "";
            holder.id           = "";
            JSONObject json_obj = data.getJSONObject(i);
            Log.d("JSONObject ", ""+json_obj);
            holder.name         = json_obj.getString("name");
            if (json_obj.has("email")){
                holder.email           = json_obj.getString("email");
            }
            if (json_obj.has("id")){
                holder.id          = json_obj.getString("id");
            }
            String picture  = "http://www.domain.com/"+id+"/picture";

            //Fetch the image and create a Drawable from it - Synchronously
            holder.imageDrawable = getImageDrawable(picture, name);

            publishProgress(holder);

        }
    } catch (Exception e) {
        e.printStackTrace();
    } 
    return amount;
}// end method

protected void onProgressUpdate(Holder... holder) {
    //Update the user name and image
    TextView s2     = (TextView) findViewById(R.id.name_placeholder);
    s2.setText(holder[0].name);

    ImageView imgView = (ImageView) findViewById(R.id.imageViewId);
    imgView.setImageDrawable(holder[0].imageDrawable);

}

protected void onPostExecute(Integer amount) {
    TextView s1 = (TextView) findViewById(R.id.some_id);
    s1.setText(amount.toString()); //displays number of items
}// end method
person Rajesh    schedule 09.06.2012
comment
вау, почему я не подумал об этом? На самом деле очень простое решение. Большое спасибо, что нашли время изменить мой код и опубликовать его как ответ! Мне нужно было внести в него несколько небольших изменений, чтобы он работал, и соответственно обновил ваш ответ. Спасибо еще раз. - person slinden77; 09.06.2012
comment
PS: я обновляю один TextView, потому что хочу показать информацию о пользователе для профилей, найденных в запросе. Все это делается на одной странице/Activity. Конечно, позже я действительно сделаю что-нибудь полезное с Activity;) - person slinden77; 09.06.2012