zoukankan      html  css  js  c++  java
  • Android-LoaderManager异步加载数据库数据

    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>

    效果:

  • 相关阅读:
    第一章 教育观
    教资时间及考试分布情况
    第二章 信号量及条件变量(三)——> 重点
    Apache ftpServer 配置用户
    下载谷歌拼音输入法离线包
    springboot 启动脚本优化
    Json序列化和反序列化注意点-无参构造器
    Springboot2使用redis提示无法注入redisTemplate
    【转】iOS 保持界面流畅的技巧
    Java文件操作相关
  • 原文地址:https://www.cnblogs.com/android-deli/p/10176986.html
Copyright © 2011-2022 走看看