LitePal是一款开源的Android数据库框架,采用对象关系映射(ORM)模式,将常用的数据库功能进行封装,不使用SQL语句就可以完成创建表以及表单的CRUD操作,并且很轻量级,几乎零配置。(它将开发中常用的一些数据库功能进行了封装,因此可以在不使用SQL语句的情况下实现对数据库的CRUD操作。)
依然,以MPD数据解析为例,后面可以发现之前建立的Representation正好是LitePal所需要的。
使用LitePal的第一步就是在app/vbuild.gradle文件中添加远程包依赖:
compile 'org.litepal.android:core:1.4.1'
之后在app/src/main目录下新assets文件夹,并添加litepal.xml文件(包含数据库名、版本号、表单映射对象class的路径)
<?xml version="1.0" encoding="UTF-8" ?>
<litepal>
<dbname value= "mpdfile"></dbname>
<version value = "1"></version>
<list>
<mapping class="com.example.litepal.Representation"></mapping>
</list>
</litepal>
编写相应的关系映射对象class(本质是一个简单的JavaBean,定义为Representation.java)
package com.example.litepal;
import org.litepal.crud.DataSupport;
/**
* @Author Fupenzi on 2019/1/7.
* @Blog https://blog.csdn.net/qq_34041083
*/
public class Representation extends DataSupport {
//由litepal管理表单不需要继承DataSupport,但是要对表单进行CRUD操作,必须继承
private int id;
private String item;
private int width;
private int height;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setItem(String item) { this.item = item; }
public void setHeight(int height) {
this.height = height;
}
public void setWidth(int width) {
this.width = width;
}
public String getItem() { return item; }
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
}
在Manifest清单文件中配置 LitePalApplication,此处意味着MainActivity的继承父类不再为默认
<application
android:name="org.litepal.LitePalApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
……
重新编写MainActivity.java
package com.example.litepal;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import org.litepal.LitePal;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.StringReader;
public class MainActivity extends AppCompatActivity{
TextView responseText;//声明一个回应文本显示对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendRequest = (Button) findViewById(R.id.send_request);
responseText = (TextView) findViewById(R.id.response_text);
sendRequest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendRequestWithOkHttp();
LitePal.getDatabase();//创建数据库
}
});
}
public void sendRequestWithOkHttp() {
new Thread(new Runnable() {
@Override
public void run() {
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
// 指定访问的服务器地址是电脑本机
.url("https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd")//MPD请求地址
.build();
Response response = client.newCall(request).execute();//发送请求并获取服务端返回数据
String responseData = response.body().string();//提取返回数据中请求的文件,并转化为字符串
parseXMLWithPull(responseData); //对请求的文件进行解析
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
private void parseXMLWithPull(String xmlData) { //MPD解析方法
//Representation rep = new Representation();//实例化一个Representation对象
String item = null, width = null,height = null;
String line = "";
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); //获得一个XMLPULL工厂类的实例
XmlPullParser xmlPullParser = factory.newPullParser(); //获得一个XML解析器的实例
xmlPullParser.setInput(new StringReader(xmlData));
int eventType = xmlPullParser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
String nodeName = xmlPullParser.getName();
switch (eventType) {// 通过判断事件类型来选择执行不同的代码
// 开始解析某个结点
case XmlPullParser.START_TAG: {
if ("Representation".equals(nodeName)) {//由<Representation开始解析
item = xmlPullParser.getAttributeValue(null, "id");
width = xmlPullParser.getAttributeValue(null, "width");
height = xmlPullParser.getAttributeValue(null, "height");
}
break;
}
// 完成解析某个结点
case XmlPullParser.END_TAG: {
if ("Representation".equals(nodeName)) { //由Representation--/>结束解析
Log.d("Representation", "id is " + item +"; width is "
+ width+"; height is " + height+";");
//在调试窗口logcat打印出属性值
line = line +"ID: "+ item +"; WIDTH: "+ width +"; HEIGHT: "+ height+";\n";
//将已经遍历的属性值连接成一个字符串,并注意换行
Representation rep = new Representation();
//在程序块中初始化对象,称为局部变量,每次循环重新创建并赋值,实现数据的添加
rep.setItem(item);
try{
rep.setWidth(Integer.parseInt(width));
//对getAttributeValue()方法得到的String进行强制类型转换,Integer.parseInt()得到int类型
//必须使用异常捕捉函数,不然无法正常运行!
rep.setHeight(Integer.parseInt(height));
}catch(Exception e){
e.printStackTrace();
}
rep.save();
}
break;
}
default:
break;
}
eventType = xmlPullParser.next();
}
showResponse(line);//将字符串对象传入showResponse()方法,打印在UI的TextView
// Save(line);
} catch (Exception e) {
e.printStackTrace();
}
}
private void showResponse(final String response) {//子线程中不允许进行UI操作,因此利用showResponse()方法切换到主线程更新
runOnUiThread(new Runnable() {
@Override
public void run() {
responseText.setText(response);//创建一个TextView显示传入字符串
}
});
}
}
可以看到与之前使用文件存储和SQLite不一样,在Representation对象中添加了item属性代替之前的id属性,这是由于将id设置为String属性时,在adb中查看数据库创建语句:
即首项id总是默认设为integer、主键和自增,因此将之前的id属性改为item属性。
另外,由于每次使用save()方法之后,如果对象没有被释放,下次添加数据后知识在之前的数据上做了修改而是不是新增。因此,在对Representation对象进行实例化时选择在循环体内部,则完成一次数据添加即释放对象。
在本次的Representation文件中,将width属性和height属性设置为int型,而XML解析的结果是String类型,所以在向数据库写入数据之前必须使用Integer.parseInt(s)方法,如果直接使用Integer.parseInt(s)方法,调试过程不会报错,但是在虚拟机上Run App时将无法创建数据库。查找资料,得知类型强制转换过程中可能会出现异常Exception,因此加入try{…}catch(){…}语句进行异常处理。
在数据库创建成功后可以在FileExplore视窗查看,并使用adb shell进入设备的文件系统查勘表单具体内容