Loader的特点和使用场所
- Loader 可以在Activity 和Fragments 的界面下运行(本篇将结合上篇文章的Fragments的DEMO进行讲述如何在Fragments 下使用Loaders)。
- 它可以提供类似于AysncTask一样的异步请求数据加载的功能,实际上它就是来源于AysncTask 的扩展并增加了很多人性化的功能,例如加载进度框、更好的控制API等。
- 它拥有一个类似于Windows Phone 开发的MVVM一样的数据改变通知机制,当数据源做出改变时会及时通知。
- 当Cursor 发生变化时,会自动加载数据,因此并不需要再重新进行数据查询。
Loader API 使用参考
- LoaderManager 每一个Activity 和 Fragments 只能存在一个LoaderManager,负责管理界面中的Loader。
- LoaderManager.LoaderCallbacks 位于LoaderManager的子接口,提供众多的回调接口操作Loader ,如初始化、创建、重新启动、销毁、结束等一系列实用接口。
- Loader 与Fragments相似,是一个基础类,可以由用户自行扩展适合自己的类
- AsyncTaskLoader 提供了一个基于AsyncTask 工作机制的Loader,查看源码可以看到其继承于Loader,并且子类LoadTask 继承于AsyncTask<Void, Void, D>,并且实现了Runable 接口,功能十分强大。本DEMO就是基于AsyncTaskLoader篇写。
- CursorLoader 提供了一个基于AsyncTaskLoader工作机制的Loader,查看源码可以看到其继承于AsyncTaskLoader,一般继承OnQueryTextListener,可用于查询、更改数据源作用。
Loader 详细使用DEMO
基于上篇的Fragments 代码,添加Loaders功能,实现加载应用程序数据到界面上,DEMO的运行效果如下:
核心代码为
应用程序的数据对象类:
public static class AppEntry { private final AppListLoader mLoader; private final ApplicationInfo mInfo; private final File mApkFile; private String mLable; private Drawable mIcon; private boolean mMounted; public AppEntry(AppListLoader loader, ApplicationInfo info) { mLoader = loader; mInfo = info; mApkFile = new File(info.sourceDir); } public ApplicationInfo getApplicationInfo() { return mInfo; } public String getLable() { return mLable; } public Drawable getIcon() { if (mIcon == null) { if (mApkFile.exists()) { mIcon = mInfo.loadIcon(mLoader.mPm); return mIcon; } else { mMounted = false; } } else if (!mMounted) { if (mApkFile.exists()) { mMounted = true; mIcon = mInfo.loadIcon(mLoader.mPm); return mIcon; } } else { return mIcon; } return mLoader.getContext().getResources().getDrawable( android.R.drawable.sym_def_app_icon); } @Override public String toString() { // TODO Auto-generated method stub return mLable.toString(); } void loadLable(Context mContext) { if (mLable == null || !mMounted) { if (!mApkFile.exists()) { mMounted = false; mLable = mInfo.packageName; } else { mMounted = true; CharSequence lable = mInfo.loadLabel(mContext .getPackageManager()); mLable = lable != null ? lable.toString() : mInfo.packageName; } } }
}
实现AsyncTaskLoader 加载数据
public static class AppListLoader extends AsyncTaskLoader<List<AppEntry>> { final InterestingConfigChanges mLastConfig = new InterestingConfigChanges(); final PackageManager mPm; List<AppEntry> mApps; packageIntentReceiver mPackageObserver; public AppListLoader(Context context) { super(context); // TODO Auto-generated constructor stub mPm = getContext().getPackageManager(); } @Override public List<AppEntry> loadInBackground() { // TODO Auto-generated method stub List<ApplicationInfo> apps = mPm .getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS); if (apps == null) apps = new ArrayList<ApplicationInfo>(); final Context mContext = getContext(); List<AppEntry> entries = new ArrayList<AppEntry>(apps.size()); for (ApplicationInfo info : apps) { AppEntry entry = new AppEntry( this, info); entry.loadLable(mContext); entries.add(entry); } Collections.sort(entries, ALPHA_COMPARATOR); return entries; } @Override public void deliverResult( List<com.xuzhi.fragment.FragmentDemoActivity.AppEntry> data) { // TODO Auto-generated method stub if (isReset()) { if (data != null) { // 释放资源处理 } } List<AppEntry> oladApps=data; mApps=data; if(isStarted()){ super.deliverResult(data); } if(oladApps!= null){ // 释放资源 } } protected void onStartLoading() { if(mApps!= null) deliverResult(mApps); if(mPackageObserver== null) mPackageObserver= new packageIntentReceiver( this); boolean configChange=mLastConfig.applyNewConfig(getContext().getResources()); if(takeContentChanged()|| mApps== null || configChange){ forceLoad(); } }; @Override public void onCanceled( List<com.xuzhi.fragment.FragmentDemoActivity.AppEntry> data) { // TODO Auto-generated method stub super.onCanceled(data); cancelLoad(); } @Override protected void onReset() { // TODO Auto-generated method stub super.onReset(); onStopLoading(); if(mApps!= null){ // 释放资源 mApps= null; } if(mPackageObserver!= null){ getContext().unregisterReceiver(mPackageObserver); mPackageObserver= null; } }
}
实现数据源:
public static class AppListAdapter extends ArrayAdapter<AppEntry>{ private LayoutInflater mInflater; public AppListAdapter(Context context) { // TODO Auto-generated constructor stub super(context, android.R.layout.simple_list_item_2); mInflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public void setData(List<AppEntry> data){ clear(); if(data!= null){ addAll(data); } } @Override public View getView( int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub View view; if(convertView== null){ view=mInflater.inflate(R.layout.list_item_icon_text, parent, false); } else{ view=convertView; } AppEntry item=getItem(position); ((ImageView)view.findViewById(R.id.icon)).setImageDrawable(item.getIcon()); ((TextView)view.findViewById(R.id.text)).setText(item.getLable()); return view; }
}
在Activity 或者Fragments 里面实现接口:
public static class DetailsFragment extends ListFragment implements OnQueryTextListener,LoaderCallbacks<List<AppEntry>>实现接口里面的函数:
public boolean onQueryTextChange(String newText) { // TODO Auto-generated method stub return false; } public boolean onQueryTextSubmit(String query) { // TODO Auto-generated method stub return false; } public Loader<List<com.xuzhi.fragment.FragmentDemoActivity.AppEntry>> onCreateLoader( int id, Bundle args) { // TODO Auto-generated method stub return new AppListLoader(getActivity()); } /** * Load 完成后 */ public void onLoadFinished( Loader<List<com.xuzhi.fragment.FragmentDemoActivity.AppEntry>> arg0, List<com.xuzhi.fragment.FragmentDemoActivity.AppEntry> arg1) { // TODO Auto-generated method stub mAdapter.setData(arg1); if (isResumed()) { setListShown( true); } else { setListShownNoAnimation( true); } } /** * Loader 重置时 */ public void onLoaderReset( Loader<List<com.xuzhi.fragment.FragmentDemoActivity.AppEntry>> arg0) { // TODO Auto-generated method stub mAdapter.setData( null);
}
得到LoaderManager初始化Loader,启动加载在Fragment 的onActivityCreated回调方法上添加,本DEMO的DetailsFragment类添加:
@Override public void onActivityCreated(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onActivityCreated(savedInstanceState); mAdapter = new AppListAdapter(getActivity()); setListAdapter(mAdapter); // Start out with a progress indicator. setListShown( false); // Prepare the loader. Either re-connect with an existing one, // or start a new one. getLoaderManager().initLoader(0, null, this);
}
总结
Loader的使用分为以下几个步骤:
- 实现自己的异步Loader ,如本篇的AsyncTaskLoader或者CursorLoader或者自己继承Loader,第二步需要用到这个Loader
- 创建数据源->public static class AppListAdapter extends ArrayAdapter<AppEntry>
- 在Activity 或者Fragments 上实现OnQueryTextListener,LoaderManager.LoaderCallbacks接口
- 在onCreateLoader里面返回Loader,在onLoadfinished里面做清除动作,在 onQueryTextChange或者onQueryTextSubmit改变数据源,在onCreate里面让Loader去执行请求数据 getLoaderManager().initLoader(0, null, this);
×××: