In the previous blog "Build Android ORM Framework Opendroid (a)--orm framework use" believe you already understand the use of opendroid, then from this blog, we formally entered the opendroid source analysis, to create a self-ORM framework!
Before the official start, you need to ensure that you have a copy of the opendroid source code, if you have not yet downloaded opendroid, please go to http://git.oschina.net/qibin/OpenDroid download opendroid source code.
Any database operation starts with the creation of a database, and today we'll look at how Opendroid helped us create the database automatically. Remember how the relationship mapping is configured? In Open-droid.xml, by configuring the mapping node to tell opendroid we need to map the Java bean. So when does the database operation start, and with insert, it calls the Save () method inherited from Opendroid! Before that, we didn't have any database operations, so let's start with the Save () method and see how opendroid created the database.
/** * Insert Data * @return The last inserted id*/public long Save () {try {class<opendroid> klass = (class<opendroid>) getclass (); Contentvalues CV = new Contentvalues () Generatedata (Klass, CV); return Crud.insert (Klass.getsimplename (), CV, Ssqlitedatabase);} catch (Exception e) {e.printstacktrace ();} return-1;}
Line 11th, by calling a static method of the CRUD insert to save the data to the database, insert the last parameter Ssqlitedatabas is our concern, to see its definition:
private static Sqlitedatabase Ssqlitedatabase = Sopenhelper.getwritabledatabase ();
Ssqlitedatabase is returned through the Sopenhelper call Getwriteabledatabase (), I believe everyone here should be very familiar with, and then look at the definition of Sopenhelper:
private static Createdb Sopenhelper = new Createdb ();
Here is a direct new createdb, through the class name we can fully know that Createdb is the key to create a database. Let's take a look at Createdb:
public class Createdb extends Sqliteopenhelper {public createdb () {Super (Droidapplication.scontext, Opendroidhelper.getdbinfobean (). GetName (), NULL, Opendroidhelper.getdbinfobean (). GetVersion (), New Defaultdatabaseerrorhandler ());} @Overridepublic void OnCreate (Sqlitedatabase db) {for (String Sql:OpenDroidHelper.getDBInfoBean (). Getsqls ()) { Db.execsql (SQL);}}}
Here I only intercepted and create the database about the code, you can see Createdb inherited from Sqliteopenhelper, here is certainly familiar, first from the construction method to see, in the construction method directly called the parent class construction method, the first parameter is a context object, This object is in the droidapplication, in fact, is very simple, is called in the OnCreate Getapplicationcontext () for the droidapplication scontext static variable assignment, here does not paste the code, Can be found in the source code, look at the next few parameters, are obtained through the Opendroidhelper.getdbinfobean. Take a look back and find out that OnCreate is also going through the Opendroidhelper.getdbinfobean (). Getsqls () to get the SQL statement that created the table, now let's go to Opendroidhelper to see it.
public class Opendroidhelper {public static final string tag_droid = "Open-droid";p ublic static final String tag_version = "Version";p ublic static final String tag_name = "NAME";p ublic static final String tag_mapping = "MAPPING";p rivate static Dbbean sdbbean;public static Dbbean Getdbinfobean () {if (Sdbbean = = null) {Generatedbinfobean ();} return Sdbbean;} /** * Parse open_droid.xml file under asserts directory, generate Dbinfobean */private static void Generatedbinfobean () {try {Xmlpullparser Pullparser = Xml.newpullparser (); InputStream InputStream = DroidApplication.sContext.getAssets (). Open ("Open_ Droid.xml ");p ullparser.setinput (InputStream," utf-8 "); int type = Pullparser.geteventtype (); String tagName = null;while (type! = xmlpullparser.end_document) {if (type = = Xmlpullparser.start_tag) {tagName = Pullparse R.getname (); if (Tagname.equals (tag_droid)) {Sdbbean = new Dbbean ();} else if (tagname.equals (tag_version)) {//Get version number Sdbbean.setversion (Integer.parseint (Pullparser.getattributevalue ( NULL, "value")));} else if (tagName. Equals (Tag_name)) {//Gets the database name Sdbbean.setname (Pullparser.getattributevalue (NULL, "value");} else if (tagname.equals (tag_mapping)) {//Gets all the build statement statements Sdbbean.addsql (GenerateSQL (Pullparser));}} Type = Pullparser.next ();}} catch (Exception e) {e.printstacktrace ();}} /** * Generate table SQL statement * @param pullparser * @return * @throws classnotfoundexception * @throws xmlpullparserexception * @t Hrows ioexception */private static String GenerateSQL (Xmlpullparser pullparser) throws ClassNotFoundException, Xmlpullparserexception, IOException {//Reflection get classclass<opendroid> Klass = (class<opendroid>) Class.forName (Pullparser.getattributevalue (NULL, "class")); StringBuilder sql = new StringBuilder ("CREATE TABLE");//Gets the class name, Getsimplename gets the class name, GetName () gets the package name + class name Sql.append ( Klass.getsimplename ()). Append ("(");//Automatically create a _idsql.append ("_id Integer primary Key AutoIncrement,");//Get all fields field[ field = Klass.getdeclaredfields (); for (field Field:fields) {//If it is public, it is not a table of fields if (Field.isaccessible ()) { Continue;} Gets the field name String name = Field.getname (), Sql.append (name). Append ("");//Gets the field type class<?> FieldType = Field.gettype (); if (FieldType = = String.class) {//If it is Stringsql.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 ();}}
Well, the code is a little bit long, so let's take a slow look. The first thing to look at is the Getdbinfobean () that we called earlier, which is very simple, which is to return a Dbbean object, but it also calls the Generatedbinfobean () method, which can be seen by means of the method name, which is used to generate Dbbean.
/*** parsing the Open_droid.xml file in the asserts directory, generating dbinfobean*/private static void Generatedbinfobean () {try {Xmlpullparser Pullparser = Xml.newpullparser (); InputStream InputStream = DroidApplication.sContext.getAssets (). Open ("Open_ Droid.xml ");p ullparser.setinput (InputStream," utf-8 "); int type = Pullparser.geteventtype (); String tagName = null;while (type! = xmlpullparser.end_document) {if (type = = Xmlpullparser.start_tag) {tagName = Pullparse R.getname (); if (Tagname.equals (tag_droid)) {Sdbbean = new Dbbean ();} else if (tagname.equals (tag_version)) {//Get version number Sdbbean.setversion (Integer.parseint (Pullparser.getattributevalue ( NULL, "value")));} else if (tagname.equals (tag_name)) {//Gets the database name Sdbbean.setname (Pullparser.getattributevalue (NULL, "value"));} else if (tagname.equals (tag_mapping)) {//Gets all the build statement statements Sdbbean.addsql (GenerateSQL (Pullparser));}} Type = Pullparser.next ();}} catch (Exception e) {e.printstacktrace ();}}
Well, in Generatedbinfobean This method, we are familiar with the Xmlpullparser code, the role is to parse the Open-droid.xml file, get the database name, database version and data table information. Although very long, but all very simple, 20 rows, we get the database version number, and saved to the Dbbean, the same 23 rows get the name of the database, note the 26th line, we want to add the SQL statement in the Dbbean, that add what SQL statement? It must be the SQL statement that built the table. Take a look at the GenerateSQL () method.
/** * Generate table SQL statement * @param pullparser * @return * @throws classnotfoundexception * @throws xmlpullparserexception * @throws IOException */private static String GenerateSQL (Xmlpullparser pullparser) throws ClassNotFoundException, Xmlpullparserexception, IOException {//Reflection get classclass<opendroid> Klass = (class<opendroid>) Class.forName (Pullparser.getattributevalue (NULL, "class")); StringBuilder sql = new StringBuilder ("CREATE TABLE");//Gets the class name, Getsimplename gets the class name, GetName () gets the package name + class name Sql.append ( Klass.getsimplename ()). Append ("(");//Automatically create a _idsql.append ("_id Integer primary Key AutoIncrement,");//Get all fields field[ field = Klass.getdeclaredfields (); for (field Field:fields) {//If it is public, it is not a table of fields if (Field.isaccessible ()) { Continue;} Gets the field name String name = Field.getname (), Sql.append (name). Append ("");//Gets the field type class<?> FieldType = Field.gettype (); if (FieldType = = String.class) {//If it is Stringsql.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 () is full of reflection code, if you are not familiar with the reflection, it is recommended that you first look at the Java reflection, because opendroid in a large number of use of the reflection mechanism,
12 lines, the class that we want to map by reflection, and then the 14~18 line, is the SQL statement that initializes the table, and we can see that opendroid automatically adds a _id field for us, so we don't need to define the bean again when we define it.
21 rows, gets all the fields defined in the class, and iterates through the fields in 22 rows.
14~26 line, you can see that if the field is public, then ignore it, so if you do not want to map a field to the database, it is defined as public.
The 29~30 row is the table name appended to the SQL statement that created the table.
33~44 the type of the field to be appended to the SQL statement that created the table by judging the field type.
The function of the 46 row is to delete the last ","
47 rows, the created SQL statement for the table is completed.
At this point, Opendroid's automated process of creating a database has been analyzed, so let's summarize:
1, the creation of the database we rely on the Android API Sqliteopenhelper.
2, in the sqliteopenhelper of the oncreate to traverse our auto-generated statement and execution of the build table.
3. How do I generate a build statement? The class name and field name of the class are obtained through reflection in Opendroidhelper, and the table statements are pieced together by StringBuilder.
4, in order to facilitate, we in Opendroidhelper will parse out the data name, the database version and the Construction table statement all put in the Dbbean, then we in Createdb class can through the Dbbean convenient to obtain the information of the database.
OK, the automatic creation of the database of the general process is the case, in the next blog, we will also introduce opendroid CRUD operations and its database upgrade mechanism.
Opendroid's Open source address: http://git.oschina.net/qibin/OpenDroid
Build Android ORM Framework Opendroid (ii)--CREATE database automatically