add 2018/6/11
以上是LitePal的包结构,来自https://blog.csdn.net/android_app_2012/article/details/78025704
我学习的方式是通过使用LItePal的顺序来的。使用LitePal第一步是在asssets写litepal.xml文件,建表操作是LitePal.getDatabase(),那么可以以LitePal为切入点进行学习。
创建DB的过程:LitePal.getDatabase()
/**
* Get a writable SQLiteDatabase.
*
* @return A writable SQLiteDatabase instance
*/
public static SQLiteDatabase getDatabase() {
synchronized (LitePalSupport.class) {
return Connector.getDatabase();
}
}
可以看到这个方法给LitePalSupport加锁,然后调用Connector.getDatabase(),源码如下:
public static SQLiteDatabase getDatabase() {
return getWritableDatabase();
}
继续,Connector.getWritableDatabase():
public synchronized static SQLiteDatabase getWritableDatabase() {
LitePalOpenHelper litePalHelper = buildConnection();
return litePalHelper.getWritableDatabase();
}
LitePalOpenHelper继承自SQLiteOpenHelper,最后调用的getWritableDatabase(),是原生的方法,接下来将关注点放在Connextor.buildConnextion():
/**
* Build a connection to the database. This progress will analysis the
* litepal.xml file, and will check if the fields in LitePalAttr are valid,
* and it will open a SQLiteOpenHelper to decide to create tables or update
* tables or doing nothing depends on the version attributes.
*
* After all the stuffs above are finished. This method will return a
* LitePalHelper object.Notes this method could throw a lot of exceptions.
*
* @return LitePalHelper object.
*
* @throws org.litepal.exceptions.InvalidAttributesException
*/
private static LitePalOpenHelper buildConnection() {
LitePalAttr litePalAttr = LitePalAttr.getInstance();
litePalAttr.checkSelfValid();
if (mLitePalHelper == null) {
String dbName = litePalAttr.getDbName();
if ("external".equalsIgnoreCase(litePalAttr.getStorage())) {
dbName = LitePalApplication.getContext().getExternalFilesDir("") + "/databases/" + dbName;
} else if (!"internal".equalsIgnoreCase(litePalAttr.getStorage()) && !TextUtils.isEmpty(litePalAttr.getStorage())) {
// internal or empty means internal storage, neither or them means sdcard storage
String dbPath = Environment.getExternalStorageDirectory().getPath() + "/" + litePalAttr.getStorage();
dbPath = dbPath.replace("//", "/");
if (BaseUtility.isClassAndMethodExist("android.support.v4.content.ContextCompat", "checkSelfPermission") &&
ContextCompat.checkSelfPermission(LitePalApplication.getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
throw new DatabaseGenerateException(String.format(DatabaseGenerateException.EXTERNAL_STORAGE_PERMISSION_DENIED, dbPath));
}
File path = new File(dbPath);
if (!path.exists()) {
path.mkdirs();
}
dbName = dbPath + "/" + dbName;
}
mLitePalHelper = new LitePalOpenHelper(dbName, litePalAttr.getVersion());
}
return mLitePalHelper;
}
可以很清楚的看到做了3件事:
(1)获取了LitePalAttr单例;
(2)根据xml中设置的Storage标签创建了保存数据库的文件夹;
(3)创建LitePalOpenHelper并返回。
逻辑比较清晰,(2)不用解释,(1)大致可以推测是解析了xml,将配置都存在了LitePalAttr中,先放过,我们先看(3),也就是LitePalOpenHelper:
@Override
public void onCreate(SQLiteDatabase db) {
Generator.create(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Generator.upgrade(db);
SharedUtil.updateVersion(LitePalAttr.getInstance().getExtraKeyName(), newVersion);
}
构造方法就是调用了父类的构造方法,主要看上面两个方法的实现,可以得知建表和更新表操作都在Generator中实现,并且DB的最新version是在SharedPreferences中存储的。
LitePal的模块化是比较规范的,接下来有两个方向可以走:
1.去LitePalAttr看xml解析
2.去Generator看建表和更新表的逻辑
先1后2,LitePalAttr:
public static LitePalAttr getInstance() {
if (litePalAttr == null) {
synchronized (LitePalAttr.class) {
if (litePalAttr == null) {
litePalAttr = new LitePalAttr();
loadLitePalXMLConfiguration();
}
}
}
return litePalAttr;
}
然后看loadLitePalXMLConfiguration()方法:
private static void loadLitePalXMLConfiguration() {
if (BaseUtility.isLitePalXMLExists()) {
LitePalConfig config = LitePalParser.parseLitePalConfiguration();
litePalAttr.setDbName(config.getDbName());
litePalAttr.setVersion(config.getVersion());
litePalAttr.setClassNames(config.getClassNames());
litePalAttr.setCases(config.getCases());
litePalAttr.setStorage(config.getStorage());
}
}
关键在 LitePalConfig config = LitePalParser.parseLitePalConfiguration(); 这一句,那我们先看一下LitePalConfig的结构:
/**
* The version of database.
*/
private int version;
/**
* The name of database.
*/
private String dbName;
/**
* The case of table names and column names and SQL.
*/
private String cases;
/**
* Define where the .db file should be. Option values: internal external.
*/
private String storage;
/**
* All the model classes that want to map in the database. Each class should
* be given the full name including package name.
*/
private List<String> classNames;
我省略了其中自动生成的getter,setter方法,很显然这是一个单纯的bean,存储了数据库的基本信息。
那么接下来是LitePalParser.parseLitePalConfiguration():
public static LitePalConfig parseLitePalConfiguration() {
if (parser == null) {
parser = new LitePalParser();
}
return parser.usePullParse();
}
到这里基本xml解析都做了什么就比较明确了,LitePalParser中只有3个方法,其中一个是读取assets文件夹的,另外两个分别是Pull解析和SAX解析,没有做什么特别的操作,那么解析xml的代码分析到这里就结束了,接下来回到回到Generator。
先码到这。
update 2018/6/12
Generator这一块在tablemanager包中,继承结构为: