LoaderManager异步加载数据库数据,是在(Activity/fragment/其他UI等) 加载大量的本地Database库表数据,由于数据大在加载过程中会导致UI线程阻塞,导致用户体验不好,Android为来解决这个问题,就设计了LoaderManager异步加载数据库数据

以前我在深圳做项目的时候,公司研发的APP是给中国联通人员在山上工作办事的,对这款APP要求离线数据,大量的离线数据(成百上千条)都是存储在本地Database表里面的,常常在查询本地Database数据的时候,导致UI线程阻塞,体验不好,哪个时候还不知道有LoaderManager异步加载数据库数据,如果早点知道就可以解决这个问题;


MySQLiteOpenHelper3 数据库帮助类 创建类表

package liudeli.datastorage.db;

import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; public class MySQLiteOpenHelper3 extends SQLiteOpenHelper { public static MySQLiteOpenHelper3 mySQLiteOpenHelper; /**
* 由于表名每次使用很频繁,所有定义成常量
*/
public static final String TABLE_NAME = "_student_table"; private static final String DB_NAME = "student.db";
private static final int VERSION = 1; public synchronized static MySQLiteOpenHelper3 getInstance(Context context) {
if (null == mySQLiteOpenHelper) {
mySQLiteOpenHelper = new MySQLiteOpenHelper3(context, DB_NAME, null, VERSION);
}
return mySQLiteOpenHelper;
} /**
* 当开发者调用 getReadableDatabase(); 或者 getWritableDatabase();
* 就会通过此构造方法配置的信息 来创建 person_info.db 数据库
* 此方法的另外作用是,如果存着数据库就打开数据库,不存着数据库就创建数据库
* @param context 上下文
* @param name 数据库名
* @param factory 游标工厂
* @param version 版本,最低为1
*/
private MySQLiteOpenHelper3(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
} /**
* 此方法是何时调用? ,是需要开发者调用 getReadableDatabase(); 或者 getWritableDatabase();
* 此方法的作用是,如果没有表就创建打开,如果有表就打开
* @param db 可执行SQL语句
*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table "+TABLE_NAME+"(_id integer primary key autoincrement, name text, age integer, my_assets text);"); ContentValues values = new ContentValues(); for (int i = 0; i < 6; i++) {
values.clear();
values.put("name", "张三" + i);
values.put("age", 62 + i);
values.put("my_assets", "1000000" + i);
db.insert(TABLE_NAME, null, values);
}
} /**
* 此方法用于数据库升级
* @param db 可执行SQL语句
* @param oldVersion 以前旧版本的版本号
* @param newVersion 现在目前最新的版本号
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}

ConnectMySQLiteOpenHelper3ContentProvider 内容提供者 暴露数据库里面的数据 进行查询 增加

package liudeli.datastorage;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log; import liudeli.datastorage.db.MySQLiteOpenHelper3; public class ConnectMySQLiteOpenHelper3ContentProvider extends ContentProvider { private MySQLiteOpenHelper3 dbHelper; @Override
public boolean onCreate() {
Log.d("Provider", "ConnectMySQLiteOpenHelper3ContentProvider");
dbHelper = MySQLiteOpenHelper3.getInstance(getContext()); // 必须这在里面,要是写在外面是无法获取上下文的
return false;
} @Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteDatabase database = dbHelper.getReadableDatabase();
Cursor cursor = database.query(MySQLiteOpenHelper3.TABLE_NAME, projection, selection, selectionArgs, sortOrder, null, "_id desc");
return cursor; // 内容提供者里面的 cursor / database 不能关闭
} @Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase database = dbHelper.getWritableDatabase();
long insertThisID = database.insert(MySQLiteOpenHelper3.TABLE_NAME, null, values); // insertThisID是 插入成功后,插入的这条数据ID
Uri uriResult = ContentUris.withAppendedId(uri, insertThisID); // 内容提供者里面的 cursor / database 不能关闭
return uriResult;
} @Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
} @Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
} @Override
public String getType(Uri uri) {
return null;
}
}

在AndroidManifest.xml provider 对外提供可以访问的 Uir

      <!--  定义provider 内容提供者
provider对外暴露
-->
<provider
android:authorities="db.ConnectMySQLiteOpenHelper3ContentProvider"
android:name=".ConnectMySQLiteOpenHelper3ContentProvider"
android:exported="true"
android:enabled="true" />

在LoaderActivity使用LoaderManager异步加载数据库数据

package liudeli.datastorage;

import android.app.Activity;
import android.app.LoaderManager;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; public class LoaderActivity extends Activity { private LoaderManager loaderManager;
private ListView listView; // 访问内容提供者的Uir地址
private Uri uri = Uri.parse("content://db.ConnectMySQLiteOpenHelper3ContentProvider"); @Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.activity_loader); loaderManager = getLoaderManager(); /**
* 参数一:ID
* 参数二:参数
* 参数三:LoaderCallbacks回调
*/
loaderManager.initLoader(1, null, callbacks); listView = findViewById(R.id.list_view);
} /**
* 定义LoaderCallbacks回调
*/
private LoaderManager.LoaderCallbacks<Cursor> callbacks = new LoaderManager.LoaderCallbacks<Cursor>() {
/**
* 此方法是 加载读取大量数据 异步执行
* @param id
* @param args
* @return
*/
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader cursorLoader = new CursorLoader(LoaderActivity.this);
cursorLoader.setUri(uri);
cursorLoader.setSortOrder(null);
cursorLoader.setSelectionArgs(null);
cursorLoader.setSelection(null);
cursorLoader.setProjection(new String[]{"name", "age"});
// .... /*
第二种方式,都是可以的
new CursorLoader(Context context, Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder);*/ return cursorLoader;
} /**
* 此方法是 已经读取数据库数据完成✅了 更新UI操作
* @param loader
* @param cursor
*/
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
List<Map<String, Object>> list = new ArrayList<>(); while (cursor.moveToNext()) {
Map<String, Object> mMap = new HashMap<>();
mMap.put("name", cursor.getString(cursor.getColumnIndex("name")));
mMap.put("age", cursor.getInt(cursor.getColumnIndex("age")));
list.add(mMap);
} ListAdapter listAdapter =
new SimpleAdapter(LoaderActivity.this,
list,
android.R.layout.simple_list_item_2,
new String[]{"name","age"}, // 从哪里来
new int[]{android.R.id.text1, android.R.id.text2}); // 到哪里去
listView.setAdapter(listAdapter);
} /**
* Called when a previously created loader is being reset, and thus
* making its data unavailable. The application should at this point
* remove any references it has to the Loader's data.
*
* @param loader The Loader that is being reset.
*/
@Override
public void onLoaderReset(Loader<Cursor> loader) { }
}; /**
* 增加数据
* @param view
*/
public void insert(View view) {
ContentResolver contentResolver = getContentResolver();
ContentValues values = new ContentValues();
values.clear();
values.put("name", "大民");
values.put("age", 99);
values.put("my_assets", "9000000");
contentResolver.insert(uri, values); /**
* Loader restartLoader 会自动去读内容提供者里面的数据
* 参数一:ID
* 参数二:参数
* 参数三:LoaderCallbacks回调
*/
loaderManager.restartLoader(3333, null, callbacks);
}
}

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"> <ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" /> <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="insert"
android:text="增加"
android:layout_centerInParent="true"
/> </RelativeLayout>

效果:

Android-LoaderManager异步加载数据库数据的更多相关文章

  1. Android之数据存储----使用LoaderManager异步加载数据库

    一.各种概念: 1.Loaders: 适用于Android3.0以及更高的版本,它提供了一套在UI的主线程中异步加载数据的框架.使用Loaders可以非常简单的在Activity或者Fragment中 ...

  2. Android 之异步加载LoaderManager

    LoaderManager: Loader出现的背景: Activity是我们的前端页面展现,数据库是我们的数据持久化地址,那么正常的逻辑就是在展示页面的渲染页面的阶段进行数据库查询.拿到数据以后才展 ...

  3. [Android] Android 用于异步加载 ContentProvider 中的内容的机制 -- Loader 机制 (LoaderManager + CursorLoader + LoaderManager.LoaderCallbacks)

    Android 用于异步加载 ContentProvider 中的内容的机制 -- Loader 机制 (LoaderManager + CursorLoader + LoaderManager.Lo ...

  4. [置顶] Android异步加载数据库和多线程编程

    Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发.尚未有统一中文名称,中国大陆地区较多人使用“安卓” ...

  5. android 网络异步加载数据进度条

    ProgressDialog progressDialog = null; public static final int MESSAGETYPE = 0; private void execute( ...

  6. Android 图片异步加载的体会,SoftReference已经不再适用

      在网络上搜索Android图片异步加载的相关文章,目前大部分提到的解决方案,都是采用Map<String, SoftReference<Drawable>>  这样软引用的 ...

  7. ajax验证表单元素规范正确与否 ajax展示加载数据库数据 ajax三级联动

    一.ajax验证表单元素规范正确与否 以用ajax来验证用户名是否被占用为例 1创建表单元素<input type="text" id="t"> 2 ...

  8. Android图片异步加载之Android-Universal-Image-Loader

    将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就 ...

  9. Android图片异步加载之Android-Universal-Image-Loader(转)

    今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异步加载解决 ...

随机推荐

  1. 用R进行统计学分析

    1.基本统计 summary函数:R中的summary函数根据输入的类提供输入的摘要.该函数根据输入对象的类调用各种函数.返回值也取决于输入对象.例如,如果输入是一个由数字数据组成的向量,它将为数据提 ...

  2. toString方法的用法

    public class JLDtoS {   public static void main(String[]args)   {    long a=123;    Long aa=new Long ...

  3. np.random.randn()、np.random.rand()、np.random.randint()

    (1)np.random.randn()函数 语法: np.random.randn(d0,d1,d2……dn) 1)当函数括号内没有参数时,则返回一个浮点数: 2)当函数括号内有一个参数时,则返回秩 ...

  4. Robotium原理初步--Android自动化测试学习历程

    章节:自动化基础篇——Robotium原理初步(第四讲) 主要讲解内容与笔记: 一.基于控件 1.spinner——下拉菜单 2.TabHost——左右滑动选择菜单,类似电话本 3.Gallery—— ...

  5. springboot自定义消息转换器HttpMessageConverter

    在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换,底层这种灵活的消息转换机制就是利用HttpMessageCo ...

  6. runloop - 介绍

    1. 简介 没有的话 有的话

  7. ViewPager 带动画的欢迎界面

    一般APP进去之后都会有几张图片来导航,这里就学习怎么在这张图片切换的时候添加切换动画效果 先看布局文件 activity_main.layout <?xml version="1.0 ...

  8. Spring框架之Bean的作用范围和生命周期的注解

    1. Bean的作用范围注解 * 注解为@Scope(value="prototype"),作用在类上.值如下: * singleton -- 单例,默认值 * prototype ...

  9. git 一些提交等用法

    从服务器上下载项目到em_cesium:git clone ssh://kjwang@code-bj.clustertech.com:29418/em-satdata em_cesium 在本地新建一 ...

  10. PS大神的作品,每张都是科幻大片!

    相信大家在网上一定见过 各种PS的作品 但是要想成为“PS大神”, 不仅仅要会P图, 最关键的就是脑洞! 同样的马路破坏效果 在大神操作后变成了大片! 摩托车换成了骏马 这效果果然不一般! 这个绝对牛 ...