从doInBackground方法中的另一个asynctask调用AsyncTask?

时间:2014-06-01 12:15:32

标签: java android multithreading android-asynctask adapter

我从AsyncTask1调用AsyncTask2 ......这是我的'场景':

  • AsyncTask1下载一个rss feed,解析xml,并为doInBackground方法中的每个识别创建和执行AsyncTask2的项目。
  • doInBackground方法中的AsyncTask2下载从AsyncTask1传递的项目的enclosure url属性,并在onPostExecute方法中将该项目添加到全局项目数组,并将项目更改通知给关联的适配器。

它工作正常而不会崩溃,为什么? AsyncTasks应该从UI线程(threading rules)运行,现在我对这个假设有点困惑。

抱歉英语不好,我希望问题很清楚。

修改 这里有些代码...... DownloadRssAsyncTask = AsyncTask2, RssAsyncTask = AsyncTask1

public class ParseActivity extends Activity {

public class FeedItemAdapter extends ArrayAdapter<FeedItem> {

    int resource;

    public FeedItemAdapter(Context context, int resource, List<FeedItem> items) {
        super(context, resource, items);

        this.resource = resource;
    }

    public View getView(int position, View convertView, ViewGroup parent) {

        LinearLayout myView;
        FeedItem item = getItem(position);

        if (convertView == null) {
            myView = new LinearLayout(getContext());
            String inflaterService = Context.LAYOUT_INFLATER_SERVICE;
            LayoutInflater li = (LayoutInflater) getContext().getSystemService(inflaterService);
            li.inflate(resource, myView, true);
        } else {
            myView = (LinearLayout) convertView;
        }

        TextView titleFeedItem = (TextView) myView.findViewById(R.id.itemTitle);
        TextView dateFeedItem = (TextView) myView.findViewById(R.id.itemDate);
        ImageView imageFeedItem = (ImageView) myView.findViewById(R.id.imageThumb);

        titleFeedItem.setText(item.mTitle);
        dateFeedItem.setText(item.mPubDate);
        imageFeedItem.setImageBitmap(item.bitmapEnclosure);

        return myView;
    }
}


private class DownloadRssAsyncTask extends AsyncTask<FeedItem, Void, FeedItem> {

    @Override
    protected FeedItem doInBackground(FeedItem... params) {

        FeedItem item = params[0];
        if (item.mEnclosure == null) {
            Log.i("info: ", "no enclosure tag");
            item.bitmapEnclosure = null;
            return item;
        }

        try {
            URL imageUrl = new URL(item.mEnclosure);
            item.bitmapEnclosure = BitmapFactory.decodeStream(imageUrl.openStream());
        } catch (IOException e) {
            Log.e("error", "download image resource error: "+item.mEnclosure);
            item.bitmapEnclosure = null;
        }

        return item;
    }

    @Override
    protected void onPostExecute(FeedItem result) {
        items.add(result);
        arrayAdapter.notifyDataSetChanged();

        dbHelper.putItem(result.mGuid, result.mTitle, result.mDescription, result.mEnclosure, result.mPubDate);
    }
}


private class RssAsyncTask extends AsyncTask<String, Integer, Void> {

    @Override
    protected Void doInBackground(String... params) {
        int dimParams = params.length;
        for (int i=0; i<dimParams; i++) {
            Log.i("doInBackground", "rss feed num "+ (i+1) + " of "+ dimParams+ ": " + params[i]);
            refreshFeed(params[i]);
        }

        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        Log.i("onPostExecute in RssAsyncTask", "notifyDataSetChanged");
    }

}

public static class FeedItem {


    public String mAuthor;
    public String mCategory;
    public String mComments;
    public String mDescription; //r
    public String mEnclosure;
    public Bitmap bitmapEnclosure;
    public String mGuid;
    public String mLink;    //r
    public String mPubDate;
    public String mSource;
    public String mTitle;   //r

    public FeedItem() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public String toString() {
        return
            "Data: "+mPubDate+
            "\nLink:\n"+mLink+
            "\nAutore:\n"+mAuthor+
            "\nTitolo:\n"+mTitle+
            "\nEnclosure:\n"+mEnclosure;
    }
}

private FeedReaderDbHelper dbHelper;
private FeedItemAdapter arrayAdapter;
private ArrayList<FeedItem> items;
private ListView myListView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_parse);

    items = new ArrayList<FeedItem>();
    new ArrayList<FeedItem>();

    myListView = (ListView) findViewById(R.id.myListView);
    arrayAdapter = new FeedItemAdapter(this, R.layout.feed_item, items);
    myListView.setAdapter(arrayAdapter);


    dbHelper = new FeedReaderDbHelper(this);

    //RssAsyncTask: download and parsing rss feed
    new RssAsyncTask().execute(getString(R.string.my_feed));

}

public void refreshFeed(String feed) {

    final String TAG = "refreshFeed";

    Log.i(TAG, feed);
    URL url = null;
    try {
        url = new URL(feed);

        HttpURLConnection httpConnection =  (HttpURLConnection) url.openConnection();
        int httpCode = httpConnection.getResponseCode();

        if (httpCode == HttpURLConnection.HTTP_OK) {
            processFeed(httpConnection.getInputStream());
        } else {
            Log.i(TAG, httpCode + httpConnection.getResponseMessage());
        }

    } catch (MalformedURLException e1) {
        Log.i(TAG, "MalformedUrlException in " + feed);
    } catch (IOException e) {
        Log.i(TAG, "IOException in " + url.toString());
    }
}

private void processFeed(InputStream inputStream ) {

    final String TAG = "processFeed";
    final String ITEM = "item";
    final String AUTHOR ="author";
    final String TITLE ="title";
    final String CATEGORY ="category";
    final String COMMENTS ="comments";
    final String DESCRIPTION ="description";
    final String GUID ="guid";
    final String LINK ="link";
    final String PUBDATE="pubDate";
    final String SOURCE ="source";
    final String ENCLOSURE = "enclosure";


    Log.i(TAG, inputStream.toString());
    XmlPullParserFactory pullParserFact;
    try {
        pullParserFact = XmlPullParserFactory.newInstance();
        pullParserFact.setNamespaceAware(true);

        XmlPullParser pullParser = pullParserFact.newPullParser();
        pullParser.setInput(inputStream, null);
        int eventType = pullParser.getEventType();

        while (eventType != XmlPullParser.END_DOCUMENT) {

            if (eventType == XmlPullParser.START_TAG && pullParser.getName().equals(ITEM)){
                final FeedItem item = new FeedItem();
                eventType = pullParser.next();

                while ( !(eventType == XmlPullParser.END_TAG && pullParser.getName().equals(ITEM)) ) {

                    if ( eventType == XmlPullParser.START_TAG ) {
                        String name = pullParser.getName();

                        switch (name) {
                        case AUTHOR:
                            item.mAuthor = pullParser.nextText();
                            break;
                        case TITLE:
                            item.mTitle = pullParser.nextText();
                            break;
                        case CATEGORY:
                            item.mCategory = pullParser.nextText();
                            break;
                        case COMMENTS:
                            item.mComments = pullParser.nextText();
                            break;
                        case DESCRIPTION:
                            item.mDescription = pullParser.nextText();
                            break;
                        case GUID:
                            item.mGuid = pullParser.nextText();
                            break;
                        case LINK:
                            item.mLink = pullParser.nextText();
                            break;
                        case PUBDATE:
                            item.mPubDate = pullParser.nextText();
                            break;
                        case SOURCE:
                            item.mSource = pullParser.nextText();
                            break;
                        case ENCLOSURE:
                            item.mEnclosure = pullParser.getAttributeValue(null, "url");
                        default:
                            break;
                        }

                    }

                    eventType = pullParser.next();
                }

                //download the optional enclosure resource and update UI
                new DownloadRssAsyncTask().execute(item);

            }

            eventType = pullParser.next();
        }


    } catch (XmlPullParserException e) {
        Log.i(TAG, "XmlPullparserException");
    } catch (IOException e) {
        Log.i(TAG, "IOException");
    }
}

}

1 个答案:

答案 0 :(得分:1)

由于AsyncTask的内部运作。

AsyncTask内部使用静态Handler实例,基本上是Android方式进行线程通信。使用Handler,您可以在线程上发送消息和运行代码;特别是,AsyncTask使用它来运行其回调,例如onPostExecute()

现在,当初始化Handler时,它会在初始化它的线程上绑定。在AsyncTask中,这是在类初始化/加载行中完成的:

private static final InternalHandler sHandler = new InternalHandler();

由于sHandler也是最终的,因此在此之后无法修改,并且将始终在该线程上触发回调。

在您的情况下,您在RssAsyncTask中创建onCreate()的实例,该实例在UI线程上运行。这会触发加载AsyncTask类并将AsyncTask的{​​{1}}绑定到UI线程。因此,从那时起,您的Handler将始终在UI线程上运行。尽管你在另一个后台线程中创建了一些onPostExecute()

线程规则希望确保在UI线程(see this)上加载/初始化类,并希望强制执行良好的线程实践。

另外,我建议AsyncTask用于简单的网络操作,而不是IntentService