在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如何从数据库中加载海量数据相关推荐

  1. Databricks 加载MySQL数据

    databricks加载MySQL数据,需要先安装MySQL的驱动包.可以从集群的Libraries安装.上传jar包即可. 查询如下 driver = "com.mysql.jdbc.Dr ...

  2. Mybatis拦截器安全加解密MySQL数据实战

    需求背景 公司为了通过一些金融安全指标(政策问题)和防止数据泄漏,需要对用户敏感数据进行加密,所以在公司项目中所有存储了用户信息的数据库都需要进行数据加密改造.包括Mysql.redis.mongod ...

  3. sql compact 转mysql_如何将数据导入到 SQL Server Compact Edition 数据库中(五)

    系列文章导航: 如何将数据导入到 SQL Server Compact Edition 数据库中(一) 如何将数据导入到 SQL Server Compact Edition 数据库中(二) 如何将数 ...

  4. 如何将数据导入到 SQL Server Compact Edition 数据库中(四)

    系列文章导航: 如何将数据导入到 SQL Server Compact Edition 数据库中(一) 如何将数据导入到 SQL Server Compact Edition 数据库中(二) 如何将数 ...

  5. sql compact 转mysql_如何将数据导入到 SQL Server Compact Edition 数据库中(三)

    系列文章导航: 如何将数据导入到 SQL Server Compact Edition 数据库中(一) 如何将数据导入到 SQL Server Compact Edition 数据库中(二) 摘要:时 ...

  6. sql compact 转mysql_如何将数据导入到 SQL Server Compact Edition 数据库中(四)

    系列文章导航: 如何将数据导入到 SQL Server Compact Edition 数据库中(一) 如何将数据导入到 SQL Server Compact Edition 数据库中(二) 如何将数 ...

  7. 加载mySQL数据到内存_【测试验证】数据库加载到内存占用大小

    介绍 数据库大小加载到内存占用是不是数据库的本身大小哪?今天忽然突发奇想于是就测试一下.首先我要说明的是我是在EF框架下进行测试的,不知道会不会与ado.net连接方式差生不同的结果,我仅仅是做记录, ...

  8. mysql 查询表 第一列报错_MySQL----DQL(查询数据库表中数据)

    ##DQL:查询表中的记录 1.语法: select 字段列名 from 表名列表 where 条件列表 group  by 分组字段 having  分组之后的条件 order  by 排序 lim ...

  9. 在mysql中能够删除一列的是什么_mysql数据库中命令行下常用命令的操作(增、删、改、查)和数据类型...

    连接命令:mysql -h[主机地址] -u[用户名] -p[用户密码] 创建数据库:create database [库名] 显示所有数据库: show databases; 打开数据库:use [ ...

最新文章

  1. char* 长度_leetcode之最后一个单词的长度
  2. Listview点击事件
  3. 用VS向SharePoint中部署添加List 并指定应用的Content Type
  4. 启动器中图标的默认路径
  5. Java 网络编程1
  6. 查看 rabbitmq 启动websocket 提示404_RabbitMQ在windows下安装(笔记)
  7. 初识c语言教程,第1课C语言教程一: 初识C程序.doc
  8. 魅族16s Pro邀请函发布:对称式全面屏+骁龙855Plus
  9. hibernate自动建表到数据库及spring下自动建表到数据库
  10. pythoninit_Python __init__.py文件的作用
  11. 听音乐学英语之- I Need to Wake Up 奥斯卡获奖单曲:关注全球变暖
  12. MQ发送的消息都到了死信队列中了
  13. svn和git的区别
  14. 贴心的特效制作软件,抖音特效开放平台就能找到
  15. python3.8安装robotfrmework-ride安装及报错完美解决方法
  16. 量化进阶——如何突破期货交易难点
  17. 谷歌地图地理翻遍码,谷歌地图地点搜索
  18. 新浪微博传播途径研究
  19. DELL电脑开机自检提示please run setup program
  20. 概率质量函数(Probability mass function)

热门文章

  1. 十四、去年写的Numpy使用方法梳理,2020年5月13日整理
  2. Huggingface BERT源码详解:应用模型与训练优化
  3. 直播 | 北京邮电大学助理教授王啸:网络嵌入的最新进展
  4. 深度学习预训练模型可解释性概览
  5. 实录分享 | 计算未来轻沙龙:深度学习工具专场(PPT下载)
  6. 实录分享 | 计算未来轻沙龙:大规模数据存储与挖掘(PPT下载)
  7. AIProCon在线大会笔记之Google李双峰:TensorFlow的最新进展
  8. Spring注释详解
  9. Spring Security——根据请求Header[Accept]不同返回不同类型资源解决方案
  10. 网页设计/移动开发学习资源推荐