LoaderManager使用詳解(一)---沒有Loader之前的世界


來源:
感謝作者 Alex Lockwood的努力,讓我們看到如此精彩的文章。

第一部分 沒有Loader之前的世界

 
這一部分將對Loaders和LoaderManager做一個簡短的介紹。第一節將在Android3.0之前如何載入數據,指出其缺陷。第二節講述每個類的目的,以及它們異步載入數據的能力。
這篇文章是有關Loaders和LoaderManager一系列文章的開篇,該系列如下:
 
一:Loaders之前世界
三: 實現Loaders
 
如果你對Loaders和LoaderManager完全不了解,在繼續閱讀之前,強烈建議你讀一下 Loaders向導
 

以前情況

在Android3.0之前,很多應用程序響應性能方面有缺陷。UI切換之間的小故障、activity切換延遲、ANR問題。響應性能方面的故障大多數來源於此事實----大多數開發者在UI線程中執行了查詢操作---用這種方式載入數據是最差的選擇。
 
這篇文章強調及時反饋的同時,Android3.0之前的APIs似乎並沒有支持該特性。在Loaders之前,cursors主要通過兩個Activity方法(現在已經過時deprecated)來進行管理和查詢:
 
public void startManagingCursor(Cursor)
告訴activity根據自己的生命周期來管理cursor的生命周期。cursor會被自動deactivate()當活動stopped時。會自動close()當活動摧毀的時候。當活動stopped之后重新restarted,cursor會re-queried(requery())重新查詢最新的數據。
 
public Cursor managedQuery(Uri, String, String, String, String)
該函數是對ContentResolver的query()方法的包裝。除了執行query之外,在它返回之前還會將調用startManagingCursor(cursor)。也就是說將這個query的cursor放入了activity生命周期管理了。
 
用起來很方便的同時,上面的方法在UI線程中執行查詢操作時,會導致嚴重的延遲問題。而且該“managed cursors”方式在activity配置變化(configuration changed,橫豎屏切換、鍵盤彈出等)時,並不會保持數據。在這些情況下會重新requry()數據,但是實際上是沒有必要、低效,而且會導致方向切換呆滯和卡頓。
 

Managed Cursors的問題

讓我們在一個簡單的代碼里面模擬managed cursors的問題。下面提供的代碼是在一個ListActivity里面載入數據使用的是Android3.0之前的APIs。該活動從ContentProvider里面查詢數據,並且管理返回的cursor。查詢結果用SimpleCursorAdapter包裝,並且顯示在listview中。代碼精煉如下:
public class SampleListActivity extends ListActivity {

  private static final String[] PROJECTION = new String[] {"_id", "text_column"};

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Performs a "managed query" to the ContentProvider. The Activity 
    // will handle closing and requerying the cursor.
    //
    // WARNING!! This query (and any subsequent re-queries) will be
    // performed on the UI Thread!!
    Cursor cursor = managedQuery(
        CONTENT_URI,  // The Uri constant in your ContentProvider class
        PROJECTION,   // The columns to return for each data row
        null,         // No where clause
        null,         // No where clause
        null);        // No sort order

    String[] dataColumns = { "text_column" };
    int[] viewIDs = { R.id.text_view };
 
    // Create the backing adapter for the ListView.
    //
    // WARNING!! While not readily obvious, using this constructor will 
    // tell the CursorAdapter to register a ContentObserver that will
    // monitor the underlying data source. As part of the monitoring
    // process, the ContentObserver will call requery() on the cursor 
    // each time the data is updated. Since Cursor#requery() is performed 
    // on the UI thread, this constructor should be avoided at all costs!
    SimpleCursorAdapter adapter = new SimpleCursorAdapter(
        this,                // The Activity context
        R.layout.list_item,  // Points to the XML for a list item
        cursor,              // Cursor that contains the data to display
        dataColumns,         // Bind the data in column "text_column"...
        viewIDs);            // ...to the TextView with id "R.id.text_view"

    // Sets the ListView's adapter to be the cursor adapter that was 
    // just created.
    setListAdapter(adapter);
  }
}
上面的代碼有3個問題。如果你讀懂了上面講的內容,那么開始兩個問題不難讀懂。
 
1. managedQuery在Ui線程中執行了一個查詢操作,這將導致應用無響應,這種方法不應該再使用。
2. 通過查看Activity.java源碼,可以知道managedQuery也順便調用了startManagingCursor來管理查詢到的數據。看起來很簡便,因為我們不用考慮cursor后續的關閉、requery等。但是使用這種方式導致每次activity的狀態從stopped返回時都需要重新查詢數據,這通常會導致UI線程卡頓。讓activity替我們管理cursor所冒的風險大於便捷性。
3. 32行的SimpleCursorAdapter構造方法過時了,不應該再使用。該構造方法問題是,當有改變時,將導致SimpleCursorAdapter自動查詢。更具體來說,CursorAdapter會在數據上注冊一個ContentObserver監聽器,當監聽的數據變化時會requery數據。我們應該使用標准的構造函數(如果你嘗試使用CursorLoader來載入適配器數據,確保最后一個參數傳入值為0)。如果你不能理解第三條,沒有關系,這僅僅只是個小錯誤。
 
Android平板設備的發布,應該加強UI友好性(反應更快)。更大的設備,7~10寸的平板的應用更復雜、交互更多、有更多的界面布局。后續將介紹Fragment,fragment使應用更動態化,更多的事件驅動。一個簡單的,單線程的方法來載入數據顯然已經不再合適。所以這就是Loader和LoaderManager在Android3.0誕生的背景。
 

Android3.0,Loaders, LoaderManager

在Honeycomb之前,很難管理cursors的操作,比如,在UI線程中正常同步,確保所有查詢適時在后台線程中執行。Android3.0引入了Loader和LoaderManager類來簡化該過程。可以通過使用ASL(Android Support Library),在Android1.6以上的系統實現這兩個類。
新的Loader API是一個巨大的進步,是用戶體驗的巨大進步。Loaders確保所有的cursor操作是異步的,從而排除了UI線程中堵塞的可能性。而且,當通過LoaderManager來管理,Loaders還可以在activity實例中保持當前的cursor數據,也就是不需要重新查詢(比如,當因為橫豎屏切換需要重新啟動activity時)。還有額外的好處,當數據改變時,Loaders可以很聰明的自動檢測底層數據的更新和重新檢索。
 

總結

自從有了Honeycomb的Loaders以及其實現庫,Android應用變得更好了。現在還使用startManagingCursor和managedQuery是非常不合適的,不僅僅將你的程序變慢,而且存在程序卡死的潛在地可能性。另一方面,Loaders可以通過將數據載入工作交給單獨的后台進程,將明顯的提高用戶體驗。
 
轉載:http://blog.csdn.net/murphykwu/article/details/35287303


免責聲明!

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



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