2014-10-27 69 views
10

我已經瀏覽了很多在Android中使用SQLite的示例/教程。假設您的應用使用SQLite,ContentProvider,CursorLoader,自定義CursorAdapter。 現在我所發現的所有主要示例都依賴於CursorLoader將數據提取到CursorAdapter,而CursorLoader的性質以異步UI線程安全的方式發生。但是,這些相同的示例都通過主線程上的ContentResolver(例如,從onClick,onResume,,)來插入/刪除/更新呼叫。 (Example)他們不會將這些呼叫包裝在AsyncTask中,也不會啓動單獨的線程或使用AsyncQueryHandler。 爲什麼這麼多,寫得好的博客/例子怎麼會出現如此明顯的錯誤?還是簡單的單行插入/刪除/更新調用如此之快,以至於它們足夠安全以便從Main/UI線程啓動?做這些快速通話的正確方法是什麼?Android - SQLite ContentResolver在UI線程上插入/刪除/更新?

+1

您最後一句可能是對的:查詢操作肯定比單個插入/更新/刪除複雜得多 – pskink 2014-10-27 09:38:35

回答

4

我也對主線程調用樣本感到困惑。我猜這些示例只是簡化了示例,避免了額外的線程和回調,因爲單個插入/更新/刪除調用可能會很快返回。

除了用於查詢的Loader模式外,android還提供了輔助類AsyncQueryHandler,因爲API級別1支持支持完整CRUD回調的異步CRUD操作。 AsyncQueryHandler與HandlerThread一起工作以進行異步操作,並將結果傳遞迴主線程。

所以我相信ContentProvider查詢應該在UI以外的工作線程中運行,並且這些示例可能不是根據官方設計的最佳實踐。

===編輯

實測值從官方框架文檔的註釋,見thisthis,行255:

In practice, this should be done in an asynchronous thread instead of 
on the main thread. For more discussion, see Loaders. If you are not 
just reading data but modifying it, see {@link android.content.AsyncQueryHandler}. 

===編輯2 Link包含實際Android開發指南以上報價

+0

對,我在我的問題中提到了AsyncQueryHandler ...它仍然不是很有說服力,所有的教程和例子,我來了不要這樣做,只是因爲它更簡單,甚至沒有提到,這不是你應該怎麼做的。爲了得到正確的答案,我希望來自谷歌(團隊成員,文檔,教程)的官員或其他人(可能是鏈接到一個可敬的GitHub項目,以這種或那種方式做這樣或那樣的事情)主線程或使用類似AsyncQueryHandler ... – 2015-04-07 20:40:50

+0

否則其他一切只是我們對此的看法... :) – 2015-04-07 20:41:35

+0

@LeoK得到了一個官方文檔提到這一點。請參閱我的編輯。 – 2015-04-09 03:15:46

2

這個問題很久以來一直在我的腦海裏。我想,這取決於我們試圖插入,更新或刪除的文件的複雜性。如果我們的應用程序要插入或更新大型文件,那麼它將是非常正確的,如果這些文件不會那麼大,那麼可以在UI線程上運行它。

但是,始終建議在單獨的線程上繼續數據庫操作。

+0

感謝您的回覆。這並不能完全解釋爲什麼解釋最佳實踐和其他方面的教程在插入/刪除/更新的情況下正確/安全地執行任何操作都不會受到單獨線程的困擾。很明顯,我沒有閱讀所有優秀的教程,所以我們歡迎一些好的反例。 (特別是來自Google或其他信譽良好的源代碼) – 2014-10-27 09:53:41

0

我想你已經回答了你自己的問題。我確實相信CursorLoader擴展了AsyncTaskLoader。來自UI線程的調用僅處理對CusorLoader(使用AsyncTask)的調用。UI線程上不會發生正在調用的內容。調用一個方法/函數,然後在單獨的線程上運行的東西仍然在遠離UI線程工作。

你認爲UI線程上發生了什麼工作?

如果可能,請顯示調試日誌,或者您認爲在UI上完成工作的示例。 它不應該。

沒有試圖爭辯只是想知道你是如何得出UI工作的結論?

+0

關於遊標加載器是異步的,你是對的。這是我在這個問題上寫下的。但是,插入/刪除/更新調用是通過ContentReslover而不是CursorLoader進行的。如果對UI線程的調用是在UI線程上完成的,則通過ContentReslover執行的所有操作都將在UI線程上完成。只需將Thread.sleep(5000)添加到ContentProvider的插入覆蓋開頭即可輕鬆進行驗證。如果你這樣做,你會看到你的用戶界面凍結5秒... – 2014-11-21 11:56:22