Loader的用法详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq475703980/article/details/80636315

本文主要从Loader入手, 去分析Loader使用、Loader的源码分析等,主要分为以下四篇:

本文基于原生的 Android8.0源码进行分析。

产生背景

在Android3.0之前,很多应用程序响应性能方面有缺陷。UI切换之间的小故障、activity切换延迟、ANR问题。响应性能方面的故障大多数来源于此事实—-大多数开发者在UI线程中执行了耗时操作,其中很常用的一个就是通过网络或者本地数据库进行数据加载,用这种方式载入数据是很差的选择。

比如,在Loaders之前,cursors主要通过两个Activity方法(现在已经过时deprecated)来进行管理和查询:
public void startManagingCursor(Cursor)
public Cursor managedQuery(Uri, String, String, String, String)

由于API本身的这种设计,也会给开发者一种误导:我应该在这里进行cursor查询操作。有经验的开发者都知道在这里进行异步操作,比如自己控制子线程或者AsyncTask,处理完了通过Handler回调给主线程,但是把这些交给开发者去做,开发者去管理这些也会比较费事费力,于是Google在Android3.0引入了Loader和LoaderManager类来简化该过程。

Loaders确保所有的cursor操作是异步的,从而排除了UI线程中堵塞的可能性。而且,通过LoaderManager来管理,Loaders还可以在activity实例中保持当前的cursor数据,也就是不需要重新查询(比如,当因为横竖屏切换需要重新启动activity时)。另外,当数据改变时,Loaders可以自动检测底层数据的更新和重新检索。

Loader的简单使用

Loader 机制的 使用场景 有:

  • 加载联系人

  • 加载短信

  • 网络加载数据

    我们主要讲对于本地资源的加载,也就是访问本地数据库,获取cursor。我们先来看一下Loader的使用,主要分为两步:

  • 1、创建自己的Loader

  • 2、实现在Activity或者Fragment上LoaderCallbacks接口

    下面将通过一个demo来具体介绍Loader的使用, 不过为了节省篇幅,只贴出了代码主干部分, 完全的demo请参考文末的地址。

1、 创建自己的Loader

Google已经封装得很好了,使用Loader通常都是继承自AsyncTaskLoader或者它的子类, 如CursorLoader就是AsyncTaskLoader的子类,源码中使用CursorLoader及其子类比较多。 下面看一个简单的例子及必须实现的方法:

public class AppListLoader extends AsyncTaskLoader<List<AppEntry>> {

……

  @Override
  public List<AppEntry> loadInBackground() {
    //省略具体的代码

    //最核心的方法,也是必须实现的方法
//此处用来去真正加载数据, 数据加载完成后返回数据
    //数据最终会回调给 回调接口的onLoadFinished 方法
  ……
    List<AppEntry> entries = new ArrayList<AppEntry>(apps.size());
  ……
    //返回我们的数据泛型的类型
    return entries;
  }

@Override
 public void deliverResult(List<AppEntry> apps) {
 //此方法可不实现,但是如果实现了此方法,则必须调用super. deliverResult
 //正常流程都需要调用父类的deliverResult, 此方法用来分发数据
//把loadInBackground加载完的数据回调到onLoadFinished方法中
super.deliverResult(apps);
}


/**
 * 子类必须实现的方法, 启动Loader调用
 */
 @Override
  protected void onStartLoading() {
    if (mApps != null) {
      deliverResult(mApps);
    }

    //如果想监听数据源, 可以再开始加载数据前,去设置一个数据监听,当数据源变化, 就回调给自己设置的监听
    if (mAppsObserver == null) {
      mAppsObserver = new InstalledAppsObserver(this);
    }

    if (takeContentChanged()) {
      //如果想真正开始加载数据, 则必须调用forceLoad()方法
      forceLoad();
    } else if (mApps == null) {
      forceLoad();
    }
  }

@Override
  protected void onStopLoading() {
    // The Loader has been put in a stopped state, so we should attempt to
    // cancel the current load (if there is one).
    cancelLoad();

    // Note that we leave the observer as is; Loaders in a stopped state
    // should still monitor the data source for changes so that the Loader
    // will know to force a new load if it is ever started again.
  }


 /**
  * 重置 Loader
  */
  @Override
  protected void onReset() {
    // Ensure the loader is stopped.
    onStopLoading();

    // At this point we can release the resources associated with 'apps'.
    if (mApps != null) {
      releaseResources(mApps);
      mApps = null;
    }

    // The Loader is being reset, so we should stop monitoring for changes.
    if (mAppsObserver != null) {
      getContext().unregisterReceiver(mAppsObserver);
      mAppsObserver = null;
    }

    if (mLocaleObserver != null) {
      getContext().unregisterReceiver(mLocaleObserver);
      mLocaleObserver = null;
    }
  }

  @Override
  public void onCanceled(List<AppEntry> apps) { 
    super.onCanceled(apps);

    // The load has been canceled, so we should release the resources
    // associated with 'mApps'.
    releaseResources(apps);
  }

  /**
   * 可以不用实现,父类通过此方法去加载数据,
   * 内部会调用 loadInBackground()
   */
  @Override
  public void forceLoad() {
    super.forceLoad();
  }

……
}

2、在Activity或者Fragment中实现LoaderCallbacks回调接口

LoaderCallbacks接口主要有三个方法, 实现如下:

public class LoaderDemoFragment extends ListFragment implements
      LoaderManager.LoaderCallbacks<List<AppEntry>> {

@Override
    public Loader<List<AppEntry>> onCreateLoader(int id, Bundle args) {
      //这个方法主要用来创建我们需要的Loader
      //在这里我们还可以做一些想做的事
      return new AppListLoader(getActivity());
    }

    @Override
    public void onLoadFinished(Loader<List<AppEntry>> loader, List<AppEntry> data) {
      //数据加载完毕会回调到这个方法, 
      mAdapter.setData(data);

      if (isResumed()) {
        setListShown(true);
      } else {
        setListShownNoAnimation(true);
      }
    }

    @Override
    public void onLoaderReset(Loader<List<AppEntry>> loader) {
     //该方法将在 先前创建的加载器重置 且 数据因此不可用 时调用,
//通过此回调我们可以了解何时将释放数据,因此能够及时移除其引用。
      mAdapter.setData(null);
    }


 /**
   * 找一个合适的地方, 初始化Loader
   */
@Override
    public void onActivityCreated(Bundle savedInstanceState) {
      super.onActivityCreated(savedInstanceState); 
      // 参数:id ,唯一标识, Bundle,额外的数据, LoaderCallbacks接口
      getLoaderManager().initLoader(LOADER_ID, null, this);
    }
}

Loader的使用流程大致就是这样,详细的代码可以去这个地址下载demodemo下载

后面讲继续分析Loader的源码部分,了解Loader实现原理。

猜你喜欢

转载自blog.csdn.net/qq475703980/article/details/80636315