本博文為子墨原創,轉載請注明出處! 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對象
(3).其餘操作均不變,隻不過導包時需要導入android.support.v4下的包public void load(View view) { LoaderManager manager = this.getSupportLoaderManager();//注意,不同 manager.initLoader(0, null, myLoader); }
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(); } }