9

在我最近的一个 SO 问题中,有人建议我使用Loader我的解决方案。所以在这里我试图了解如何实现一个简单的AsyncTaskLoader

这是我想出的:

public class Scraper extends AsyncTaskLoader<List<Event>> {

    List<Event> lstEvents;

    public Scraper(Context context) {
        super(context);
    }

    public List<Event> loadInBackground() {

            //This is where I will do some work and return the data

    }

}

这就是我想出来的。我阅读了文档,AyncTaskLoader但我从未遇到过像它这样神秘和凌乱的东西。有一百万种方法,所有这些方法都是相互对立的,看着它们,很难推断出它们被调用的顺序,甚至它们是否应该被覆盖和调用。这项任务的生命周期是一场该死的噩梦。

我正在寻找的是简单地抓取一些数据并将其返回。我还想将它存储在一个类变量中,以便下次及时返回它,而不必再次抓取所有数据。

我没有打开的游标、流或类似的东西,只有一个名为lstEvents(可能很大)的简单变量。我不想泄漏内存和浪费资源,所以如果有人能解释我需要什么来关闭/取消何时何地让这个任务工作,我会很高兴。

我应该在哪里将数据存储到类变量中?我应该在我的loadInBackground方法结束时这样做还是应该在deliverResult方法中这样做?

在这个简单的场景中,我是否真的需要检查任务是否被取消或是否被重置,或者我是否应该简单地不覆盖这些方法并让AsyncTaskLoader处理它。

如果有人知道,一些脚手架代码会很有帮助。万分感谢。

4

3 回答 3

7

在我最近的一个 SO 问题中,有人建议我使用 Loader 作为我的解决方案。

这可能不是一个好建议。

这项任务的生命周期是一场该死的噩梦。

更不用说Loader合同建议您应该能够动态检测数据的变化并自动向使用 的人提供更新Loader,这对于 a 来说很容易ContentProvider,对于其他设备上的商店来说很困难,对于像你这样的场景。

坦率地说,我只是使用AsyncTask并称它为好。

话虽如此,您可能会看看为 SQLite 数据库 (sans )所做Loader实现以及自定义加载程序的示例。您需要实现的唯一方法 是和。如果内置实现不足,您可能需要- 在您的情况下,我怀疑内置实现会很好。您可以添加一些其他方法,正如您将在的 中看到的那样,尽管我再次怀疑您不需要它们。ContentProviderSharedPreferencesloadInBackground()onStartLoading()deliverResult()AbstractCursorLoader

有没有地方我真的需要检查任务是否被取消或是否被重置,或者我是否应该简单地不覆盖这些方法并让 AsyncTaskLoader 处理它。

从让它AsyncTaskLoader处理开始,只有当您确定出于某种原因需要它们时才担心它们。

于 2012-09-27T19:59:33.290 回答
3

除了来自 CommonsWare 答案的所有好信息之外,还有另一件事需要考虑。实现时AsyncTaskLoader,您需要调用forceLoad()Loader 或AsyncTaskLoader. 否则,loadInBackground()根据我的经验,您的方法不会被调用。

根据我对文档的理解,加载程序可以在成员变量中保留其结果,就像您在问题中提出的那样。然后,您可以覆盖onStartLoading()并检查缓存的结果列表。如果列表为空,加载程序可以调用forceLoad()自身。

另请注意,如果您最终实现了缓存结果,请注意loadInBackground()在另一个线程上调用它,因此您可能希望同步对任何成员变量的访问。

于 2012-09-27T20:15:14.787 回答
1

有点晚了,但可能对正在阅读此问题的其他人有用。这是AsyncTaskLoader的一个实现:

public class EventListLoader extends AsyncTaskLoader<List<Event>> {
    private List<Event> events;

    public EventListLoader(Context context) {
        super(context);
        events = new ArrayList<Event>();
    }

    @Override
    public List<Event> loadInBackground(){
        //"Simply scrape some data and return it" as a list of events here.
    }

    @Override
    public void deliverResult(List<Event> data) {
        if (isReset()) {
            releaseResources(events);
            return;
        }

        List<Event> oldData = events;
        events = data;

        if (isStarted())
            super.deliverResult(data);

        releaseResources(oldData);
    }

    @Override
    protected void onStartLoading() {
        if (events != null && !events.isEmpty())
            deliverResult(events);

        if (takeContentChanged() || events == null || events.isEmpty())
            forceLoad();
    }

    @Override
    protected void onStopLoading() {
        super.onStopLoading();
        cancelLoad();
    }

    @Override
    public void onCanceled(List<Event> data) {
        super.onCanceled(data);
        releaseResources(events);
    }

    @Override
    protected void onReset() {
        super.onReset();
        onStopLoading();
        releaseResources(events);
    }

    private void releaseResources(List<Event> data) {
        if (data!= null && !data.isEmpty())
            data.clear();
    }
}

在 ListFragment 中使用它作为:

public class EventsListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<List<Event>> {
    private static final int LOADER_ID = 0;

    ...

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        ...
        setListAdapter(new EventListAdapter());
        if (savedInstanceState == null)
            getLoaderManager().initLoader(LOADER_ID, null, this);
        else
            getLoaderManager().restartLoader(LOADER_ID, null, this);
    }

    @Override
    public Loader<List<Event>> onCreateLoader(int id, Bundle args) {
        return new EventLoader(getActivity());
    }

    @Override
    public void onLoadFinished(Loader<List<Event>> loader, List<Event> data) {
        ((EventListAdapter) getListAdapter()).setData(data);
        invalidateActionMode(); //Only if Contextual Action Bar (CAB) is used.
    }

    @Override
    public void onLoaderReset(Loader<List<Event>> loader) {
        ((EventListAdapter) getListAdapter()).clearData();
    }

如果我们将 EventListAdapter 定义为:

public class EventListAdapter extends BaseAdapter {
    protected List<Event> mItems = new ArrayList<>();

    @Override                               
    public boolean isEnabled(int position) {
        return true;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public int getCount() {
        return mItems.size();
    }

    @Override
    public Object getItem(int position) {
        return mItems.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
       ...
    }

    public void setData(List<Event> items){
        mItems.clear();
        mItems.addAll(items);
        notifyDataSetChanged();
    }

    public void clearData(){
        mItems.clear();
        notifyDataSetChanged();
    }
}
于 2017-01-24T15:05:34.447 回答