我理解的Android加載器


Android的加載器(loader)是從Android 3.0開始出來的東西。要理解這里需要先理解為什么會出現加載器(也有地方把它說成是裝載器)呢?

如果沒有加載器...

首先Activity是我們的前端頁面展現,數據庫是我們的數據持久化地址,那么正常的邏輯就是在展示頁面的渲染頁面的階段進行數據庫查詢。拿到數據以后才展示頁面。

但是這個邏輯有一些缺點:

 

首先是查詢數據的邏輯放在了UI生成的同個線程中,這個就意味着在查詢數據的時候,UI頁面生成的工作被阻塞住了。UI一旦被阻塞用戶就會被感知出來了,因此就會出現各種無相應頁面(Application Not Response),或者activity頁面延遲的現象,這對用戶體驗來說是不可接受的。

其次是在渲染頁面的時候需要固定需要進行一次數據查詢,但是這個是很不節省資源的。假如一個Activity從一個停止狀態回到前台,那么這個時候盡管數據並沒有變化,但是也需要進行一次query操作。在浪費資源的同時也再次增加了頁面渲染失敗的風險。

還有就是當數據變化的時候如何通知頁面進行修改呢?這個時候往往就又要創建一個monitor的角色,來當數據源變化的時候來讓頁面重新調用requery。

 

因此在Android的越來越提倡用戶體驗的今天,加載器和加載管理器(Loader,LoaderManager)就出現了。

Loader有什么作用?

簡單來說,Loader做了下面兩個事情:

1 在單獨的線程中讀取數據

2 監視數據的更新

 

而LoaderManager就是加載器的管理器,一個LoaderManager可以管理一個或多個Loader,一個Activity或者Fragment只能有一個LoadManager。LoaderManager管理Loader的初始化,重啟和銷毀操作。

從官網http://developer.android.com/reference/android/app/LoaderManager.html就可以看出它包含的方法有:

Image(1)

對應的就是這幾個操作。

 

initLoader是初始化一個加載器,它的第三個參數是一個LoaderCallbacks<D>接口,LoaderManager的initLoader是不做任何事情的,它只綁定了一個LoaderCallbacks<D>,具體的創建Loader的事情是由這個callback來做的。

LoaderCallbacks<D>接口需要實現的三個方法:

Image(2)

在loader創建loader的時候會調用onCreateLoader,然后當load數據結束的時候(第一次讀取數據或者數據有改變的時候load數據)會調用onLoadFinished,而onLoaderReset只有在destory一個loader的時候才有可能調用。

 

所以一般創建數據Cursor(CursorLoader)的工作是在onCreateLoader中做,將CursorLoader返回,這樣就創建了對這個數據源的監控,當數據源有數據變化的時候,就會自動調用了onLoadFinished函數了。

比如下面一個例子:

public class ToDoListActivity extends Activity
implements NewItemFragment.OnNewItemAddedListener, 
LoaderManager.LoaderCallbacks<Cursor>{
//獲得對UI小組件的引用
    private ArrayList<ToDoItem> todoItems;
    private ToDoItemAdapter aa;
    @Override
    // onCreate是創建這個activity的時候會調用的
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        // 獲取該Fragment的引用
        FragmentManager fm = getFragmentManager();
        ToDoListFragment todoListFragment = (ToDoListFragment)fm.findFragmentById(R.id.TodoListFragment);
        
        todoItems = new ArrayList<ToDoItem>();
        
        // 這里需要將數據庫中存儲的東西都讀取出來
        int resID = R.layout.todolist_item;
        
        aa = new ToDoItemAdapter(this, resID, todoItems);
        
        todoListFragment.setListAdapter(aa);
        getLoaderManager().initLoader(0, null, this);
        getLoaderManager().enableDebugLogging(true);
    }

    @Override
    // onResume是暫停以后重新啟動這個Activity時候調用
    protected void onResume() {
      super.onResume();
      getLoaderManager().restartLoader(0, null, this);
    }
    
    @Override
public void onNewItemAdded(String newItem) {
    ContentResolver cr = getContentResolver();
    
    ContentValues values = new ContentValues();
    values.put(ToDoContentProvider.KEY_TASK, newItem);
   
    cr.insert(ToDoContentProvider.CONTENT_URI, values);
    getLoaderManager().restartLoader(0, null, this);
}
    
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader loader = new CursorLoader(this, ToDoContentProvider.CONTENT_URI,
null, null, null, null);
return loader;
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
// 當loader查詢完成的時候,Cursor會返回到onLoadFinished處理程序。
int keyTaskIndex = cursor.getColumnIndexOrThrow(ToDoContentProvider.KEY_TASK);
todoItems.clear();
while (cursor.moveToNext()) {
ToDoItem newItem = new ToDoItem(cursor.getString(keyTaskIndex));
todoItems.add(newItem);
}
aa.notifyDataSetChanged();
}

@Override
public void onLoaderReset(Loader<Cursor> arg0) {
// TODO Auto-generated method stub
}

}

在這個例子中,在創建activity的時候(onCreate)調用了

getLoaderManager().initLoader(0,null,this);

這里的第一個參數0是指loader的id,我們並不關注它,所以設置了一個0。第二個參數是給Loader初始化的時候傳遞的參數(也就是onCreateLoader中的第二個參數)。

這里的第三個參數LoaderCallbacks<D>使用的直接是Activity類,所以這個類需要實現LoaderCallbacks<D>的三個方法:

onCreateLoader

onLoadFinished

onLoaderReset

 

在onCreateLoader中創建CursorLoader

在onLoadFinished中重新渲染ViewList。

總結:

在3.0之后Android的官方文檔強烈推薦使用Loader來做數據的加載。因此在能使用這個的情況下就盡量使用Loader吧。

使用需要先確定一個類來實現LoaderCallbacks<D>接口,然后實現接口的三個方法。

之后使用getLoaderManager來獲取LoadManager,再調用initLoader來創建loader,把實際的修改頁面的邏輯放在onLoadFinished中。

當然Loader並不只有CursorLoader,你也可以自己定義loader。

參考文章

http://www.kaixinwenda.com/article-wre_most2-8781946.html

http://www.androiddesignpatterns.com/2012/07/loaders-and-loadermanager-background.html

http://www.androiddesignpatterns.com/2012/07/understanding-loadermanager.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM