码迷,mamicode.com
首页 > 其他好文 > 详细

LoaderManager和Loader初步使用

时间:2015-03-11 19:43:55      阅读:201      评论:0      收藏:0      [点我收藏+]

标签:

    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的用法,显示数据



LoaderManager和Loader初步使用

标签:

原文地址:http://blog.csdn.net/dengliulin/article/details/44201503

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!