千家信息网

Android架构中的数据库框架该如何搭建

发表于:2025-11-12 作者:千家信息网编辑
千家信息网最后更新 2025年11月12日,这篇文章将为大家详细讲解有关Android架构中的数据库框架该如何搭建,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。前言:你还在苦恼的写SQL么?你还
千家信息网最后更新 2025年11月12日Android架构中的数据库框架该如何搭建

这篇文章将为大家详细讲解有关Android架构中的数据库框架该如何搭建,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

    前言:

    你还在苦恼的写SQL么?你还在为数据库升级而烦恼么?你还在因查询数据而写繁琐不可用的代码么? 在这,这些都将不复存在!在本篇中,将会让你一点一滴从无到有创建一个不再为数据库而烦恼的框架。

    在开始之前我们先欣赏一下本章实现的最终效果 效果展示

    图所示:

    • 对应的model,可直接成为表结构,不再写对应的 Create table xxx对应的SQL了

    • 对应model的Dao层,里面封装了数据表的基本操作(增删改查)

    • 对应的增删改查操作,再也不用SQL了,全用对象处理

    接下来开始实战了

    1、先创建对应相关操作的注解

    1.1 bTable 标识表

    @Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface DbTable { //表名    String value();}

    1.2 DbPrimaryKey 标识主键

    @Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface DbPrimaryKey {        //表列名    String value();    //是否为自动增长    boolean isAuto() default false;}

    1.3 DbFiled 标识成员属性

    @Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface DbFiled {  //表列名    String value();    /* 这里可以像主键一样,添加其他属性,比如是否唯一约束,是否非空等 甚至可以将主键的约束放在这里来,只是表明可以这样做,具体怎样扩展,完全可以按你们想法来 */}

    2、创建对应表操作类Dao层

    2.1 建 待实现的基层 IBaseDao

    public interface IBaseDao {    Long insert(T entity);    int update(T entity, T where);    /**     * 删除数据     *     * @param where     * @return     */    int delete(T where);    /**     * 查询数据     */    List query(T where);    List query(T where, String groupBy, String orderBy, String having, Integer startIndex,                  Integer limit);}

    代码分析:

    这里创建了基类 IBaseDao ,拥有待实现的增删改查, T 代表对应的 数据表结构的 model

    2.2 建已实现的基层 BaseDao

    public class BaseDao implements IBaseDao {    private static final String TAG = "hqk";    /**     * 持有数据库操作类的引用     */    private SQLiteDatabase database;    /**     * 持有操作数据库表所对应的java类型     * User     */    private Class entityClass;    /**     * 保证实例化一次     */    private boolean isInit = false;    private String tableName;    //    检查表    private HashMap cacheMap;    protected BaseDao() {    }    protected synchronized boolean init(Class entity, SQLiteDatabase sqLiteDatabase) {        if (!isInit) {            //初始化完了  自动建表            entityClass = entity;            database = sqLiteDatabase;            if (entity.getAnnotation(DbTable.class) == null) {                tableName = entity.getClass().getSimpleName();            } else {                tableName = entity.getAnnotation(DbTable.class).value();            }            if (!database.isOpen()) {                return false;            }            String sql = createTable();            database.execSQL(sql);            //建立好映射关系            initCacheMap();            isInit = true;        }        return true;    }    /**     * 将真实表中的列名  + 成员变量进行 映射     * 缓存对应的 表 Model里的属性名以及对应表列名     */    private void initCacheMap() {        cacheMap = new HashMap<>();        //这里没有必要查询 对应表中的任何数据,只想要对应表列名,所以 这 limit 0        String sql = "select * from " + tableName + " limit 0";        Cursor cursor = database.rawQuery(sql, null);        String[] columnNames = cursor.getColumnNames();        Field[] columnFields = entityClass.getDeclaredFields();        //获取对应表中的列名数组,以及对应表Model里面的属性数组        for (String columnName : columnNames) {            Field resultField = null;            for (Field field : columnFields) {                //拿到对应属性的注解值                String fieldAnnotationName = field.getAnnotation(DbFiled.class).value();                //如果对应的属性注解值与数据库表列名相同,则拿到对应属性值                if (columnName.equals(fieldAnnotationName)) {                    resultField = field;                    break;                }            }            if (resultField != null) {                cacheMap.put(columnName, resultField);            }        }    }    /**     * 组装 创建表的SQL语句     *     * @return     */    private String createTable() {        StringBuffer stringBuffer = new StringBuffer();        //开始组装 SQL语句        stringBuffer.append("create table if not exists ");        stringBuffer.append(tableName + " (");        Field[] fields = entityClass.getDeclaredFields();        for (Field field : fields) {            Class type = field.getType();            String primaryKey = null;            try {                primaryKey = field.getAnnotation(DbPrimaryKey.class).value();            } catch (Exception e) {            }            Log.i(TAG, "createTable primaryKey " + primaryKey);            Log.i(TAG, "createTable type " + type);            if (type == String.class) {                if (null == primaryKey) {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " TEXT,");                } else {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " TEXT PRIMARY KEY,");                }            } else if (type == Double.class) {                if (null == primaryKey) {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  DOUBLE,");                } else {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  DOUBLE PRIMARY KEY,");                }            } else if (type == Integer.class) {                if (null == primaryKey) {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  INTEGER,");                } else {                    boolean isAuto = field.getAnnotation(DbPrimaryKey.class).isAuto();                    if (isAuto) {                        stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  INTEGER PRIMARY KEY AUTOINCREMENT,");                    } else {                        stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  INTEGER PRIMARY KEY,");                    }                }            } else if (type == Long.class) {                if (null == primaryKey) {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  BIGINT,");                } else {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  BIGINT PRIMARY KEY,");                }            } else if (type == byte[].class) {                if (null == primaryKey) {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  BLOB,");                } else {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  BLOB PRIMARY KEY,");                }            } else {                  /*                不支持的类型                 */                continue;            }        }        //循环完成后,最后一项会有 逗号 ,如果最后一个是逗号,则删除最后一个字符        if (stringBuffer.charAt(stringBuffer.length() - 1) == ',') {            stringBuffer.deleteCharAt(stringBuffer.length() - 1);        }        //SQL 语句 收尾        stringBuffer.append(")");        Log.i(TAG, "createTable: " + stringBuffer.toString());        return stringBuffer.toString();    }    @Override    public Long insert(T entity) {        Map map = getValues(entity);        ContentValues contentValues = getContentValues(map);        return database.insert(tableName, null, contentValues);    }    /**     * 获取对应 model 属性以及对应的注解值(表列名值)     *     * @param entity 对应 表结构的model     * @return 返回 key= 列名,value=属性的值          map集合     */    private Map getValues(T entity) {        HashMap map = new HashMap<>();        //获取对应缓存 model 里面的属性键        Iterator fieldIterator = cacheMap.values().iterator();        while (fieldIterator.hasNext()) {            Field field = fieldIterator.next();            field.setAccessible(true);            try {                Object object = field.get(entity);                if (object == null) {                    continue;                }                String value = object.toString();                String key = field.getAnnotation(DbFiled.class).value();                //遍历 取出对应 属性的值 以及对应的 注解值,并添加至Map里                if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {                    map.put(key, value);                }            } catch (IllegalAccessException e) {                e.printStackTrace();            }        }        return map;    }    /**     * 数据库数据结构的封装     *     * @param map 带有 以表列名为键,的map     * @return 数据库需要的封装格式     */    private ContentValues getContentValues(Map map) {        ContentValues contentValues = new ContentValues();        Set keys = map.keySet();        Iterator iterator = keys.iterator();        while (iterator.hasNext()) {            String key = iterator.next();            String value = map.get(key);            if (value != null) {                contentValues.put(key, value);            }        }        return contentValues;    }    @Override    public int update(T entity, T where) {        Map values = getValues(entity);        ContentValues contentValues = getContentValues(values);        //条件        Map whereMap = getValues(where);        Condition condition = new Condition(whereMap);        return database.update(tableName, contentValues, condition.whereClause, condition.whereArgs);    }    class Condition {        String whereClause;        String[] whereArgs;        public Condition(Map whereClause) {            boolean flag = false;            if (true && flag) {            }            ArrayList list = new ArrayList();            StringBuilder stringBuilder = new StringBuilder();            // 这里之所以先添加 1=1 这个条件 是因为            // SQL  where  后面需要给条件判断,而下面 while 循环 直接添加了 and            // SQL 语句就变成了 where and  这显然不符合SQL语句            // 因此 加上 1=1 就变成了  where 1=1 and xx。起了一个呈上去下的作用            stringBuilder.append("1=1");            Set keys = whereClause.keySet();            Iterator iterator = keys.iterator();            while (iterator.hasNext()) {                String key = (String) iterator.next();                String value = whereClause.get(key);                if (value != null) {                    stringBuilder.append(" and " + key + " =?");                    list.add(value);                }            }            this.whereClause = stringBuilder.toString();            this.whereArgs = (String[]) list.toArray(new String[list.size()]);        }    }    @Override    public int delete(T where) {        Map map = getValues(where);        Condition condition = new Condition(map);        return database.delete(tableName, condition.whereClause, condition.whereArgs);    }    @Override    public List query(T where) {        return query(where, null, null, null, null, null        );    }    //所有  条件    @Override    public List query(T where, String groupBy, String orderBy, String having,Integer startIndex,                         Integer limit) {        String limitString=null;        if(startIndex!=null&&limit!=null)        {            limitString=startIndex+" , "+limit;        }        Map map=getValues(where);        Condition condition=new Condition(map);        Cursor cursor=  database.query(tableName, null, condition.whereClause,                condition.whereArgs,                groupBy, having,                orderBy, limitString        );//        封装   --返回        List result = getResult(cursor, where);        cursor.close();        return result;    }    private List getResult(Cursor cursor, T where) {        ArrayList  list=new ArrayList();        Object item;        while (cursor.moveToNext()) {            try {//                cachmap        ---对象中的成员变量    Filed    annotion-- tb_name//cacheMap    name  ---Filed       1//            tb_name       ---Filed  2                item=where.getClass().newInstance();                Iterator iterator=cacheMap.entrySet().iterator();                while (iterator.hasNext())                {                    Map.Entry entry= (Map.Entry) iterator.next();                    //tb_name                    /**                     * 得到列名                     */                    String colomunName= (String) entry.getKey();//                    通过列名查找到游标的索性                    Integer colmunIndex= cursor.getColumnIndex(colomunName);//                    Filed//反射的成员 cursor                    Field field= (Field) entry.getValue();                    Class type=field.getType();                    if(colmunIndex!=-1)                    {//                        if (type == String.class) {                            field.set(item, cursor.getString(colmunIndex));                        }else if(type==Double.class)                        {                            field.set(item,cursor.getDouble(colmunIndex));                        }else  if(type==Integer.class)                        {                            field.set(item,cursor.getInt(colmunIndex));                        }else if(type==Long.class)                        {                            field.set(item,cursor.getLong(colmunIndex));                        }else  if(type==byte[].class)                        {                            field.set(item,cursor.getBlob(colmunIndex));                            /*                            不支持的类型                             */                        }else {                            continue;                        }                    }                }                list.add(item);            } catch ( Exception e) {                e.printStackTrace();            }        }        return list;    }}

    代码分析:

    在这个BaseDao 里面,几乎分担了数据表大部分的脏活累活,根据model结构自动生成对应SQL并创建对应表,以及基础的增删改查操作。

    2.3 建对应model 的Dao层

    1.UserDao

    public class UserDao extends BaseDao {    @Override    public Long insert(User entity) {        return super.insert(entity);    }    @Override    public List query(User where) {        return super.query(where);    }    @Override    public int delete(User where) {        return super.delete(where);    }    @Override    public int update(User entity, User where) {        return super.update(entity, where);    }    @Override    public List query(User where, String groupBy, String orderBy, String having, Integer startIndex, Integer limit) {        return super.query(where, groupBy, orderBy, having, startIndex, limit);    }}

    2.PhotoDao

    public class PhotoDao extends BaseDao {    @Override    public Long insert(Photo entity) {        return super.insert(entity);    }    @Override    public int update(Photo entity, Photo where) {        return super.update(entity, where);    }    @Override    public List query(Photo where) {        return super.query(where);    }    @Override    public int delete(Photo where) {        return super.delete(where);    }}

    代码分析:

    虽然 BaseDao 已经完成了几乎所有的操作,但是一旦遇到多表查询的时候,光是一个BaseDao远远不够。所以这里还是选择创建不同modelDao层,并继承与BaseDao。也就是说,有多少表,最好就创建对应多少个Dao层。

    3、创建数据库工厂

    public class BaseDaoFactory {    private final String TAG = "hqk";    private SQLiteDatabase sqLiteDatabase;    private String sqliteDatabasePath;    private static BaseDaoFactory instance = new BaseDaoFactory();    //饿汉单例模式    public static BaseDaoFactory getInstance() {        return instance;    }    public BaseDaoFactory() {        //读者可随意更改路径以及对应数据库名,这里演示暂时放在根目录        sqliteDatabasePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/hqk.db";        sqLiteDatabase = SQLiteDatabase.openOrCreateDatabase(sqliteDatabasePath, null);        Log.i(TAG, "sqliteDatabasePath : " + sqliteDatabasePath);        Log.i(TAG, "sqLiteDatabase : " + sqLiteDatabase.getPath());    }    /**     * @param clazz     * @param entityClass     * @param          我们在这可以把它看成某一个对象,它继承与 BaseDao ,而里面的T 就是下面的那个空对象     * @param          我们在这可以吧它看成某一个空对象 T     * @return     */    public synchronized , T> R createBaseDao(Class clazz, Class entityClass) {        BaseDao baseDao = null;        try {            baseDao = clazz.newInstance();            baseDao.init(entityClass, sqLiteDatabase);        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (InstantiationException e) {            e.printStackTrace();        }        return (R) baseDao;    }}

    代码分析:

    这里也没啥好分析的,就一个数据库创建,以及对应model的初始化。唯一值得注意的就是初始化的时候用了俩个泛型,具体什么意思,可按照代码注释理解。

    4、创建对应model

    1.User

    @DbTable("tb_user")public class User {        @DbPrimaryKey(value = "tb_id", isAuto = true)    @DbFiled("tb_id")    public Integer id;    @DbFiled("tb_name")    public String name;//        @DbFiled("tb_age")    public Integer age;    public User(String name, Integer age) {        this.name = name;        this.age = age;    }    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Integer getAge() {        return age;    }    public void setAge(Integer age) {        this.age = age;    }    public User() {    }}

    2.Photo

    @DbTable("tb_photo")public class Photo {    @DbFiled("time")    private  String time;    @DbFiled("id")    private  Long id;    @DbFiled("path")    private  String path;    public Photo( ) {    }    public Photo(String time, Long id, String path) {        this.time = time;        this.id = id;        this.path = path;    }    public void setTime(String time) {        this.time = time;    }    public void setId(Long id) {        this.id = id;    }    public void setPath(String path) {        this.path = path;    }}

    代码分析:

    这俩类就是对应表结构model 类,用到了对应注解,相信通过注解能够清楚知道对应表结构是怎样的。

    5、最终使用

    ainActivity

    public class MainActivity extends AppCompatActivity {    UserDao userDao;    PhotoDao photoDao;    private ArrayList listUser = new ArrayList<>();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        requestPermission(this);    }    public void save(View view) {        User user = new User("hqk", 18);        long size = userDao.insert(user);        Photo photo = new Photo("time", System.currentTimeMillis(), "path");        long photoSize = photoDao.insert(photo);        Toast.makeText(this, "save line :   " + size, Toast.LENGTH_LONG).show();    }    public void update(View view) {        User where = new User();        where.setAge(18);        int size = userDao.update(new User("TOM", 99), where);        Toast.makeText(this, "update Size :   " + size, Toast.LENGTH_LONG).show();    }    public void delete(View view) {        User where = new User();        where.setAge(18);        int size = userDao.delete(where);        Toast.makeText(this, "delete Size :   " + size, Toast.LENGTH_LONG).show();    }    public void queryList(View view) {        listUser.clear();        listUser.addAll(userDao.query(new User()));        Toast.makeText(this, "查询条数为:" + listUser.size(), Toast.LENGTH_LONG).show();    }    public void requestPermission(            Activity activity) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ActivityCompat.checkSelfPermission(activity,                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {            ActivityCompat.requestPermissions(activity, new String[]{                    Manifest.permission.READ_EXTERNAL_STORAGE,                    Manifest.permission.WRITE_EXTERNAL_STORAGE            }, 1);            return;        }        createTable();    }    private void createTable() {        userDao = BaseDaoFactory.getInstance().createBaseDao(UserDao.class, User.class);        photoDao = BaseDaoFactory.getInstance().createBaseDao(PhotoDao.class, Photo.class);    }    @Override    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        createTable();    }}

    关于Android架构中的数据库框架该如何搭建就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

    0