Android 打造属于自己的数据库操作类。

Kelly916
• 阅读 1066

1、概述

开发Android的同学都知道sdk已经为我们提供了一个SQLiteOpenHelper类来创建和管理SQLite数据库,通过写一个子类去继承它,就可以方便的创建、管理数据库。但是当我们需要去做增删改查的操作的时候,就得通过getWritableDatabase获取一个SQLiteDataBase然后老老实实去写操作值的put以及查询返回的Cursor处理,其实我们可以搞一个对象来帮我们干这些事情,打造属于你自己的数据库操作类。

2、操作类的初显形

假设现在我们什么都没有,我们要去搞一个对象来给我们干这件事情,它需要有什么才可以干呢?
先想想要做的事情:管理数据库的操作
那要做数据库的操作需要什么就很简单了吧?
1、要操作数据库,所以需要一个SQLiteDataBase对象,可以通过SQLiteOpenHelper的子类来获取。
2、此外数据库要创建,还需要数据库信息吧?那就直接变量引入。
3、有了数据库信息,创建了数据库,你要操作,怎么也得告诉我操作哪个表。所以还得包含创建表和更新表的信息,由于表一般会有多张,所以这里用一个数组变量。

有了信息还得交互,不然我怎么知道你要怎么创建表,所以我们在构造方法中直接获取这些信息。

接下看上面文字的代码表示

public abstract class DataBaseHelper {

     /**
     * 用来创建和获取数据库的SQLiteOpenHelper
     */
    protected DBHelper mDbHelper;
    /**
     * 数据库对象
     */
    protected SQLiteDatabase mDb;

    /**
     * 数据库信息
     */
    private int mDbVersion;//版本
    private String mDbName;//数据库名
    /**
     * 创建表语句
     */
    private String[] mDbCreateSql;
    /**
     * 更新表语句
     */
    private String[] mDbUpdateSql;

    protected abstract int getMDbVersion(Context context);

    protected abstract String getDbName(Context context);

    protected abstract String[] getDbCreateSql(Context context);

    protected abstract String[] getDbUpdateSql(Context context);

    public DataBaseHelper(Context context) {
        this.mDbVersion = this.getMDbVersion(context);
        this.mDbName = this.getDbName(context);
        this.mDbCreateSql = this.getDbCreateSql(context);
        this.mDbUpdateSql = this.getDbUpdateSql(context);
        this.mDbHelper = new DBHelper(context,this.mDbName,null,this.mDbVersion);
    }

    protected void open(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                mDb = mDbHelper.getWritableDatabase();
            }
        }).start();

    }

    protected SQLiteDatabase getDB(){
        return this.mDb;
    }


    public void close(){
        this.mDb.close();
        this.mDbHelper.close();
    }

    private class DBHelper extends SQLiteOpenHelper{

        public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            String[] arr = DataBaseHelper.this.mDbCreateSql;
            //执行创建表语句
            for (int i=0;i<arr.length;i++){
                String sql = arr[i];
                db.execSQL(sql);
            }
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            String[] arr = DataBaseHelper.this.mDbUpdateSql;
             //执行更新语句
            for (int i=0;i<arr.length;i++){
                String sql = arr[i];
                db.execSQL(sql);
            }
        }
    }
} 

代码比较简单,包含了进行数据库操作要用到的各种信息,并且在初始化的进行了赋值。同时还提供了SQLiteDatabase的open、close。同时在这里用到了抽象方法是因为考虑创建多个数据库的情况,让子类来提供具体的数据库信息,我只管做创建和操作就行了。

这里我们的数据库操作类已经初显雏形了,但是现在除了创建表还没什么用。操作类不提供简便的操作还叫什么操作类,下面就来说说操作。

我们要做操作类,无非是要简化操作,就像当老板一样。我告诉你一些用到的东西,你去给我完成这个事情。哈哈。

假如我现在就是要操作数据库的老板,那我其实只想告诉你必要的事情,其它的我都不想做。

那么必要的信息只有表名,要操作的字段和值,如果是删除、更新、和查询的话多加个筛选条件。接下来看代码

 /**
     * 统一对ContentValues处理
     * @param contentValues
     * @param key
     * @param value
     */
    private void ContentValuesPut(ContentValues contentValues,String key,Object value){
        if (value==null){
            contentValues.put(key,"");
        }else{
            String className = value.getClass().getName();
            if (className.equals("java.lang.String")){
                contentValues.put(key,value.toString());
            } else if (className.equals("java.lang.Integer")){
                contentValues.put(key,Integer.valueOf(value.toString()));
            } else if (className.equals("java.lang.Float")){
                contentValues.put(key,Float.valueOf(value.toString()));
            } else if (className.equals("java.lang.Double")){
                contentValues.put(key,Double.valueOf(value.toString()));
            } else if (className.equals("java.lang.Boolean")){
                contentValues.put(key,Boolean.valueOf(value.toString()));
            } else if (className.equals("java.lang.Long")){
                contentValues.put(key,Long.valueOf(value.toString()));
            } else if (className.equals("java.lang.Short")){
                contentValues.put(key,Short.valueOf(value.toString()));
            }
        }
    }

    /**
     * 根据数组的列和值进行insert
     * @param tableName
     * @param columns
     * @param values
     * @return
     */
    public boolean insert(String tableName,String[] columns,Object[] values){
        ContentValues contentValues = new ContentValues();
        for (int rows = 0; rows < columns.length;++rows){
             ContentValuesPut(contentValues,columns[rows],values[rows]);
        }
        long rowId = this.mDb.insert(tableName,null,contentValues);
        return rowId!=-1;
    }

    /**
     * 根据map来进行insert
     * @param tableName
     * @param columnValues
     * @return
     */
    public boolean insert(String tableName,Map<String,Object> columnValues){
        ContentValues contentValues = new ContentValues();
        Iterator iterator = columnValues.keySet().iterator();
        while (iterator.hasNext()){
            String key = (String) iterator.next();
            this.ContentValuesPut(contentValues,key,columnValues.get(key));
        }

        long rowId = this.mDb.insert(tableName,null,contentValues);
        return rowId!=-1;
    }


    /**
     * 统一对数组where条件进行拼接
     * @param whereColumns
     * @return
     */
    private String initWhereSqlFromArray(String[] whereColumns){
        StringBuffer whereStr = new StringBuffer();
        for (int i=0;i<whereColumns.length;++i){
            whereStr.append(whereColumns[i]).append(" = ? ");
            if (i<whereColumns.length-1){
                whereStr.append(" and ");
            }
        }
        return whereStr.toString();
    }

    /**
     * 统一对map的where条件和值进行处理
     * @param whereParams
     * @return
     */
    private Map<String,Object> initWhereSqlFromMap(Map<String,String> whereParams){
        Set set = whereParams.keySet();
        String[] temp = new String[whereParams.size()];
        int i = 0;
        Iterator iterator = set.iterator();
        StringBuffer whereStr = new StringBuffer();
        while (iterator.hasNext()){
            String key = (String) iterator.next();
            whereStr.append(key).append(" = ? ");
            temp[i] = whereParams.get(key);
            if (i<set.size()-1){
                whereStr.append(" and ");
            }
            i++;
        }
        HashMap result = new HashMap();
        result.put("whereSql",whereStr);
        result.put("whereSqlParam",temp);
        return result;
    }


    /**
     * 根据数组条件来update
     * @param tableName
     * @param columns
     * @param values
     * @param whereColumns
     * @param whereArgs
     * @return
     */
    public boolean update(String tableName,String[] columns,Object[] values,String[] whereColumns,String[] whereArgs){
        ContentValues contentValues = new ContentValues();
        for (int i=0;i<columns.length;++i){
            this.ContentValuesPut(contentValues,columns[i],values[i]);
        }
        String whereClause = this.initWhereSqlFromArray(whereColumns);
        int rowNumber = this.mDb.update(tableName,contentValues,whereClause,whereArgs);
        return rowNumber > 0 ;
    }

    /**
     * 根据map值来进行update
     * @param tableName
     * @param columnValues
     * @param whereParam
     * @return
     */
    public boolean update(String tableName,Map<String,Object> columnValues,Map<String,String> whereParam){
        ContentValues contentValues = new ContentValues();
        Iterator iterator = columnValues.keySet().iterator();

        String columns;
        while (iterator.hasNext()){
            columns = (String) iterator.next();
            ContentValuesPut(contentValues,columns,columnValues.get(columns));
        }

        Map map = this.initWhereSqlFromMap(whereParam);
        int rowNumber = this.mDb.update(tableName,contentValues,(String)map.get("whereSql"),(String[]) map.get("whereSqlParam"));
        return rowNumber > 0;
    }

    /**
     * 根据数组条件进行delete
     * @param tableName
     * @param whereColumns
     * @param whereParam
     * @return
     */
    public boolean delete(String tableName,String[] whereColumns,String[] whereParam){
        String whereStr = this.initWhereSqlFromArray(whereColumns);
        int rowNumber = this.mDb.delete(tableName,whereStr,whereParam);
        return rowNumber > 0;
    }


    /**
     * 根据map来进行delete
     * @param tableName
     * @param whereParams
     * @return
     */
    public boolean delete(String tableName,Map<String,String> whereParams){
        Map map = this.initWhereSqlFromMap(whereParams);
        int rowNumber = this.mDb.delete(tableName,map.get("whereSql").toString(),(String[]) map.get("whereSqlParam"));
        return rowNumber > 0;
    }


    /**
     * 查询返回List
     * @param sql
     * @param params
     * @return
     */
    public List<Map> queryListMap(String sql,String[] params){
        ArrayList list = new ArrayList();
        Cursor cursor = this.mDb.rawQuery(sql,params);
        int columnCount = cursor.getColumnCount();
        while (cursor.moveToNext()){
            HashMap item = new HashMap();
            for (int i=0;i<columnCount;++i){
                int type = cursor.getType(i);
                switch (type){
                    case 0:
                        item.put(cursor.getColumnName(i),null);
                        break;
                    case 1:
                        item.put(cursor.getColumnName(i), cursor.getInt(i));
                        break;
                    case 2:
                        item.put(cursor.getColumnName(i),cursor.getFloat(i));
                        break;
                    case 3:
                        item.put(cursor.getColumnName(i),cursor.getString(i));
                        break;
                }
            }
            list.add(item);
        }
        cursor.close();
        return list;
    }

    /**
     * 查询单条数据返回map
     * @param sql
     * @param params
     * @return
     */
    public Map queryItemMap(String sql,String[] params){
        Cursor cursor = this.mDb.rawQuery(sql,params);
        HashMap map = new HashMap();
        if (cursor.moveToNext()){
            for (int i = 0;i < cursor.getColumnCount();++i){
                int type = cursor.getType(i);
                switch (type){
                    case 0:
                        map.put(cursor.getColumnName(i),null);
                        break;
                    case 1:
                        map.put(cursor.getColumnName(i),cursor.getInt(i));
                        break;
                    case 2:
                        map.put(cursor.getColumnName(i),cursor.getFloat(i));
                        break;
                    case 3:
                        map.put(cursor.getColumnName(i),cursor.getString(i));
                        break;
                }
            }
        }
        cursor.close();
        return map;
    }

    public void execSQL(String sql){
        this.mDb.execSQL(sql);
    }

    public void execSQL(String sql,Object[] params){
        this.mDb.execSQL(sql,params);
    } 

