Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 打造android ORM框架opendroid(二)——自動創建數據庫

打造android ORM框架opendroid(二)——自動創建數據庫

編輯:關於Android編程

在上一篇博客《打造android ORM框架opendroid(一)——ORM框架的使用》中相信你已經了解了opendroid的使用,那麼從這篇博客開始,我們正式進入opendroid的源碼分析,打造一款自己的ORM框架!

在正式開始之前,你需要保證手裡有一份opendroid的源碼,如果還沒下載opendroid,請到http://git.oschina.net/qibin/OpenDroid 下載opendroid的源碼。

 

任何數據庫操作都是從創建數據庫開始的,今天我們就來看看opendroid是怎麼幫我們自動創建數據庫的。 還記得關系映射怎麼配置嗎? 在open-droid.xml中,通過配置mapping節點來告訴opendroid我們需要映射的java bean。那麼數據庫操作是從何時開始的呢, 拿insert來說,就是調用了從OpenDroid繼承而來的save()方法!在這之前,我們沒有任何數據庫方面的操作,那麼我們就從save()方法開始,看看opendroid是怎麼創建數據庫的。

 

/**
 * 插入數據
 * @return 最後插入的id
*/
public long save() {
	try {
		Class klass = (Class) getClass();
		ContentValues cv = new ContentValues();
		generateData(klass, cv);
			
		return CRUD.insert(klass.getSimpleName(), cv, sSqliteDatabase);
	} catch (Exception e) {
		e.printStackTrace();
	}
	return -1;
}

第11行,通過調用了CRUD的一個靜態方法insert將數據保存到數據庫中,insert的最後一個參數sSqliteDatabas是我們關心的,來看看它的定義:

 

 

private static SQLiteDatabase sSqliteDatabase = sOpenHelper.getWritableDatabase();

sSqliteDatabase是通過sOpenHelper調用getWriteableDatabase()返回的,相信這裡大家應該非常熟悉了,再來看看sOpenHelper的定義:

 

 

private static CreateDB sOpenHelper = new CreateDB();

在這裡直接new了一個CreateDB,通過類名我們完全可以知道CreateDB就是創建數據庫的關鍵。來看看CreateDB吧:

 

 

public class CreateDB extends SQLiteOpenHelper {
	
	public CreateDB() {
		super(DroidApplication.sContext, OpenDroidHelper.getDBInfoBean().getName(),
				null, OpenDroidHelper.getDBInfoBean().getVersion(), new DefaultDatabaseErrorHandler());
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		for(String sql : OpenDroidHelper.getDBInfoBean().getSqls()) {
			db.execSQL(sql);
		}
	}
}

這裡我只截取了和創建數據庫有關的代碼, 可以看到CreateDB繼承自SQLiteOpenHelper,這裡大家肯定也很熟悉,先從構造方法開始看, 在構造方法中直接調用了父類的構造方法,第一個參數是一個context對象,這個對象是在DroidApplication中,其實很簡單,就是在onCreate中調用getApplicationContext()為DroidApplication中的sContext靜態變量賦值,這裡就不貼代碼了,可以在源碼中找到,在看看接下來幾個參數,都是通過OpenDroidHelper.getDBInfoBean獲取的。再往後看看發現onCreate中也是通過遍歷OpenDroidHelper.getDBInfoBean().getSqls()來獲取創建表的sql語句,那麼現在我們就去OpenDroidHelper看看吧。

 

 

public class OpenDroidHelper {
	public static final String TAG_DROID = open-droid;
	public static final String TAG_VERSION = version;
	public static final String TAG_NAME = name;
	public static final String TAG_MAPPING = mapping;
	
	private static DBBean sDBBean;
	
	public static DBBean getDBInfoBean() {
		if(sDBBean == null) {
			generateDBInfoBean();
		}
		
		return sDBBean;
	}
	
