java - 在 doInBackground 方法中从另一个异步任务调用 AsyncTask?

标签 java android multithreading android-asynctask adapter

我从 AsyncTask1 调用了 AsyncTask2...这是我的“场景”:

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

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

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

编辑 这里有一些代码...... 下载RssAsyncTask = 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");
    }
}

最佳答案

因为 AsyncTask 的内部工作原理。

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

现在,当 Handler 被初始化时,它绑定(bind)到初始化它的线程上。在 AsyncTask 中,这是在类初始化/加载期间完成的:

private static final InternalHandler sHandler = new InternalHandler();

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

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

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

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

关于java - 在 doInBackground 方法中从另一个异步任务调用 AsyncTask?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23979766/

相关文章:

java - 使用spring boot使用gmail smtp发送邮件

java - Mockito - 当调用 void 方法时设置一个标志

android - 如何使用异步任务以编程方式检查蓝牙是否已与其他设备连接?

Java线程,从主线程更改值

java - 当我完成运行时,如何将 IntelliJ 上的控制台输出设置在底部

java - 从文件 BufferedReader 获取文本,输出看起来不错,但不等于 "true"或 "false"(文件中的内容)

Android,为什么一个 Fragment 不能直接调用另一个?

android - 停止的前台服务自行重启

c# - 有没有办法为整个应用程序设置文化?所有当前线程和新线程?

ios - dataWithContentsOfURL(线程)和dataTaskWithURL之间有什么区别吗?