來源:
感謝作者
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