天天看點

Android_Loader_使用LoaderManager管理Loader實作異步動态加載資料1.Loader特性:2.Loader相關類接口3.簡單使用Loaders4.loader向下相容 5.應用

本博文為子墨原創,轉載請注明出處! http://blog.csdn.net/zimo2013/article/details/10263339

1.Loader特性:

(1).對于每個Activity或者Fragment都可用

(2).提供異步加載資料

(3).監視資料資源,當内容改變時重新更新

(4).當配置改變時,自動重新連接配接最新的cursor,故不需要重新查詢資料

2.Loader相關類接口

(1).LoaderManager

對于每個activity或者fragment隻存在一個與之相關的LoaderManager對象,該LoaderManager對象可以存在多個可供管理loader對象。

(2).LoaderManager.LoaderCallbacks

LoaderManager.LoaderCallbacks是個回掉接口,用于用戶端與LoaderManager的互動,loader對象就是在其接口的onCreateLoader()方法中得到,在使用時需要覆寫其方法。

(3).CursorLoader

CursorLoader是AsyncTaskLoader的子類,通過它可以查詢ContentResolver并傳回一個Cursor對象,并使用該cursor對象在背景線程執行查詢操作,以不至于會阻塞主線程,從一個内容提供者去異步加載資料是CursorLoader對象最大用處。

3.簡單使用Loaders

(1).得到LoaderManager對象

//得到LoaderManager對象
LoaderManager manager = content.getLoaderManager();
           

(2).初始化loader

在activity的onCreate()方法區或者在fragment的onActivityCreated()方法區中,需要初始化一個Loader對象(可能已經存在或者新建立),getLoaderManager().initLoader(0, null, this);調用initLoader()方法是確定loader對象已經初始化且可用,然而存在下面2種情況

1).ID存在

如果指定ID的loader已經存在,将重新使用最新的loader對象

2).ID不存在

如果指定的ID不存在,通過initLoader()方法,将會觸發LoaderManager.LoaderCallbacks的onCreateLoader()方法并傳回一個新的loader

雖然通過initLoader()可以得到loader對象,但是我們不需要捕獲該對象,但LoaderManager對象可以自動管理loader生命周期,是以不需要直接與loader對象直接互動

(3).實作LoaderCallbacks

以典型的CursorLoader為例,app允許資料在onStart() 和 onStop()函數中傳遞,一旦的當使用者重新進入app,不必等待資料重新加載,LoaderManager.LoaderCallbacks包含下面3個重要函數

1).onCreateLoader()

Instantiate and return a new Loader for the given ID.

當loadermanager調用initLoader()時, 首先檢查指定的id是否存在,如果不存在才會觸發該方法,通過該方法才能建立一個loader。傳回建立的CursorLoader對象,其中可以在建立對象時,指定查詢的條件,并攜帶一個Cursor對象。

CursorLoader接收 uri projection  selection  selectionArgs  sortOrder 等參數資訊

// 傳回一個new CursorLoader對象
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
	Uri uri = Uri.parse("content://com.baidu.provider/music");
	return new CursorLoader(MainActivity.this, uri, null, null, null,
			null);
}
           

2).onLoadFinished()

Called when a previously created loader has finished its load.

可以完成對Ui控件的更新,比如更新一個listView清單。一旦應用不在使用,将自動釋放loader的資料,不需要使用close();

// 完成對UI主界面的更新
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
	if(cursor == null){
		Toast.makeText(MainActivity.this, "失敗", 1).show();
		return;
	}
	//ui主界面更新相關操作
}
           

3).onLoaderReset()

Called when a previously created loader is being reset, thus making its data unavailable.

(4).重新開機loader

通過指定相同的loader ID,使用loadermanager的restartLoader()方法,消除就資料,加載新資料,達到動态更新的目的!可參考,ListView資料動态更新。
// 當檢測到資料已經放手改變時,重新開機指定ID的loader
if(u != null){
	MainActivity.this.getLoaderManager().restartLoader(0, null, myLoader);
	Toast.makeText(MainActivity.this, "插入成功", 1).show();
}else{
	Toast.makeText(MainActivity.this, "插入失敗", 1).show();
}
           

4.loader向下相容

(1)目前Activity繼承FragmentActivity

(2).得到Loadermanager對象

public void load(View view) {
	LoaderManager manager = this.getSupportLoaderManager();//注意,不同
	manager.initLoader(0, null, myLoader);
}
           
(3).其餘操作均不變,隻不過導包時需要導入android.support.v4下的包

 5.應用

(1).需求

