https://developer.android.com/reference/android/content/AsyncTaskLoader.html
什么是loader loader是干什么的
Loader一个执行异步数据加载的类。在Loader处于活动状态时,应该监视其数据源并在内容发生更改时提供新的结果。
Loader有两个子类,AsyncTaskLoader和CursorLoader
在本次简单实例中我们用的就是CursorLoader进行加载数据。对Cursor进行操作,建议使用CursorLoader。
有时CursorLoader不能满足我们的需求,需要我们自定义Loader,一般情况下,我们不直接集成Loader,而是继承AsyncTaskLoader。
子类通常必须至少实现onStartLoading(),onStopLoading(),onForceLoad()和onReset()。
- 在单独的线程中加载数据,并不会阻塞UI线程
- 监听数据的变化
- Activity配置发生变化如屏幕横竖屏切换,不会在重新加载数据。
什么是LoaderManager
LoaderManager是专门管理Loader的管理器,一个Activity或者Fragment只能有一个LoaderManager,一个LoaderManager可以管理多个Loader,LoaderManager管理Loader的各种事件。
Loader的简单使用
public class LoaderDemoActivity extends AppCompatActivity {
private ListView listView;
private SimpleCursorAdapter adapter;
private CursorLoader loader;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_loader_demo);
initView();
}
private void initView() {
listView = (ListView) findViewById(R.id.lv_loader_demo);
adapter = new SimpleCursorAdapter(this, R.layout.item_loader_demo, null, new String[]{MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.DATA}, new int[]{R.id.tv_loader_music, R.id.tv_loader_who_music, R.id.tv_loader_path}, 0);
listView.setAdapter(adapter);
getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks() {
@Override
public Loader onCreateLoader(int id, Bundle args) {
Toast.makeText(LoaderDemoActivity.this, "创建Loader", Toast.LENGTH_SHORT).show();
loader = new CursorLoader(LoaderDemoActivity.this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
return loader;
}
@Override
public void onLoadFinished(Loader loader, Cursor data) {
Toast.makeText(LoaderDemoActivity.this, "Loader加载完成", Toast.LENGTH_SHORT).show();
adapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader loader) {
Toast.makeText(LoaderDemoActivity.this, "Loader重置", Toast.LENGTH_SHORT).show();
adapter.swapCursor(null);
}
});
}
}
在Activity中创建一个Loader,首先调用getLoaderManager方法,获取LoaderManager,在调用initLoader方法会返回一个Loader。
- initLoader
确保Loader已经初始化,并且处于活动状态,如果Loader不存在,会创建一个加载器,如果存在会复用之前的加载器。initLoader有三个参数:
- id 区分不同的Loader
- Bundle 一个可选的参数
- LoaderManager.LoaderCallbacks
callback 回调接口
LoaderManager.LoaderCallbacks
- onCreateLoader 实例化并根据给定的id返回一个新的Loader
- onLoadFinished 在加载完成时调用 data是由Loader生成的数据
- onLoaderReset 表示正在重置,在这个方法中应该删除对数据的引用。
Loader类源码分析
接口
- public final class ForceLoadContentObserver extends ContentObserver
public final class ForceLoadContentObserver extends ContentObserver {
public ForceLoadContentObserver() {
super(new Handler());
}
@Override
public boolean deliverSelfNotifications() {
return true;
}
@Override
public void onChange(boolean selfChange) {
onContentChanged();
}
}
deliverSelfNotifications 如果返回true,观察者将自我接受更改通知
ContentObserver的一个实现类,负责将他链接到Loader,当观察者告诉它数据已经改变时,Loader会重新加载数据,通常不需要自己使用,当cursor的数据发生改变时,CursorLoader会使用它来执行更新。onChange 当观察的内容发生改变时才被调用。子类应该重写来处理内容更改的逻辑。
public interface OnLoadCompleteListener
public interface OnLoadCompleteListener {
/**
* Called on the thread that created the Loader when the load is complete.
*
* @param loader the loader that completed the load
* @param data the result of the load
*/
public void onLoadComplete(Loader loader, D data);
}
OnLoadCompleteListener是一个接口,用于发现loader何时加载完数据。不需要我们来实现,是由LoaderManager实现。
唯一方法 onLoadComplete 在加载完成时,调用在创建Loader的线程,data就是加载的结果。
- OnLoadCanceledListener
public interface OnLoadCanceledListener {
/**
* Called on the thread that created the Loader when the load is canceled.
*
* @param loader the loader that canceled the load
*/
public void onLoadCanceled(Loader loader);
}
用于在加载数据完之前检查加载器何时取消。也是,不需要我们来实现,LoaderManager会处理。onLoadCanceled唯一实现方法,在此方法调用时,应该释放数据。
方法
- deliverResult
public void deliverResult(D data) {
if (mListener != null) {
mListener.onLoadComplete(this, data);
}
}
将加载的结果返回给注册的监听器。只能由子类调用。必须从进程的主线程中调用。
- deliverCancellation
public void deliverCancellation() {
if (mOnLoadCanceledListener != null) {
mOnLoadCanceledListener.onLoadCanceled(this);
}
}
通知已经注册的Loader.OnLoadCanceledListener接口Loader已经取消。只能由子类调用。必须从进程的主线程中调用。
- getContext getId
/**
* @return an application context retrieved from the Context passed to the constructor.
*/
public Context getContext() {
return mContext;
}
/**
* @return the ID of this loader
*/
public int getId() {
return mId;
}
返回上下文
返回Loader的ID
- registerListener 和 unregisterListener
/**
* Registers a class that will receive callbacks when a load is complete.
* The callback will be called on the process's main thread so it's safe to
* pass the results to widgets.
*
* Must be called from the process's main thread.
*/
public void registerListener(int id, OnLoadCompleteListener listener) {
if (mListener != null) {
throw new IllegalStateException("There is already a listener registered");
}
mListener = listener;
mId = id;
}
/**
* Remove a listener that was previously added with {@link #registerListener}.
*
* Must be called from the process's main thread.
*/
public void unregisterListener(OnLoadCompleteListener listener) {
if (mListener == null) {
throw new IllegalStateException("No listener register");
}
if (mListener != listener) {
throw new IllegalArgumentException("Attempting to unregister the wrong listener");
}
mListener = null;
}
- registerListener:注册一个将在加载完成时接受回调的类。必须主线程中调用
- unregisterListener:移除监听器
- registerOnLoadCanceledListener 和 unregisterOnLoadCanceledListener
/**
* Registers a listener that will receive callbacks when a load is canceled.
* The callback will be called on the process's main thread so it's safe to
* pass the results to widgets.
*
* Must be called from the process's main thread.
*
* @param listener The listener to register.
*/
public void registerOnLoadCanceledListener(OnLoadCanceledListener listener) {
if (mOnLoadCanceledListener != null) {
throw new IllegalStateException("There is already a listener registered");
}
mOnLoadCanceledListener = listener;
}
/**
* Unregisters a listener that was previously added with
* {@link #registerOnLoadCanceledListener}.
*
* Must be called from the process's main thread.
*
* @param listener The listener to unregister.
*/
public void unregisterOnLoadCanceledListener(OnLoadCanceledListener listener) {
if (mOnLoadCanceledListener == null) {
throw new IllegalStateException("No listener register");
}
if (mOnLoadCanceledListener != listener) {
throw new IllegalArgumentException("Attempting to unregister the wrong listener");
}
mOnLoadCanceledListener = null;
}
- registerOnLoadCanceledListener:注册一个将在加载被取消时接收回调的侦听器。
- unregisterOnLoadCanceledListener:取消注册的registerOnLoadCanceledListener(Loader.OnLoadCanceledListener)的侦听器
- isStarted 和 isAbandoned和isReset
/**
* Return whether this load has been started. That is, its {@link #startLoading()}
* has been called and no calls to {@link #stopLoading()} or
* {@link #reset()} have yet been made.
*/
public boolean isStarted() {
return mStarted;
}
/**
* Return whether this loader has been abandoned. In this state, the
* loader must not report any new data, and must keep
* its last reported data valid until it is finally reset.
*/
public boolean isAbandoned() {
return mAbandoned;
}
/**
* Return whether this load has been reset. That is, either the loader
* has not yet been started for the first time, or its {@link #reset()}
* has been called.
*/
public boolean isReset() {
return mReset;
}
- isStarted:返回这个Loader是否已经被加载。如果返回true表示已经调用了startLoading方法,并且没有调用stopLoading方法或者reset方法。
- isAbandoned:返回这个Loader是否被放弃。如果返回true,Loader不能发送任何新的数据,并且必须保持上次发送的数据有效值。知道调用reset。
- isReset:返回这个Loader是否被重置。也就是说,加载程序尚未第一次启动,或者调用了reset()。
startLoading
public final void startLoading() {
mStarted = true;
mReset = false;
mAbandoned = false;
onStartLoading();
}
当相关的Activity或者Fragment正在启动时,LoaderManager通常会自动调用这个方法,与LoaderManager一起使用时,不要自己调用这个方法,否则会和LoaderManager发生冲突。loader会异步加载数据,当结果准备就绪时,回调会发生在主线程。如果之前的数据加载完成,并且有效,则结果立即传递给回调,Loader将监听数据源,如果有更改,则提供新的数据。调用stopLoading()将停止传递回调。
这会更新Loader的内部状态,以便isStarted()和isReset()将返回正确的值,然后调用实现的onStartLoading()。
必须从进程的主线程中调用。
cancelLoad
public boolean cancelLoad() {
return onCancelLoad();
}
尝试取消当前加载任务。
取消的操作不是立即执行,因为数据加载在后台进程。如果loader当前正在进行加载,此时调用这个方法要求取消加载,在这种情况,一旦后台进程完成加载工作,其余的状态都会被清除。如果在此期间另一个Loader请求加载,它会一直保持取消加载完成。
此方法有个boolean返回值,如果任务无法取消,返回false,通常是因为loader在后台已经正常完成了,也有可能没有调用startLoading。如果返回true,任务仍在继续运行,当任务完成时将调用Loader.OnLoadCanceledListener。
- onCancelLoad
protected boolean onCancelLoad() {
return false;
}
子类必须实现这个方法,处理取消的逻辑。
- forceLoad 和 onForceLoad
public void forceLoad() {
onForceLoad();
}
/**
* Subclasses must implement this to take care of requests to {@link #forceLoad()}.
* This will always be called from the process's main thread.
*/
protected void onForceLoad() {
}
- forceLoad 强制进行异步加载。和startLoading不同,忽略以前的数据,加载一个新的数据。通常只有加载程序启动时才应该调用这个方法,也就是说isStart返回true。
- 子类必须实现这个方法来处理forceLoad的请求。
- stopLoading 和 onStopLoading
public void stopLoading() {
mStarted = false;
onStopLoading();
}
/**
* Subclasses must implement this to take care of stopping their loader,
* as per {@link #stopLoading()}. This is not called by clients directly,
* but as a result of a call to {@link #stopLoading()}.
* This will always be called from the process's main thread.
*/
protected void onStopLoading() {
}
- stopLoading
通常来说会被Loader Manager自动调用,当相关的Activity或者Fragment停止时,不需要自己调用,否则会和LoaderManager发生冲突。
停止传递更新,知道下一此调用startLoading。在此时实现不应该数据无效,客户端仍然可以使用上一次发送的数据。但是如果数据发生改变,就不会发送新的数据。仍然会监听数据源更改,但是不发送新数据给客户端,直到startLoading被调用。
这将更新Loader的内部状态,以便isStarted()将返回正确的值,然后调用实现的onStopLoading()。
- onStopLoading:子类必须实现这个来停止它们的加载器。这不是由客户端直接调用,而是由stopLoading()调用结果。这将始终从进程的主线程中调用。
- abandon 和 onAbandon
public void abandon() {
mAbandoned = true;
onAbandon();
}
protected void onAbandon() {
}
abandon: 在LoaderManager重新启动Loader时,通常会自动调用这个方法,和Loader Manager一起使用时,不能自己调用方法,否则会和LoaderManager发生冲突,告诉Loader,它正在被放弃,这是在reset之前,让他保留当前的数据,但不发送任何新数据。
onAbandon:子类必须重新实现被放弃方法,这个是在onRest方法之前可选的中间状态,这意味着客户端对来自加载器的数据不在关注,此时Loader不需要在发送新的数据。但是Loader必须保证上次数据是有效的,直到onReset被调用,可以使用isAbandoned方法检索当前的废弃状态。
- reset
public void reset() {
onReset();
mReset = true;
mStarted = false;
mAbandoned = false;
mContentChanged = false;
mProcessingChange = false;
}
protected void onReset() {
}
reset
这个方法通常是在Loader正在销毁时被LoaderManager自动调用的,和LoaderManager一起使用时,自己不要去调用这个方法,否则会和LoaderManager发生冲突。
这个方法会重置Loader的状态,在这一点上,应该释放所有的资源,因为可用不会再次调用这个方法。
也有可能会调用startLoading方法,此时loader必须可以再次运行。
此方法会更新内部的状态,以便isStarted()和isReset()将返回正确的值,然后调用实现的onReset()。onReset
子类要想重置Loader必须实现此方法,
- takeContentChanged
/**
* Take the current flag indicating whether the loader's content had
* changed while it was stopped. If it had, true is returned and the
* flag is cleared.
*/
public boolean takeContentChanged() {
boolean res = mContentChanged;
mContentChanged = false;
mProcessingChange |= res;
return res;
}
获取当前的标志,查看Loader加载的内容是否在停止前发生了改变,如果有,返回true,,并清除标志位。
- commitContentChanged
public void commitContentChanged()
mProcessingChange = false;
}
根据takeContentChanged的返回值,提交已经处理完的更改的内容。与rollbackContentChanged()一起使用来处理加载被取消的情况。 当你处理一个Loader而不被取消的时候调用它。
- rollbackContentChanged
public void rollbackContentChanged() {
if (mProcessingChange) {
onContentChanged();
}
}
通知已放弃由takeContentChanged()返回的内容更改的处理,并且想要回滚到还有待处理内容更改的状态。 这是为了处理在数据被传送回加载程序之前由于内容改变而导致的数据加载已被取消的情况。
- onContentChanged
public void onContentChanged() {
if (mStarted) {
forceLoad();
} else {
// This loader has been stopped, so we don't want to load
//Loader已经停止了,所以我们不加载
// new data right now... but keep track of it changing to
//新的数据现在...但跟踪它改变
// refresh later if we start again.
//如果再一次启动,等待数据刷新
mContentChanged = true;
}
}
Loader.ForceLoadContentObserver检测到有更改时调用, 默认实现检查Loader是否当前启动; 如果是,它只是简单地调用forceLoad(); 否则,它设置一个标志,以便takeContentChanged()返回true。