在开始使用LitePal时,要求在项目的assets目录下新建一个litepal.xml文件:
<?xml version="1.0" encoding="utf-8"?> <litepal> <dbname value="Questionnaire"/> <version value="1"></version> <list> <mapping class="com.aliao.parser.entity.UserInfo"></mapping> <mapping class="com.aliao.parser.entity.SurveyInfo"></mapping> </list> </litepal>
什么是对象关系映射模型?
因为sqlite数据库是关系型数据库,而编程是面向对象的,为了使用面向对象的方式来操作数据库,所以在关系数据库和实体对象之间做了一个映射,这样在进行数据库操作的时候,我们只需要操作实体对象即可,不需要直接处理sql语句。
在litepal.xml文件的<list>标签里来设置需要进行映射的对象,数据库里的每一张的表都对应一个实体对象类。
一个litepal.xml文件让我们在进行数据库基本信息配置上变得异常方便,那程序是怎么来获取到我们配置后的信息呢?
首先需要通过解析xml文件来获取到数据库名,版本信息,以及需要映射的对象。在Litepal里使用SAXParser来解析xml,那解析后的信息放在哪里呢,是由LitePalAttr该实体类来接收从litepal.xml里读取到的所有属性值。
本来想直接贴源码的,还是立足源码自己手动实现一下好了,勤奋宝宝在咬我,biaji biaji biaji~~~
创建一个LitePalAttr实体类,对应litepal.xml的属性及其set/get方法:
package com.aliao.parser.entity; import java.util.ArrayList; import java.util.List; /** * Created by aliao on 2015/6/4. */ public class LitePalAttr { private static LitePalAttr litePalAttr; //数据库版本号 private int version; //数据库名 private String dbName; //所有在数据库中想要有映射关系的实体类 private List<String> classNames; public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } public String getDbName() { return dbName; } public void setDbName(String dbName) { this.dbName = dbName; } /** * 在sqlite里table_schema表示自动生成的,这里一定要手动添加进去 * table_schema用来查看数据库的元数据,这里的元数据包括表名及表类型 * @return */ public List<String> getClassNames() { if (classNames == null){ classNames = new ArrayList<>(); classNames.add("com.aliao.parser.entity.Table_Schema"); }else if (classNames.isEmpty()){ classNames.add("com.aliao.parser.entity.Table_Schema"); } return classNames; } public void addClassName(String className){ getClassNames().add(className); } /** * 这里用双重检测来实现单例模式 * 整个程序创建一个唯一的litePalAttr对象,可以通过这个对象拿到数据库的基本信息 * @return */ public static LitePalAttr getIntance(){ if (litePalAttr == null){ synchronized (LitePalAttr.class){ if (litePalAttr == null){ litePalAttr = new LitePalAttr(); } } } return litePalAttr; } @Override public String toString() { return "数据库名称:"+dbName+" ,数据库版本"+version; } }
接下来就是如何解析litepal.xml的问题了,源码里郭神使用SAXParser来解析,如何使用SAXParser来解析一个xml文件的知识会单独写篇blog总结一下,这里就不啰嗦直接上吧。
解析litepal.xml需要创建两个类:
LitePalParser:这个类主要的操作就是创建解析器,然后解析文档
LitePalContentHandler(继承DefaultHandler):解析文档的具体实现,开始对文档进行扫描分析,将xml里的属性值保存到LitePalAttr的对应属性里。
创建解析器:
package com.aliao.parser.entity; import java.util.ArrayList; import java.util.List; /** * Created by aliao on 2015/6/4. */ public class LitePalAttr { private static LitePalAttr litePalAttr; //数据库版本号 private int version; //数据库名 private String dbName; //所有在数据库中想要有映射关系的实体类 private List<String> classNames; public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } public String getDbName() { return dbName; } public void setDbName(String dbName) { this.dbName = dbName; } /** * 在sqlite里table_schema表示自动生成的,这里一定要手动添加进去 * table_schema用来查看数据库的元数据,这里的元数据包括表名及表类型 * @return */ public List<String> getClassNames() { if (classNames == null){ classNames = new ArrayList<>(); classNames.add("com.aliao.parser.entity.Table_Schema"); }else if (classNames.isEmpty()){ classNames.add("com.aliao.parser.entity.Table_Schema"); } return classNames; } public void addClassName(String className){ getClassNames().add(className); } /** * 这里用双重检测来实现单例模式 * 整个程序创建一个唯一的litePalAttr对象,可以通过这个对象拿到数据库的基本信息 * @return */ public static LitePalAttr getIntance(){ if (litePalAttr == null){ synchronized (LitePalAttr.class){ if (litePalAttr == null){ litePalAttr = new LitePalAttr(); } } } return litePalAttr; } @Override public String toString() { return "数据库名称:"+dbName+"\n数据库版本:"+version+"\n\n数据库映射对象类名:"; } }
package com.aliao.parser.saxparser; import com.aliao.parser.entity.LitePalAttr; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * Created by aliao on 2015/6/4. */ public class LitePalContentHandler extends DefaultHandler{ private LitePalAttr litePalAttr; @Override public void startDocument() throws SAXException { litePalAttr = LitePalAttr.getIntance(); litePalAttr.getClassNames().clear();//因为litePalAttr是静态的,所以如果再次进行解析要清空之前的数据 } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if ("dbname".equalsIgnoreCase(localName)){ for (int i = 0; i<attributes.getLength(); i++){ if ("value".equalsIgnoreCase(attributes.getLocalName(i))){ litePalAttr.setDbName(attributes.getValue(i).trim()); } } }else if ("version".equalsIgnoreCase(localName)){ for (int i = 0; i<attributes.getLength();i++){ if ("value".equalsIgnoreCase(attributes.getLocalName(i))){ litePalAttr.setVersion(Integer.parseInt(attributes.getValue(i).trim())); } } }else if ("mapping".equalsIgnoreCase(localName)){ for (int i = 0; i<attributes.getLength();i++){ if ("class".equalsIgnoreCase(attributes.getLocalName(i))){ litePalAttr.addClassName(attributes.getValue(i).trim()); } } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { super.endElement(uri, localName, qName); } @Override public void endDocument() throws SAXException { super.endDocument(); } @Override public void characters(char[] ch, int start, int length) throws SAXException { super.characters(ch, start, length); } }
在主程序里启动解析:
package com.aliao.parser.saxparser; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import com.aliao.parser.R; import com.aliao.parser.entity.LitePalAttr; /** * Created by aliao on 2015/6/4. */ public class LitePalParserFragment extends Fragment implements View.OnClickListener { public static final String TAG = LitePalParserFragment.class.getSimpleName(); private TextView mTvResult; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_saxparser_litepal, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); Button btnParse = (Button) view.findViewById(R.id.btn_parse_litepal); btnParse.setOnClickListener(this); mTvResult = (TextView) view.findViewById(R.id.tvSaxParserResult); } @Override public void onClick(View v) { LitePalParser.parseLitePalConfiguration(); showResult(); } private void showResult() { mTvResult.setVisibility(View.VISIBLE); LitePalAttr mLitePalAttr = LitePalAttr.getIntance(); StringBuffer sb = new StringBuffer(mLitePalAttr.toString()); for (String className:mLitePalAttr.getClassNames()){ sb.append("\n\n"+className); } mTvResult.setText("SAXParser解析litepal.xml结果:\n\n"+sb.toString()); } }
运行结果:
先到这吧