温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2021-09-24 17:43:25 来源:亿速云 阅读:152 作者:柒染 栏目:开发技术

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

    前言:

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

    在开始之前我们先欣赏一下本章实现的最终效果 效果展示 Android架构中的数据库框架该如何搭建

     如图所示:

    • 对应的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<T> {
    
        Long insert(T entity);
    
        int update(T entity, T where);
    
        /**
         * 删除数据
         *
         * @param where
         * @return
         */
        int delete(T where);
    
    
        /**
         * 查询数据
         */
        List<T> query(T where);
    
        List<T> query(T where, String groupBy, String orderBy, String having, Integer startIndex,
                      Integer limit);
    }

    代码分析:

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

    2.2 建已实现的基层 BaseDao

    public class BaseDao<T> implements IBaseDao<T> {
    
        private static final String TAG = "hqk";
    
        /**
         * 持有数据库操作类的引用
         */
        private SQLiteDatabase database;
        /**
         * 持有操作数据库表所对应的java类型
         * User
         */
        private Class<T> entityClass;
        /**
         * 保证实例化一次
         */
        private boolean isInit = false;
    
        private String tableName;
    
        //    检查表
        private HashMap<String, Field> cacheMap;
    
        protected BaseDao() {
        }
    
        protected synchronized boolean init(Class<T> 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<String, String> map = getValues(entity);
            ContentValues contentValues = getContentValues(map);
            return database.insert(tableName, null, contentValues);
        }
    
        /**
         * 获取对应 model 属性以及对应的注解值(表列名值)
         *
         * @param entity 对应 表结构的model
         * @return 返回 key= 列名,value=属性的值          map集合
         */
        private Map<String, String> getValues(T entity) {
            HashMap<String, String> map = new HashMap<>();
            //获取对应缓存 model 里面的属性键
            Iterator<Field> 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<String, String> map) {
            ContentValues contentValues = new ContentValues();
            Set keys = map.keySet();
            Iterator<String> 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<String, String> 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<T> query(T where) {
            return query(where, null, null, null, null, null
            );
        }
        //所有  条件
        @Override
        public List<T> 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<T> result = getResult(cursor, where);
            cursor.close();
            return result;
        }
    
    
    
    
    
        private List<T> 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<User> extends BaseDao<User> {
    
        @Override
        public Long insert(User entity) {
            return super.insert(entity);
        }
    
        @Override
        public List<User> 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<User> 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<Photo> extends BaseDao<Photo> {
    
        @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<Photo> 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 <R>         我们在这可以把它看成某一个对象,它继承与 BaseDao<T> ,而里面的T 就是下面的那个空对象
         * @param <T>         我们在这可以吧它看成某一个空对象 T
         * @return
         */
        public synchronized <R extends BaseDao<T>, T> R createBaseDao(Class<R> clazz, Class<T> 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<User> userDao;
    
        PhotoDao<Photo> photoDao;
    
        private ArrayList<User> 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架构中的数据库框架该如何搭建就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI