浅析郭婶儿子

编程入门 行业动态 更新时间:2024-10-08 22:21:20

浅析郭婶<a href=https://www.elefans.com/category/jswz/34/1766160.html style=儿子"/>

浅析郭婶儿子

最近看了郭神的LitePal框架感觉愣牛逼,牛逼之余,也很好奇他是如何实现的,好奇心害死猫啊!跟随大神脚步,看源码.

1.在使用LitePal框架的时候,在项目的assets目录下面新建一个litepal.xml文件,其中的内容包括数据库的名称,版本,以及映射,那它如何去把这些内容映射进去的?

先贴一下litepal.xml代码:

<?xml version="1.0" encoding="utf-8"?>
<litepal><!-- 数据库名 --><dbname value="demo" ></dbname><!-- 数据库版本 --><version value="1" ></version><!-- 映射模型 --><list><mapping class="com.sdufe.thea.guo.model.News" ></mapping></list></litepal>

下面是litepal.xml对应函数中的属性代码:

/** Copyright (C)  Tony Green, Litepal Framework Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      .0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package org.litepal.parser;import java.util.ArrayList;
import java.util.List;import org.litepal.exceptions.InvalidAttributesException;
import org.litepal.util.Const;
import org.litepal.util.SharedUtil;import android.text.TextUtils;/*** The object model for the litepal.xml file. Once database connection happens,* LitePal will try to analysis the litepal.xml, and read all the attribute into* the LitePalAttr model for further usage.* * @author Tony Green* @since 1.0*/
public final class LitePalAttr {/*** Static litePalAttr object.*/private static LitePalAttr litePalAttr;/*** 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;/*** 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;/*** Do not allow new a LitePalAttr object. Makes it a singleton class.*/private LitePalAttr() {}/*** Provide a way to get the object of LitePalAttr class.* * @return the singleton object of LitePalAttr*/public static LitePalAttr getInstance() {if (litePalAttr == null) {synchronized (LitePalAttr.class) {if (litePalAttr == null) {litePalAttr = new LitePalAttr();}}}return litePalAttr;}public int getVersion() {return version;}void setVersion(int version) {this.version = version;}public String getDbName() {return dbName;}void setDbName(String dbName) {this.dbName = dbName;}/*** Get the class name list. Always add table_schema as a value.* * @return The class name list.*/public List<String> getClassNames() {if (classNames == null) {classNames = new ArrayList<String>();classNames.add("org.litepal.model.Table_Schema");} else if (classNames.isEmpty()) {classNames.add("org.litepal.model.Table_Schema");}return classNames;}/*** Add a class name into the current mapping model list.* * @param className*            Full package class name.*/void addClassName(String className) {getClassNames().add(className);}public String getCases() {return cases;}void setCases(String cases) {this.cases = cases;}/*** Before application build the connection with database, check the fields* in LitePalAttr. If all of the fields are passed, the connection will be* continued.If anyone of them doesn't pass, an exception will be thrown.* * @return If all of the fields are passed, return true. If dbname is*         undefined, or version is less than 1, or version is earlier than*         current version, throw InvalidAttributesException* * @throws InvalidAttributesException*/public boolean checkSelfValid() {if (TextUtils.isEmpty(dbName)) {throw new InvalidAttributesException(InvalidAttributesException.DBNAME_IS_EMPTY_OR_NOT_DEFINED);}if (!dbName.endsWith(Const.LitePal.DB_NAME_SUFFIX)) {dbName = dbName + Const.LitePal.DB_NAME_SUFFIX;}if (version < 1) {throw new InvalidAttributesException(InvalidAttributesException.VERSION_OF_DATABASE_LESS_THAN_ONE);}if (version < SharedUtil.getLastVersion()) {throw new InvalidAttributesException(InvalidAttributesException.VERSION_IS_EARLIER_THAN_CURRENT);}if (TextUtils.isEmpty(cases)) {cases = Const.LitePal.CASES_LOWER;} else {if (!cases.equals(Const.LitePal.CASES_UPPER)&& !cases.equals(Const.LitePal.CASES_LOWER)&& !cases.equals(Const.LitePal.CASES_KEEP)) {throw new InvalidAttributesException(cases+ InvalidAttributesException.CASES_VALUE_IS_INVALID);}}return true;}}
这就是郭哥代码中对应xml文件中的属性了,那如何映射进去的呢?它自己应该不能平白无故的就对应上了,继续看源码

解析xml文件中出现了这么一个函数:

/*** Analyze litepal.xml, and store the analyzed result in LitePalParser. Use* DomParse to parse the configuration file as default. SAXParser and* XmlPullParser is also optional, but not visible to developers.*/public static void parseLitePalConfiguration() {if (parser == null) {parser = new LitePalParser();}parser.useSAXParser();}

从函数名上就猜到使用了SAX解析xml,也不能胡乱猜,继续看郭哥的源码, 赶紧去useSAXParser()看看到底是如何实现的

/*** Use SAXParser to parse the litepal.xml file. It will get the parsed* result from LitePalContentHandler and stored in the instance of* LitePalAttr.* * Note while analyzing litepal.xml file, ParseConfigurationFileException* could be thrown. Be careful of writing litepal.xml file, or developer's* application may be crash.*/void useSAXParser() {LitePalContentHandler handler = null;try {SAXParserFactory factory = SAXParserFactory.newInstance();XMLReader xmlReader = factory.newSAXParser().getXMLReader();handler = new LitePalContentHandler();xmlReader.setContentHandler(handler);xmlReader.parse(new InputSource(getConfigInputStream()));return;} catch (NotFoundException e) {throw new ParseConfigurationFileException(ParseConfigurationFileException.CAN_NOT_FIND_LITEPAL_FILE);} catch (SAXException e) {throw new ParseConfigurationFileException(ParseConfigurationFileException.FILE_FORMAT_IS_NOT_CORRECT);} catch (ParserConfigurationException e) {throw new ParseConfigurationFileException(ParseConfigurationFileException.PARSE_CONFIG_FAILED);} catch (IOException e) {throw new ParseConfigurationFileException(ParseConfigurationFileException.IO_EXCEPTION);}}

是的,你没有猜错,上面的就是SAX解析xml的格式了,使用SAX解析xml差不多就是这么个格式,不同的就在那个handler了,当然郭神的代码相当规范,向大神学习,要想知道他是怎么解析litepal.xml还是继续看handler的实现吧!这里只贴主要代码,不能弄得很长,长了就不太好了哈!

/*** Start analysis the litepal.xml file. Set all the parsed value into the* LitePalAttr model.*/@Overridepublic void startElement(String uri, String localName, String qName, Attributes attributes)throws SAXException {if (LitePalParser.NODE_DB_NAME.equalsIgnoreCase(localName)) {for (int i = 0; i < attributes.getLength(); i++) {if (LitePalParser.ATTR_VALUE.equalsIgnoreCase(attributes.getLocalName(i))) {litePalAttr.setDbName(attributes.getValue(i).trim());}}} else if (LitePalParser.NODE_VERSION.equalsIgnoreCase(localName)) {for (int i = 0; i < attributes.getLength(); i++) {if (LitePalParser.ATTR_VALUE.equalsIgnoreCase(attributes.getLocalName(i))) {litePalAttr.setVersion(Integer.parseInt(attributes.getValue(i).trim()));}}} else if (LitePalParser.NODE_MAPPING.equalsIgnoreCase(localName)) {for (int i = 0; i < attributes.getLength(); i++) {if (LitePalParser.ATTR_CLASS.equalsIgnoreCase(attributes.getLocalName(i))) {litePalAttr.addClassName(attributes.getValue(i).trim());}}} else if (LitePalParser.NODE_CASES.equalsIgnoreCase(localName)) {for (int i = 0; i < attributes.getLength(); i++) {if (LitePalParser.ATTR_VALUE.equalsIgnoreCase(attributes.getLocalName(i))) {litePalAttr.setCases(attributes.getValue(i).trim());}}}}
上面的就是handler的解析内容了,根据开始元素解释开始元素,个人猜测,既然是用SAX解析xml,就可以有多个Lite标签,所以我觉得可以使用LitePal框架可以建多个数据库,不过LitePal是继承自SQLite数据库,一般一个app应该不会有很多数据库吧,本来就很小!当然源代码中还有用Pull解析的xml,这里也贴一下代码

/*** Use XmlPullParser to parse the litepal.xml file. It will store the result* in the instance of LitePalAttr.* * Note while analyzing litepal.xml file, ParseConfigurationFileException* could be thrown. Be careful of writing litepal.xml file, or developer's* application may be crash.*/void usePullParse() {try {LitePalAttr litePalAttr = LitePalAttr.getInstance();XmlPullParserFactory factory = XmlPullParserFactory.newInstance();XmlPullParser xmlPullParser = factory.newPullParser();xmlPullParser.setInput(getConfigInputStream(), "UTF-8");int eventType = xmlPullParser.getEventType();while (eventType != XmlPullParser.END_DOCUMENT) {String nodeName = xmlPullParser.getName();switch (eventType) {case XmlPullParser.START_TAG: {if (NODE_DB_NAME.equals(nodeName)) {String dbName = xmlPullParser.getAttributeValue("", ATTR_VALUE);litePalAttr.setDbName(dbName);} else if (NODE_VERSION.equals(nodeName)) {String version = xmlPullParser.getAttributeValue("", ATTR_VALUE);litePalAttr.setVersion(Integer.parseInt(version));} else if (NODE_MAPPING.equals(nodeName)) {String className = xmlPullParser.getAttributeValue("", ATTR_CLASS);litePalAttr.addClassName(className);} else if (NODE_CASES.equals(nodeName)) {String cases = xmlPullParser.getAttributeValue("", ATTR_VALUE);litePalAttr.setCases(cases);}break;}default:break;}eventType = xmlPullParser.next();}} catch (XmlPullParserException e) {throw new ParseConfigurationFileException(ParseConfigurationFileException.FILE_FORMAT_IS_NOT_CORRECT);} catch (IOException e) {throw new ParseConfigurationFileException(ParseConfigurationFileException.IO_EXCEPTION);}}

当然知道了解析方法,知道了属性对应的函数,那他是如何找到的litepal.xml的呢?不急,我们继续看

/*** Iterates all files in the root of assets folder. If find litepal.xml,* open this file and return the input stream. Or throw* ParseConfigurationFileException.* * @return The input stream of litepal.xml.* @throws IOException*/private InputStream getConfigInputStream() throws IOException {AssetManager assetManager = LitePalApplication.getContext().getAssets();String[] fileNames = assetManager.list("");if (fileNames != null && fileNames.length > 0) {for (String fileName : fileNames) {if (Const.LitePal.CONFIGURATION_FILE_NAME.equalsIgnoreCase(fileName)) {return assetManager.open(fileName, AssetManager.ACCESS_BUFFER);}}}throw new ParseConfigurationFileException(ParseConfigurationFileException.CAN_NOT_FIND_LITEPAL_FILE);}

以上就是他找到本地litepal.xml的方法啦,通过getAssets()读到本地的asset里面的文件,那文件名跟Const.LitePal.CONFIGURATION_FILE_NAME对比,相同的话就读到本地文件了,当然我开始也有个疑问,我是否可以随便起个名字呢?这里当然不可以,因为asset可以有很多文件,他不知道要用哪一个,这里郭哥直接写死了,文件名只能叫litepal.xml

public static final String CONFIGURATION_FILE_NAME = "litepal.xml";
看到这,你应该大概连接到郭哥是怎么操作litepal.xml,理一理,首先你使用LitePal框架引进包之后,需要建一个litepal.xml文件,郭哥通过getAsset()读到本地asset文件夹的文件名,通过跟litepal.xml文件名对比,获得里面的内容,在使用SAX解析本地的文件,获得文件中的内容,赋值到LitePalAttr里.

2.在LitePal框架的使用中,需要配置AndroidManifest.xml,在application中加入android:name="org.litepal.LitePalApplication" 那我们不妨从LitePalApplication开始看

public class LitePalApplication extends Application {/*** Global application context.*/private static Context mContext;/*** Construct of LitePalApplication. Initialize application context.*/public LitePalApplication() {mContext = this;}/*** Get the global application context.* * @return Application context.* @throws GlobalException*/public static Context getContext() {if (mContext == null) {throw new GlobalException(GlobalException.APPLICATION_CONTEXT_IS_NULL);}return mContext;}@Overridepublic void onLowMemory() {super.onLowMemory();mContext = getApplicationContext();}}

郭哥这里为了方便用户多次调用context,将context配置到AndroidManifest.xml,并在LitePalApplication中给context赋值,这里需要注意一下,郭哥为了防止context为空,所以在onLowMemory给context赋值.大神不愧是大神,这么机智的保护措施.

今天就到这,欲知后事如何,请听下回解说!








更多推荐

浅析郭婶儿子

本文发布于:2024-02-28 01:46:17,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1767718.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:儿子

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!