安卓加载mysql数据到列表里_Android如何从数据库中加载海量数据
在Android3.0之前,很多應用程序響應性能方面有缺陷,其中比較典型的錯誤行為是在UI線程中執行了查詢數據操作,尤其是一次性從database查出大量數據并加載到ListView里,用這種方式載入數據是最差的選擇,硬件偏弱的手機會假死會兒。 其實體驗最好的還屬手機自帶通訊錄App這類應用,滑動絲般順滑。
在Android 3.0版本之前一般的做法是用Activity提供的startManagingCursor()和stopManagingCursor(), ?已經deprecated的API我們就不談了,3.0之后取而代之的是Loader,想必Loader的使用大家都有所知道:public?class?CursorLoaderListFragment?extends?ListFragment?{
SimpleCursorAdapter?mAdapter;
SearchView?mSearchView;
String?mCurFilter;????static?final?String[]?CONTACTS_SUMMARY_PROJECTION?=?new?String[]?{
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.CONTACT_STATUS,
};????private?LoaderManager.LoaderCallbacks?mLoaderCallback?=?new?LoaderManager.LoaderCallbacks()?{????????@Override
public?Loader?onCreateLoader(int?id,?Bundle?args)?{????????????//?This?is?called?when?a?new?Loader?needs?to?be?created.
String?select?=?"(("?+?ContactsContract.Contacts.DISPLAY_NAME?+?"?NOTNULL)?AND?("
+?ContactsContract.Contacts.HAS_PHONE_NUMBER?+?"=1)?AND?("
+?ContactsContract.Contacts.DISPLAY_NAME?+?"?!=?''?))";????????????return?new?CursorLoader(getActivity(),
ContactsContract.Contacts.CONTENT_URI,
CONTACTS_SUMMARY_PROJECTION,?select,?null,
ContactsContract.Contacts.DISPLAY_NAME?+?"?COLLATE?LOCALIZED?ASC");
}????????@Override
public?void?onLoadFinished(@NonNull?Loader?loader,?Cursor?data)?{????????????//?Swap?the?new?cursor?in.??(The?framework?will?take?care?of?closing?the
//?old?cursor?once?we?return.)
mAdapter.swapCursor(data);????????????//?The?list?should?now?be?shown.
if?(isResumed())?{
setListShown(true);
}?else?{
setListShownNoAnimation(true);
}
}????????@Override
public?void?onLoaderReset(@NonNull?Loader?loader)?{????????????//?This?is?called?when?the?last?Cursor?provided?to?onLoadFinished()
//?above?is?about?to?be?closed.??We?need?to?make?sure?we?are?no
//?longer?using?it.
mAdapter.swapCursor(null);
}
};????@Override
public?void?onActivityCreated(Bundle?savedInstanceState)?{????????super.onActivityCreated(savedInstanceState);
setEmptyText("No?phone?numbers");
setHasOptionsMenu(true);
mAdapter?=?new?SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_2,?null,????????????????new?String[]?{?ContactsContract.Contacts.DISPLAY_NAME,?ContactsContract.Contacts.CONTACT_STATUS?},????????????????new?int[]?{?android.R.id.text1,?android.R.id.text2?},?0);
setListAdapter(mAdapter);
LoaderManager.getInstance(this).initLoader(0,?null,?mLoaderCallback);
}????public?boolean?onQueryTextChange(String?newText)?{
String?newFilter?=?!TextUtils.isEmpty(newText)???newText?:?null;????????if?(mCurFilter?==?null?&&?newFilter?==?null)?{????????????return?true;
}????????if?(mCurFilter?!=?null?&&?mCurFilter.equals(newFilter))?{????????????return?true;
}
mCurFilter?=?newFilter;
LoaderManager.getInstance(this).restartLoader(0,?null,?mLoaderCallback);????????return?true;
}
}不難看出只要實現三個回調函數就能創建出一個LoaderCallbacks,并將此丟給LoaderManager去initLoader或者restartLoader,initLoader是第一次查詢使用的,restartLoader是二次查詢使用的。簡單是簡單不過有個東西不知有沒有發現:在此demo 中onCreateLoader()方法返回值是CursorLoader對象,它的構造函數必須是Uri,意味著必須是基于Content Provider實現的數據庫才可以使用,可是現實項目需要ContentProvider的不多吧,很多是純sqlite的,為了此場景硬生生將sqlite的實現改成ContentProvider得不償失。
當翻看onCreateLoader()方法定義時候,發現返回值不是CursorLoader而是Loader,CursorLoader只是Loader的一個子類而已,因此轉機來了:定義一個類繼承Loader并內部用Cursor實現,最終返回自定義類的對象給onCreateLoader():public?abstract?class?SQLiteCursorLoader?extends?AsyncTaskLoader?{????private?Cursor?lastCursor;????private?Cursor?queryCursor;????public?SQLiteCursorLoader(Context?context,?Cursor?cursor)?{????????super(context);
queryCursor?=?cursor;
}????/**
*?Runs?on?a?worker?thread,?loading?in?our?data.?Delegates?the?real?work?to?concrete?subclass'
*?buildCursor()?method.
*/
@Override
public?Cursor?loadInBackground()?{????????final?Cursor?cursor?=?queryCursor;????????if?(cursor?!=?null)?{????????????//?Ensure?the?cursor?window?is?filled
cursor.getCount();
}????????return?cursor;
}????/**
*?Runs?on?the?UI?thread,?routing?the?results?from?the?background?thread?to?whatever?is?using
*?the?Cursor?(e.g.,?a?CursorAdapter).
*/
@Override
public?void?deliverResult(final?Cursor?cursor)?{????????if?(isReset())?{????????????//?An?async?query?came?in?while?the?loader?is?stopped
if?(cursor?!=?null)?{
cursor.close();
}????????????return;
}????????final?Cursor?oldCursor?=?lastCursor;
lastCursor?=?cursor;????????if?(isStarted())?{????????????super.deliverResult(cursor);
}????????if?(oldCursor?!=?null?&&?oldCursor?!=?cursor?&&?!oldCursor.isClosed())?{
oldCursor.close();
}
}????/**
*?Starts?an?asynchronous?load?of?the?list?data.?When?the?result?is?ready?the?callbacks?will?be
*?called?on?the?UI?thread.?If?a?previous?load?has?been?completed?and?is?still?valid?the?result
*?may?be?passed?to?the?callbacks?immediately.?Must?be?called?from?the?UI?thread.
*/
@Override
protected?void?onStartLoading()?{????????if?(lastCursor?!=?null)?{
deliverResult(lastCursor);
}????????if?(takeContentChanged()?||?lastCursor?==?null)?{
forceLoad();
}
}????/**
*?Must?be?called?from?the?UI?thread,?triggered?by?a?call?to?stopLoading().
*/
@Override
protected?void?onStopLoading()?{????????//?Attempt?to?cancel?the?current?load?task?if?possible.
cancelLoad();
}????/**
*?Must?be?called?from?the?UI?thread,?triggered?by?a?call?to?cancel().?Here,?we?make?sure?our
*?Cursor?is?closed,?if?it?still?exists?and?is?not?already?closed.
*/
@Override
public?void?onCanceled(final?Cursor?cursor)?{????????if?(cursor?!=?null?&&?!cursor.isClosed())?{
cursor.close();
}
}????/**
*?Must?be?called?from?the?UI?thread,?triggered?by?a?call?to?reset().?Here,?we?make?sure?our
*?Cursor?is?closed,?if?it?still?exists?and?is?not?already?closed.
*/
@Override
protected?void?onReset()?{????????super.onReset();????????//?Ensure?the?loader?is?stopped
onStopLoading();????????if?(lastCursor?!=?null?&&?!lastCursor.isClosed())?{
lastCursor.close();
}
lastCursor?=?null;
}
}事實上并沒有直接繼承Loader, 而是繼承的AsyncTaskLoader,從名字看就知道它是類似AsyncTask的原理實現的,SDK的CursorLoader也是基于AsyncTaskLoader實現的,當有了SQLiteCursorLoader我們就可以用SQL創建LoaderManager.LoaderCallbacks了:private?LoaderManager.LoaderCallbacks?mLoaderCallback?=?new?LoaderManager.LoaderCallbacks()?{????????@Override
public?Loader?onCreateLoader(int?id,?Bundle?args)?{????????????//?This?is?called?when?a?new?Loader?needs?to?be?created.
String?sql?=?"SELECT?*?FROM?TABLE_XX";????????????return?new?SQLiteCursorLoader(getActivity(),?sql);
}????????@Override
public?void?onLoadFinished(@NonNull?Loader?loader,?Cursor?data)?{????????????//?...
}????????@Override
public?void?onLoaderReset(@NonNull?Loader?loader)?{????????????//?...
}
};關于Android數據庫方面的開發用純SQL的確有點累,可以考慮ORM的思路,以前我也寫了一個輕量級的,也一直使用中,SQLiteCursorLoader其實我提供了2個構造方法,一個如上傳Cursor,另外一個是傳BuilderSupport, 它有2個實現,分別為ConditionBuilder和MultiTableConditionBuilder, 通過他們可以以面向對象方式來查詢數據庫,一個是用于單表查詢,一個用于多表查詢,具體可以參考下:
作者:生活簡單些
鏈接:https://www.jianshu.com/p/4a6bb4cde477
總結
以上是生活随笔為你收集整理的安卓加载mysql数据到列表里_Android如何从数据库中加载海量数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是mysql的游标_数据库中的游标到
- 下一篇: mysql insert 几分钟_我们可