	/**
	 * 解析Asserts目錄下的open_droid.xml文件,生成DBInfoBean
	 */
 	private static void generateDBInfoBean() {
		try {
			XmlPullParser pullParser = Xml.newPullParser();
			InputStream inputStream = DroidApplication.sContext.getAssets().open(open_droid.xml);
			pullParser.setInput(inputStream, utf-8);
			
			int type = pullParser.getEventType();
			String tagName = null;
			
			while(type != XmlPullParser.END_DOCUMENT) {
				if(type == XmlPullParser.START_TAG) {
					tagName = pullParser.getName();
					if(tagName.equals(TAG_DROID)) {
						sDBBean = new DBBean();
					}else if(tagName.equals(TAG_VERSION)) {
						// 獲取版本號
						sDBBean.setVersion(Integer.parseInt(pullParser.getAttributeValue(null, value)));
					}else if(tagName.equals(TAG_NAME)) {
						// 獲取數據庫名
						sDBBean.setName(pullParser.getAttributeValue(null, value));
					}else if(tagName.equals(TAG_MAPPING)) {
						// 獲取所有建表語句
						sDBBean.addSql(generateSql(pullParser));
					}
				}
				type = pullParser.next();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

 	/**
 	 * 生成建表sql語句
 	 * @param pullParser
 	 * @return
 	 * @throws ClassNotFoundException
 	 * @throws XmlPullParserException
 	 * @throws IOException
 	 */
	private static String generateSql(XmlPullParser pullParser)
			throws ClassNotFoundException, XmlPullParserException, IOException {
		// 反射獲取class
		Class klass = (Class) Class.forName(pullParser.getAttributeValue(null, class));
		
		StringBuilder sql = new StringBuilder(create table );
		// 獲取類名, getSimpleName獲取類名, getName()獲取包名+類名
		sql.append(klass.getSimpleName()).append(();
		// 自動創建一個_id
		sql.append(_id integer primary key autoincrement,);
		
		// 獲取所有的字段
		Field[] fields = klass.getDeclaredFields();
		for(Field field : fields) {
			// 如果是public的, 則表示不是一個表的字段
			if(field.isAccessible()) {
				continue;
			}
			
			// 獲取字段名
			String name = field.getName();
			sql.append(name).append( );
			
			// 獲取字段類型
			Class fieldType = field.getType();
			if(fieldType == String.class) {  // 如果是String
				sql.append(text,);
			}else if(fieldType == Integer.class || fieldType == int.class) {
				sql.append(integer,);
			}else if(fieldType == Long.class || fieldType == long.class){
				sql.append(integer,);
			}else if(fieldType == Boolean.class || fieldType == boolean.class) {
				sql.append(boolean,);
			}else if(fieldType == Float.class || fieldType == float.class) {
				sql.append(float,);
			}
		}
		sql.replace(sql.length() - 1, sql.length(), );
		sql.append(););
		
		return sql.toString();
	}
}

額,代碼有點小長, 我們慢慢來看。首先來看看我們之前調用的getDBInfoBean(),這個方法很簡單,就是返回了一個DBBean對象,不過,它還調用了generateDBInfoBean()方法,通過方法名可以看出,它的作用是生成DBBean的。

 

 

/**
* 解析Asserts目錄下的open_droid.xml文件,生成DBInfoBean
*/
private static void generateDBInfoBean() {
	try {
		XmlPullParser pullParser = Xml.newPullParser();
		InputStream inputStream = DroidApplication.sContext.getAssets().open(open_droid.xml);
		pullParser.setInput(inputStream, utf-8);
			
		int type = pullParser.getEventType();
		String tagName = null;
			
		while(type != XmlPullParser.END_DOCUMENT) {
			if(type == XmlPullParser.START_TAG) {
				tagName = pullParser.getName();
				if(tagName.equals(TAG_DROID)) {
					sDBBean = new DBBean();
				}else if(tagName.equals(TAG_VERSION)) {
					// 獲取版本號
					sDBBean.setVersion(Integer.parseInt(pullParser.getAttributeValue(null, value)));
				}else if(tagName.equals(TAG_NAME)) {
					// 獲取數據庫名
					sDBBean.setName(pullParser.getAttributeValue(null, value));
				}else if(tagName.equals(TAG_MAPPING)) {
					// 獲取所有建表語句
					sDBBean.addSql(generateSql(pullParser));
				}
			}
			type = pullParser.next();
		}
	} catch (Exception e) {
		e.printStackTrace();
	}
}

 

恩,在generateDBInfoBean這個方法中,都是我們熟悉的XMLPullParser的代碼,作用就是去解析open-droid.xml文件,獲取數據庫名稱、數據庫版本和數據表的信息。雖然很長,但是都很簡單,20行,我們獲取了數據庫的版本號,並保存到了DBBean中,同樣的23行獲取了數據庫的名稱,注意第26行,我們想DBBean中添加的sql語句,那添加的什麼sql語句呢? 肯定是建表的sql語句了。來看看generateSql()方法。

 

 

/**
 * 生成建表sql語句
 * @param pullParser
 * @return
 * @throws ClassNotFoundException
 * @throws XmlPullParserException
 * @throws IOException
 */
private static String generateSql(XmlPullParser pullParser)
		throws ClassNotFoundException, XmlPullParserException, IOException {
	// 反射獲取class
	Class klass = (Class) Class.forName(pullParser.getAttributeValue(null, class));
		
	StringBuilder sql = new StringBuilder(create table );
	// 獲取類名, getSimpleName獲取類名, getName()獲取包名+類名
	sql.append(klass.getSimpleName()).append(();
	// 自動創建一個_id
	sql.append(_id integer primary key autoincrement,);
		
	// 獲取所有的字段
	Field[] fields = klass.getDeclaredFields();
	for(Field field : fields) {
		// 如果是public的, 則表示不是一個表的字段
		if(field.isAccessible()) {
			continue;
		}
			
		// 獲取字段名
		String name = field.getName();
		sql.append(name).append( );
			
		// 獲取字段類型
		Class fieldType = field.getType();
		if(fieldType == String.class) {  // 如果是String
			sql.append(text,);
		}else if(fieldType == Integer.class || fieldType == int.class) {
			sql.append(integer,);
		}else if(fieldType == Long.class || fieldType == long.class){
			sql.append(integer,);
		}else if(fieldType == Boolean.class || fieldType == boolean.class) {
			sql.append(boolean,);
		}else if(fieldType == Float.class || fieldType == float.class) {
			sql.append(float,);
		}
	}
	sql.replace(sql.length() - 1, sql.length(), );
	sql.append(););
		
	return sql.toString();
}

generateSql()裡面全是反射的代碼,如果你對反射還不熟悉,建議你先去看看java反射,因為opendroid中大量使用了反射機制,

 

12行,通過反射獲取我們要映射的class,然後14~18行,是初始化創建表的sql語句,並且可以看到opendroid會自動為我們添加一個_id字段,所以在定義bean的時候,我們不需要再次定義了。

21行,獲取了這個類中定義的所有字段,並在22行循環遍歷這些字段。

14~26行,可以看到,如果字段是public的,那就忽略它,所以如果你不想把某個字段映射到數據庫中,就定義成public的。

29~30行,是向創建表的sql語句中追加表名。

33~44行,通過判斷這個字段類型,來向創建表的sql語句中追加該字段的類型。

46行的作用是刪除最後一個的“,”

47行,就完成了該表的創建sql語句。

 

至此,opendroid的自動創建數據庫的流程我們就分析完了,現在來總結一下:

1、數據庫的創建我們借助了android API的SQLiteOpenHelper。

2、在SQLiteOpenHelper的onCreate中遍歷我們自動生成的建表語句並執行。

3、如何生成建表語句? 在OpenDroidHelper中通過反射獲取類的類名和字段名,並通過StringBuilder來拼湊建表語句。

4、為了方便,我們在OpenDroidHelper中將解析出來的數據名、數據庫版本和建表語句都放到了DBBean中,那麼我們在CreateDB類中就可以通過DBBean方便的獲取數據庫的信息了。

 

ok,數據庫的自動創建大體流程就是這樣,在接下來的博客中,我們還會去一一介紹opendroid的CRUD操作和它的數據庫升級機制。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved