上一章,我们读完了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

 

posted on 2015-10-18 18:11  Fishbonell  阅读(166)  评论(0编辑  收藏  举报