LoaderManager和Loader初步使用

Android 3.0中提供了一个新概念Loaders,这两天看了之前Contacts的源码,其中自己写了通话记录部分,发现源码里面有很多LoaderManager的使用,现在做一个总结,记录一下LoaderManager的基本用法:

这个其实是分为两部分:LoaderManager和自定义Loader,比如像加载联系人,短信这些系统提供ContentProvider的数据时,其实就是返回一个标准cursor,那我们就没必要自定义loader  直接用loaderManager来管理这个CursorLoader,这是一种简单普遍的情况。还有一种就是我们要加载非cursor类型的数据时,就必须自定义loader了。

1.
LoaderManager和CursorLoader

举例用一个listFragment加载联系人,那么让它实现LoaderManager.LoaderCallbacks<Cursor> 接口,必须重写下面3个方法:

onCreateLoader:  这个是创建一个CursorLoader并返回,我们在里面new一个CursorLoader并返回就OK了

onLoadFinished: 这个是加载完成后更新UI,在这里就是setAdapter了  而这个加载过程其实就是在CursorLoader里面完成的,只不过系统帮我们完成了,而如果自定义loader的话就要自己完成,这就是区别!

onLoaderReset: loader的重置,在这里一般让UI不显示数据就行

就这么3个方法就可以完成数据加载了,核心就是把CursorLoader构造出来,至于加载过程,数据监听更新这些就有系统去完成吧!

<span style="font-size:14px;">public class ContactsFragment extends ListFragment implements LoaderManager.LoaderCallbacks
<Cursor>{
		private SimpleCursorAdapter mAdapter;
		 private final String[] CONTACTS_PROJECTION = new String[]{Contacts._ID,
			        Co<span style="font-size:14px;">ntacts.DISPL</span>AY_NAME,
			        Contacts.CONTACT_STATUS,
			        Contacts.CONTACT_PRESENCE,
			        Contacts.PHOTO_ID,
			        Contacts.LOOKUP_KEY,
};

		@Override
		public void onActivityCreated(Bundle savedInstanceState) {
			// TODO Auto-generated method stub
			super.onActivityCreated(savedInstanceState);
			setEmptyText("当前没有联系人");
			mAdapter = new SimpleCursorAdapter(getActivity(),
	                android.R.layout.simple_list_item_2, null,
	                new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },
	                new int[] { android.R.id.text1, android.R.id.text2 }, 0);
			setListAdapter(mAdapter);
			getLoaderManager().initLoader(1, null, this);
		}
		@Override
		public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
			// TODO Auto-generated method stub
			String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
	                + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
	                + Contacts.DISPLAY_NAME + " != '' ))";

			return new CursorLoader(getActivity(), Contacts.CONTENT_URI,
<span style="font-size:14px;"> </span>CONTACTS_PROJECTION, select, null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
		}

		@Override
		public void onLoadFinished(Loader<Cursor> arg0, Cursor arg1) {
			// TODO Auto-generated method stub
			mAdapter.swapCursor(arg1);
		}

		@Override
		public void onLoaderReset(Loader<Cursor> arg0) {
			// TODO Auto-generated method stub
			  mAdapter.swapCursor(null);

		}

	}</span>

2. 自定义Loader

但有些拿不到cursor这样的数据,我们就需要自定义Loader,其实在Loader里面只需要重写两个方法:一个onStartLoading,还有一个loadInBackground,但为了代码更加完善一些,再重写另外几个方法:   onStopLoading   onReset    onCanceled,可以类比activity的生命周期,然后参考google文档进行重写,先贴出代码:

public class MySmsLoader extends AsyncTaskLoader<List<SmsEntry>> {
private PackageManager mPm;
private InstalledAppsObserver mAppsObserver;
	public MySmsLoader(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		mPm = getContext().getPackageManager();
		Log.d("dml", "new一个MySmsLoader");
	}

	@Override
	public List<SmsEntry> loadInBackground() {
		Log.d("dml", "loadInBackground--------" );
		// TODO Auto-generated method stub
		 // Retrieve all installed applications.
	    List<ApplicationInfo> apps = mPm.getInstalledApplications(0);
	    Log.d("dml", "apps >>>>>>>>>>" + apps);
	    if (apps == null) {
	    	Log.d("dml", "apps null");
	      apps = new ArrayList<ApplicationInfo>();
	    }

	    // Create corresponding array of entries and load their labels.
	    List<SmsEntry> entries = new ArrayList<SmsEntry>(apps.size());
	    for (int i = 0; i < apps.size(); i++) {
	    	SmsEntry entry = new SmsEntry();
	      entry.setFrom_name(i+"::::::::");
	      entry.setSend_time(apps.get(i).packageName);
	      entries.add(entry);
	    }
	    Log.d("dml", "entries---->>>>>>>>>----" + entries);
		return entries;
	}

	@Override
		protected void onStartLoading() {
			// TODO Auto-generated method stub
			super.onStartLoading();
			if (mAppsObserver == null) {
			      mAppsObserver = new InstalledAppsObserver(this);
			    }
			 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.
	  }

	  @Override
	  protected void onReset() {

	    // Ensure the loader is stopped.
	    onStopLoading();

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

	  }

	  @Override
	  public void onCanceled(List<SmsEntry> apps) {

	    // Attempt to cancel the current asynchronous load.
	    super.onCanceled(apps);

	    // The load has been canceled, so we should release the resources
	    // associated with 'mApps'.
	    releaseResources(apps);
	  }
	  private void releaseResources(List<SmsEntry> apps) {
		    // For a simple List, there is nothing to do. For something like a Cursor,
		    // we would close it in this method. All resources associated with the
		    // Loader should be released here.
		  }

}

onStartLoading:注册一些监听器到loader上,并且执行一次forceLoad(); 否则loader不会开始工作

loadInBackground:不用说,在这里就是加载数据并且返回,其实这个数据就返回到了LoaderManager的

onLoadFinished方法第二个参数

onStopLoading:停止加载数据,但不要停止监听也不要释放数据,就可以随时重启loader

onReset:先确保已经停止加载数据了,然后释放掉监听器并设为null

onCanceled: 在这里可以释放资源,如果是list就不需要做什么了,但是象cursor或者打开了什么文件就应该关闭一下

这几个生命周期方法还不是非常清楚,但就象activity的生命周期一样,可以里面的细节不是很了解  但我们还是可以很熟练的使用activity,除了这几个还有一个deliverResult(),确实没弄懂,留到以后在体会吧!

下面就是监听器的代码,注意是在构造方法中绑定到loader:

public class InstalledAppsObserver extends BroadcastReceiver {
  private static final String TAG = "ADP_InstalledAppsObserver";
  private static final boolean DEBUG = true;

  private MySmsLoader mLoader;

  public InstalledAppsObserver(MySmsLoader loader) {
    mLoader = loader;

    // Register for events related to application installs/removals/updates.
    IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
    filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
    filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
    filter.addDataScheme("package");
    mLoader.getContext().registerReceiver(this, filter);

    // Register for events related to sdcard installation.
    IntentFilter sdFilter = new IntentFilter();
    sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
    sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
    mLoader.getContext().registerReceiver(this, sdFilter);
  }

  @Override
  public void onReceive(Context context, Intent intent) {
    if (DEBUG) Log.i(TAG, "+++ The observer has detected an application change!" +
    		" Notifying Loader... +++");

    // Tell the loader about the change.
    mLoader.onContentChanged();
  }
}

剩下的工作就和之前一样了,在LoaderManager里面拿到loader返回的数据,更新UI:

public class SmsFragment extends ListFragment implements LoaderCallbacks
<List<SmsEntry>>{
	private SmsAdapter adapter;
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onActivityCreated(savedInstanceState);
		Log.d("dml", "进入SmsFragment ");
		adapter = new SmsAdapter(getActivity());
		 setEmptyText("No applications");
	      setListAdapter(adapter);
	      setListShown(false);
		 getLoaderManager().initLoader(2, null, this);
	}

	@Override
	public Loader<List<SmsEntry>> onCreateLoader(int arg0, Bundle arg1) {
		// TODO Auto-generated method stub
		Log.d("dml", " onCreateLoader");
		return new MySmsLoader(getActivity());
	}

	@Override
	public void onLoadFinished(Loader<List<SmsEntry>> arg0,
			List<SmsEntry> arg1) {
		// TODO Auto-generated method stub
		Log.d("dml", " onLoadFinished>>>>>>>arg1:  " + arg1);
		adapter.setData(arg1);

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

	@Override
	public void onLoaderReset(Loader<List<SmsEntry>> arg0) {
		// TODO Auto-generated method stub
		Log.d("dml", " onLoaderReset");
		adapter.setData(null);
	}

	class SmsAdapter extends ArrayAdapter<SmsEntry>{
		private LayoutInflater inflater;
		public SmsAdapter(Context context) {
			super(context,android.R.layout.simple_list_item_2);
			// TODO Auto-generated constructor stub
			Log.d("dml", " new SmsAdapter--------");
			inflater = (LayoutInflater) context.getSystemService
(context.LAYOUT_INFLATER_SERVICE);
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			// TODO Auto-generated method stub
			Log.d("dml", "getView-------- ");
			View view = convertView;
			ViewHolder holder;
			if(view==null){
				view = inflater.inflate(R.layout.item, parent,false);
				holder = new ViewHolder();
				holder.name = (TextView) view.findViewById(R.id.name);
				holder.date = (TextView)view.findViewById(R.id.date);
				view.setTag(holder);
			}
			else{
				holder = (ViewHolder)view.getTag();
			}
			SmsEntry item = getItem(position);
			Log.d("dml", "item-------- " + item);
			holder.name.setText(item.from_name);
			holder.date.setText(item.send_time);
			return view;
		}

		private class ViewHolder{
			TextView name;
			TextView date;
		}

		public void setData(List<SmsEntry> data){
			clear();
			if(data!=null){
				Log.d("dml", "data-------- " + data);
				for(int i=0;i<data.size();i++){
					add(data.get(i));

				}
			}
		}
	}

}

可以看出这里的数据结构由原来的cursor变成了自定义的SmsEntry,另外在这里要学会自定义ArrayAdapter的用法,显示数据

				
时间: 2024-11-05 16:34:57

LoaderManager和Loader初步使用的相关文章

LoaderManager与Loader使用理解

一.LoaderManager与Loader出现背景 LoaderManager与Loader是在Android3.0以后出现的用于数据异步加载的类库.出现的原因就是为了使得我们的用户有更好的体验.因为在3.0以前每次我们加载数据都是在UI线程里面进行,并且Android相应的API也提供了相应加载数据的方法.这就是为什么3.0以前的系统打开App的特别卡,甚至有时候会打不开.其实我们都知道,数据的加载最好放到一个线程里面实现,让数据的加载不要影响到UI的渲染.(用户看到动画慢慢变化心里也是很踏

深入源码解析Android中Loader、AsyncTaskLoader、CursorLoader、LoaderManager

如果对Loader.AsyncTaskLoader.CursorLoader.LoaderManager等概念不明白或不知道如何使用Loader机制,可参见博文Android中Loader及LoaderManager的使用(附源码下载).本文主要通过研究Loader及其子类的生命周期的方式来对Loader及其子类.LoaderManager的源码进行研究. Loader是靠LoaderManager管理的,LoaderManager可以同时管理多个Loader,即LoaderManager与Lo

Android中Loader及LoaderManager的使用(附源码下载)

managedQuery方法的缺陷 Loader是用来更好地加载数据的,在我们谈论Loader之前,我们先研究一下Activity的managedQuery方法,该方法也是用于在Activity中加载数据的.在Android 3.0之前的版本中,我们如果想在Activity中通过ContentResolver对ContentProvider进行查询,我们可以方便的调用Activity的managedQuery方法,该方法的源码如下: @Deprecated public final Cursor

LoaderManager使用详解(二)---了解LoaderManager

了解LoaderManager 这篇文章将介绍LoaderManager类,这是该系列的第二篇文章. 一:Loaders之前世界 二:了解LoaderManager 三:实现Loaders 四:实例:AppListLoader 注意: 要了解这一LoaderManager这部分知识,要求对Loaders如何工作有基本了解.Loaders的实现将在下一篇文章中涵盖.现在你只需要将Loaders看成一个简单.字包含的对象.该对象特性包括:1.在一个单独线程载入数据:2.监测底层数据源,当探测到有改变

使用Loader实时查询本地数据库用法

在看Android的文档时,看到了这么一个东西: Loader 究竟是什么东西呢? Introduced in Android 3.0, loaders make it easy to asynchronously load data in an activity or fragment. Loaders have these characteristics: 1.They are available to every Activity and Fragment.  //支持Activity和F

Android之数据存储----使用LoaderManager异步加载数据库

一.各种概念: 1.Loaders: 适用于Android3.0以及更高的版本,它提供了一套在UI的主线程中异步加载数据的框架.使用Loaders可以非常简单的在Activity或者Fragment中异步加载数据,一般适用于大量的数据查询,或者需要经常修改并及时展示的数据显示到UI上,这样可以避免查询数据的时候,造成UI主线程的卡顿. 即使是查询SQLite数据库,用Loaders来操作会更加的简便. Loaders有以下特点: 可以适用于Activity和Fragment. 可以提供异步的方式

Android 深入理解Loader机制 让APP轻装上阵

本文简书同步发布,谢谢关注. -http://www.jianshu.com/p/385327e35711 Android开发者都经历过APP UI开发不当 会造成overDraw,导致APP UI渲染过慢,但是很多人却没听过overLoad,overLoad一般是由于开发者在主线程操作耗时操作,导致程序变慢 甚至出现的anr的现象,那么android早已为这种现象提供完美的解决方案,就是今天给大家说的Loader机制. 一 Loader Android的装载器(loader)是从Android

android之LoaderManager原理分析

一.    LoaderManager的使用 LoaderManager用于异步加载数据,当然,它异步的实现依赖于AsyncTask的原理.如果不深究它的实现原理,这个LoaderManager的使用还是很简单的.我们只需要实现LoaderCallbacks类,然后调用getLoaderManager().initLoader()就可以了,执行加载数据的语句写在LoaderCallbacks类的onCreateLoader()方法中,如果加载完毕,我们可以在onLoadFinished()方法中

android Loader机制

Activity和Fragment管理LoaderManager,LoaderManager管理Loader,Loader得到数据后触发在LoaderManager中实现的Loader的callback接口,LoaderManager在接收到Loader的callback回传调运时触发我们Activity或Fragment中实现的LoaderManager回调callback接口,就这样就实现了Loader的所有功能,而我们平时写代码一般只用关心LoaderManager的callback实现即