一個listView和一個按鈕,點選按鈕後使用内容提供者,往資料庫中添加資料,同時達到listView動态更新的目的,但是listView回到第一個item,因為在cursor在restart的後,listview又重新設定了adapter,listview初始化後設定擴充卡可以避免該問題,可參考ListView資料動态更新一文。

(2).代碼實作

public class MainActivity extends Activity {
	private ListView listView;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		listView = (ListView) findViewById(R.id.list);
		
	//	1.得到LoaderManager對象
		LoaderManager manager = this.getLoaderManager();
		manager.initLoader(0, null, myLoader);
	}
	//	2.覆寫LoaderCallbacks相關方法
	private LoaderCallbacks<Cursor> myLoader = new LoaderCallbacks<Cursor>() {
		//	2.1建立一個新的CursorLoader對象,攜帶遊标
		public Loader<Cursor> onCreateLoader(int id, Bundle args) {
			Uri uri = Uri.parse("content://com.baidu.provider/music");		//内容提供者的uri資訊
			return new CursorLoader(MainActivity.this, uri, null, null, null,
					null);
		}
		//	2.2加載完成後,更新UI資訊
		public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
			if(cursor == null){
				Toast.makeText(MainActivity.this, "失敗", 1).show();
				return;
			}
			List<Map<String, String>> list = new ArrayList<Map<String, String>>();
			//	2.2.1往指定的集合中寫入讀取到的資料
			while (cursor.moveToNext()) {
				Map<String, String> map = new HashMap<String, String>();
				String id = cursor.getString(cursor.getColumnIndex("_id"));
				String name = cursor.getString(cursor.getColumnIndex("name"));
				String age = cursor.getString(cursor.getColumnIndex("age"));

				map.put("id", id);
				map.put("name", name);
				map.put("age", age);
				list.add(map);
			}
			//	2.2.2建立一個擴充卡對象
			MyAdapter adapter = new MyAdapter();
			adapter.setList(list);	//設定集合
			//	2.2.3為listView設定adapter,更新資料
			listView.setAdapter(adapter);
			//	2.2.4 設定擴充卡資料改變通知
			adapter.notifyDataSetChanged();
		}
		public void onLoaderReset(Loader<Cursor> arg0) {
		}
	};
	//	3.自定義擴充卡類
	class MyAdapter extends BaseAdapter {
		private List<Map<String, String>> list;		//集合,存儲資料
		public void setList(List<Map<String, String>> list) {
			this.list = list;
		}
		//	3.1得到清單數目,即為集合大小
		public int getCount() {
			return list.size();
		}
		public Object getItem(int arg0) {
			return list.get(arg0);
		}
		@Override
		public long getItemId(int arg0) {
			return 0;
		}

		//	3.2生成view
		public View getView(int position, View view, ViewGroup group) {
			View v = null;
			//	3.2.1得到或者加載布局對象
			if (view == null) {
				v = LayoutInflater.from(MainActivity.this).inflate(
						R.layout.item, null);
			} else {
				v = view;
			}
			//	3.2.2得到相關控件
			TextView t1 = (TextView) v.findViewById(R.id.t1);
			TextView t2 = (TextView) v.findViewById(R.id.t2);
			TextView t3 = (TextView) v.findViewById(R.id.t3);
			//	3.2.3設定課件資訊
			t1.setText(list.get(position).get("id"));
			t2.setText(list.get(position).get("name"));
			t3.setText(list.get(position).get("age"));
			return v;	//傳回該控件
		}

	}
	//	4.在使用者點選向資料庫寫入資料按鈕
	public void add(View view) {
		final View v = LayoutInflater.from(this).inflate(R.layout.info, null);
		//配置對話框資訊
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("添加資訊")
				.setView(v)
				.setPositiveButton("送出", new OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						//	包含使用者名 和 年齡
						EditText et_name = (EditText) v.findViewById(R.id.name);
						EditText et_age = (EditText) v.findViewById(R.id.age);
						String name = et_name.getText().toString();
						int age = Integer.parseInt(et_age.getText().toString());
						Uri uri = Uri.parse("content://com.baidu.provider/music");
						ContentValues values =new ContentValues();
						values.put("name", name);
						values.put("age", age);
						//	根據使用者填入的資訊,使用内容提供者,送出資料
						Uri u = getContentResolver().insert(uri, values);
						if(u != null){
							//	如果插入資料成功,則提醒loadermanager重新開始loader對象,根據指定的ID
							MainActivity.this.getLoaderManager().restartLoader(0, null, myLoader);
							Toast.makeText(MainActivity.this, "插入成功", 1).show();
						}else{
							Toast.makeText(MainActivity.this, "插入失敗", 1).show();
						}
					}
				})
				.setNegativeButton("取消", null)
				.create()
				.show();
	}
}