Loader的特点和使用场所

 

  1.  Loader 可以在Activity 和Fragments 的界面下运行(本篇将结合上篇文章的Fragments的DEMO进行讲述如何在Fragments 下使用Loaders)。
  2. 它可以提供类似于AysncTask一样的异步请求数据加载的功能,实际上它就是来源于AysncTask 的扩展并增加了很多人性化的功能,例如加载进度框、更好的控制API等。
  3. 它拥有一个类似于Windows Phone 开发的MVVM一样的数据改变通知机制,当数据源做出改变时会及时通知。
  4. 当Cursor 发生变化时,会自动加载数据,因此并不需要再重新进行数据查询。

Loader API 使用参考

 

  1. LoaderManager
    每一个Activity 和 Fragments 只能存在一个LoaderManager,负责管理界面中的Loader。
  2. LoaderManager.LoaderCallbacks
    位于LoaderManager的子接口,提供众多的回调接口操作Loader ,如初始化、创建、重新启动、销毁、结束等一系列实用接口。
  3. Loader
    与Fragments相似,是一个基础类,可以由用户自行扩展适合自己的类
  4. AsyncTaskLoader
    提供了一个基于AsyncTask 工作机制的Loader,查看源码可以看到其继承于Loader,并且子类LoadTask 继承于AsyncTask<Void, Void, D>,并且实现了Runable 接口,功能十分强大。本DEMO就是基于AsyncTaskLoader篇写。
  5. 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的使用分为以下几个步骤:

 

  1.  实现自己的异步Loader ,如本篇的AsyncTaskLoader或者CursorLoader或者自己继承Loader,第二步需要用到这个Loader
  2. 创建数据源->public static class AppListAdapter extends ArrayAdapter<AppEntry>
  3. 在Activity 或者Fragments 上实现OnQueryTextListener,LoaderManager.LoaderCallbacks接口
  4. 在onCreateLoader里面返回Loader,在onLoadfinished里面做清除动作,在 onQueryTextChange或者onQueryTextSubmit改变数据源,在onCreate里面让Loader去执行请求数据 getLoaderManager().initLoader(0, null, this);

 

×××: