zoukankan      html  css  js  c++  java
  • 读ActiveAndroid源码(三)

      上一章,我们读完了Conguration这个类。最后我们发现,Conguration就是为了数据库的初始化。其中包含了内存大小、数据库名称、数据库版本、parser信息。 

    public static synchronized void initialize(Configuration configuration) {
            if (sIsInitialized) {
                Log.v("ActiveAndroid already initialized.");
                return;
            }
    
            sContext = configuration.getContext();
            sModelInfo = new ModelInfo(configuration);
            sDatabaseHelper = new DatabaseHelper(configuration);
    
            // TODO: It would be nice to override sizeOf here and calculate the memory
            // actually used, however at this point it seems like the reflection
            // required would be too costly to be of any benefit. We'll just set a max
            // object size instead.
            sEntities = new LruCache<String, Model>(configuration.getCacheSize());
    
            openDatabase();
    
            sIsInitialized = true;
    
            Log.v("ActiveAndroid initialized successfully.");
        }

       上一章读到了这里,需要初始化一个DatabaseHelper,作为数据库的辅助类。今天来阅读这个类:

    public final class DatabaseHelper extends SQLiteOpenHelper {
        //////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC CONSTANTS
        //////////////////////////////////////////////////////////////////////////////////////
    
        public final static String MIGRATION_PATH = "migrations";
    
        //////////////////////////////////////////////////////////////////////////////////////
        // PRIVATE FIELDS
        //////////////////////////////////////////////////////////////////////////////////////
    
        private final String mSqlParser;
    
        //////////////////////////////////////////////////////////////////////////////////////
        // CONSTRUCTORS
        //////////////////////////////////////////////////////////////////////////////////////
    
        public DatabaseHelper(Configuration configuration) {
            super(configuration.getContext(), configuration.getDatabaseName(), null, configuration.getDatabaseVersion());
            copyAttachedDatabase(configuration.getContext(), configuration.getDatabaseName());
            mSqlParser = configuration.getSqlParser();
        }
        ……
    }

      由于DatabaseHelper这个类继承了SQLiteOpenHelper,构造时先构造父类:

        public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
            this(context, name, factory, version, null);
        }

      这个构造方法需要输入context、name、version,这三个参数在Conguration类中都有。

      将下来是copyAttachedDatabase方法

        public void copyAttachedDatabase(Context context, String databaseName) {
            final File dbPath = context.getDatabasePath(databaseName);
    
            // If the database already exists, return
            if (dbPath.exists()) {
                return;
            }
    
            // Make sure we have a path to the file
            dbPath.getParentFile().mkdirs();
    
            // Try to copy database file
            try {
                final InputStream inputStream = context.getAssets().open(databaseName);
                final OutputStream output = new FileOutputStream(dbPath);
    
                byte[] buffer = new byte[8192];
                int length;
    
                while ((length = inputStream.read(buffer, 0, 8192)) > 0) {
                    output.write(buffer, 0, length);
                }
    
                output.flush();
                output.close();
                inputStream.close();
            }
            catch (IOException e) {
                Log.e("Failed to open file", e);
            }
        }

      这个方法主要是 final InputStream inputStream = context.getAssets().open(databaseName); 获取assets中的数据库资源。如果在相同目录下,已经存在这个数据库就不会进行后面的操作。

      然后,再往下看就是数据库的onCreate方法:

        @Override
        public void onCreate(SQLiteDatabase db) {
            executePragmas(db);
            executeCreate(db);
            executeMigrations(db, -1, db.getVersion());
            executeCreateIndex(db);
        }

      一个一个方法看:

        private void executePragmas(SQLiteDatabase db) {
            if (SQLiteUtils.FOREIGN_KEYS_SUPPORTED) {
                db.execSQL("PRAGMA foreign_keys=ON;");
                Log.i("Foreign Keys supported. Enabling foreign key features.");
            }
        }

      这个方法主要是开始外键可用。

      关于外键,我身为一个野生伪程序员,看了下百度知道

    关系型数据库中的一条记录中有若干个属性,若其中某一个属性组(注意是组)能唯一标识一条记录,该属性组就可以成为一个主键 
    比如 
    学生表(学号,姓名,性别,班级) 
    其中每个学生的学号是唯一的,学号就是一个主键 
    课程表(课程编号,课程名,学分) 
    其中课程编号是唯一的,课程编号就是一个主键 
    成绩表(学号,课程号,成绩) 
    成绩表中单一一个属性无法唯一标识一条记录,学号和课程号的组合才可以唯一标识一条记录,所以 学号和课程号的属性组是一个主键 
    
    成绩表中的学号不是成绩表的主键,但它和学生表中的学号相对应,并且学生表中的学号是学生表的主键,则称成绩表中的学号是学生表的外键 
    
    同理 成绩表中的课程号是课程表的外键 
    
    定义主键和外键主要是为了维护关系数据库的完整性,总结一下:
    主键是能确定一条记录的唯一标识,比如,一条记录包括身份正号,姓名,年龄。身份证号是唯一能确定你这个人的,其他都可能有重复,所以,身份证号是主键。 

      继续看数据库onCreate方法中的第二个方法 executeCreate(db);

      

        private void executeCreate(SQLiteDatabase db) {
            db.beginTransaction();
            try {
                for (TableInfo tableInfo : Cache.getTableInfos()) {
                    db.execSQL(SQLiteUtils.createTableDefinition(tableInfo));
                }
                db.setTransactionSuccessful();
            }
            finally {
                db.endTransaction();
            }
        }

      这个方法用来创建表的一些,首先来看看Cache.getTableInfos()这个方法:

        public static synchronized Collection<TableInfo> getTableInfos() {
            return sModelInfo.getTableInfos();
        }

      读到这里就断了,因为我们不知道ModelInfo是什么,在本章开头我们看到:

    public static synchronized void initialize(Configuration configuration) {
            if (sIsInitialized) {
                Log.v("ActiveAndroid already initialized.");
                return;
            }
    
            sContext = configuration.getContext();
            sModelInfo = new ModelInfo(configuration);
            sDatabaseHelper = new DatabaseHelper(configuration);
    
            // TODO: It would be nice to override sizeOf here and calculate the memory
            // actually used, however at this point it seems like the reflection
            // required would be too costly to be of any benefit. We'll just set a max
            // object size instead.
            sEntities = new LruCache<String, Model>(configuration.getCacheSize());
    
            openDatabase();
    
            sIsInitialized = true;
    
            Log.v("ActiveAndroid initialized successfully.");
        }

      我们直接开始分析sDatabaseHelper = new DatabaseHelper(configuration);并没有阅读sModelInfo = new ModelInfo(configuration);导致信息的遗漏,因此我们只好倒过头来读ModelInfo这个类。这个失误有点伤,下次再来读:

    Done

  • 相关阅读:
    每日一题 为了工作 2020 0330 第二十八题
    每日一题 为了工作 2020 0329 第二十七题
    每日一题 为了工作 2020 0328 第二十六题
    每日一题 为了工作 2020 0325 第二十五题
    每日一题 为了工作 2020 0326 第二十四题
    学习总结(十四)
    学习总结(十三)
    学习总结(十二)
    学习总结(十一)
    学习总结(十)
  • 原文地址:https://www.cnblogs.com/fishbone-lsy/p/4889958.html
Copyright © 2011-2022 走看看