上面的操作代码就完毕了,这里主要对增删改的参数是数组和Map的情况进行了处理,对查询的结果进行了处理,代码比较简单也都有注释,这里就不做特别说明了。到这里一个数据库操作类就成型了。

3、操作类的继续完善

通过上面的过程已经可以使用了,那么先来看看使用,我们只需要继承操作抽象类告诉它具体的数据库信息以及建表语句。

public class TestDBHelper extends DataBaseHelper {

    private static TestDBHelper mTestDBHelper;

    private TestDBHelper(Context context){
        super(context);
    }

    public static TestDBHelper getInstance(Context context){
        if (mTestDBHelper==null){
            synchronized (DataBaseHelper.class){
                if (mTestDBHelper==null){
                    mTestDBHelper = new TestDBHelper(context);
                    if (mTestDBHelper.getDB()==null||!mTestDBHelper.getDB().isOpen()){
                        mTestDBHelper.open();
                    }
                }
            }
        }
        return mTestDBHelper;
    }

    @Override
    protected int getMDbVersion(Context context) {
        return 1;
    }

    @Override
    protected String getDbName(Context context) {
        return "test.db";
    }

    @Override
    protected String[] getDbCreateSql(Context context) {
        String[] a = new String[1];
        a[0] = "CREATE TABLE user (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,gender TEXT,age INTEGER)";
        return a;
    }

    @Override
    protected String[] getDbUpdateSql(Context context) {
        return new String[0];
    }
} 

重写父类的抽象方法告诉它数据库信息以及建表语句,然后提供一个单例供外部获取,如果没有open就open数据库,接下来看看使用

4、使用

直接获取,然后传入你想操作的表信息,So Easy!

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button selectBtn;
    private Button insertBtn;
    private Button updateBtn;
    private Button deleteBtn;
    private TextView contentTv;

    private TestDBHelper testDBHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        testDBHelper = TestDBHelper.getInstance(getApplicationContext());

        selectBtn = (Button) findViewById(R.id.select_btn);
        insertBtn = (Button) findViewById(R.id.insert_btn);
        updateBtn = (Button) findViewById(R.id.update_btn);
        deleteBtn = (Button) findViewById(R.id.delete_bt);
        contentTv = (TextView) findViewById(R.id.content_tv);


        selectBtn.setOnClickListener(this);
        insertBtn.setOnClickListener(this);
        updateBtn.setOnClickListener(this);
        deleteBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.select_btn:
                List<Map> list = testDBHelper.queryListMap("select * from user",null);
                contentTv.setText(String.valueOf(list));
                break;
            case R.id.insert_btn:
                testDBHelper.insert("user",new String[]{"name","gender","age"},new Object[]{"qiangyu","male",23});
                break;
            case R.id.update_btn:
                testDBHelper.update("user",new String[]{"name","gender","age"},new Object[]{"yangqiangyu","male",24},
                        new String[]{"name"},new String[]{"qiangyu"});
                break;
            case R.id.delete_bt:
                testDBHelper.delete("user",
                        new String[]{"name"},new String[]{"qiangyu"});
                break;
        }
    }
} 

很简单了,附一张演示图
gif制作了做了压缩,图的效果不好请见谅
Android 打造属于自己的数据库操作类。

是不是简单多了

5、最后的完善

在第3步里,我们的数据库信息,和建表语句都是写在具体的代码里的,这样我们每次修改都要动代码。Android推荐我们这些具体的信息都写在配置文件xml里面,那么我们就来做一下修改。

建立一个db.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <array name="DATABASE_INFO">
        <item>test.db</item>
        <item>1</item>
    </array>

    <array name="CREATE_TABLE_SQL">
        <item>CREATE TABLE user (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,gender TEXT,age INTEGER)</item>
    </array>

    <array name="UPDATE_TABLE_SQL">
        <item></item>
    </array>

</resources> 

现在的获取数据信息的代码是这样

 @Override
    protected int getMDbVersion(Context context) {
        return Integer.valueOf(context.getResources().getStringArray(R.array.DATABASE_INFO)[1]);
    }

    @Override
    protected String getDbName(Context context) {
        return context.getResources().getStringArray(R.array.DATABASE_INFO)[0];
    }

    @Override
    protected String[] getDbCreateSql(Context context) {
        return context.getResources().getStringArray(R.array.CREATE_TABLE_SQL);
    }

    @Override
    protected String[] getDbUpdateSql(Context context) {
        return context.getResources().getStringArray(R.array.UPDATE_TABLE_SQL);
    } 

从配置文件当中获取数据库信息,这样以后每次修改只需要修改xml文件就可以了。

6、结语

到此,一个数据库操作类就完成啦,当然你可以根据自己的需要在其实添加更多的便捷操作方法。

这里提供的操作类,在使用的时候我们还在需要在Activity中写一些查询的sql代码,我们可以再搞一个统一做各种具体操作表的对象。

觉得不错别忘记点赞哟!

最后送给大家一个鸡汤,共勉

他每做一件小事的时候 他都像救命稻草一样抓着 有一天我一看 嚯 好家伙 他抱着的是已经是让我仰望的参天大树

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
2年前
Android蓝牙连接汽车OBD设备
//设备连接public class BluetoothConnect implements Runnable {    private static final UUID CONNECT_UUID  UUID.fromString("0000110100001000800000805F9B34FB");
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Kelly916
Kelly916
Lv1
此地动归念,长年悲倦游。
文章
1
粉丝
0
获赞
0
热门文章

暂无数据