LitePal + Gson + Volley的ORM框架尝试

ORM理解

面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。

应用场景

首先提出这个解决方案是项目所需,先说一下,我们现在做的项目的应用场景。

该项目是一款点餐pad应用,需求是商户的餐桌数据和菜单数据,更新频率不高,而且餐厅上百道菜和桌子数据比较多,在服务器数据库中涉及到许多的关联表,对应表中要有所有商户菜单,倘若每次进入都从服务器加载菜单数据,服务器将会频繁查询无用的信息,对服务器也是徒增压力。基于此,本地缓存方案是必须的,接下来就是如何建立一套可行的本地数据库缓存方案。思路是在本地建立和服务器一样的表,但是Sqlite要实现同样的Mysql服务器表也是有很多问题,多表关联(一对一,一对多,多对多)这些的实现,以我自己之前维护整理的DBhelper,来实现是很大的工作量ps(其实就是搞不定O(∩_∩)O~),最终选择了sqlite的orm框架--“LitePal”,网络通信一直是用的Volley,数据格式是json,所以我一直用gson解析。

流程梳理

那么思路就很明确了,服务器接口从数据库查询菜单-->Volley通信-->gson根据接口文档解析生成对应的实体类-->业务逻辑实体类操作转化为LitePal数据库表对应对象保存数据-->业务逻辑实体类读取本地数据库菜单-->点菜时加载显示。菜单更新的话应用每次启动后,向服务器查询,本店的菜品最后一次更新时间,与本地保存的更新

时间对比,如果有变化,则后台更新本地数据库缓存。



要点处理

Volley,Gson,Litepal要一起在业务逻辑实体类中处理相关问题,有2点是很重要的

1.接口文档解析实体类:

要生成这个类,首先我们需要根据对应接口,生成一个实体类,当然前提是接口返回的是json串,xml的话,我们这边项目暂时没有用到,所以我没有处理进来。对于这种情况,我这边是直接自定义了一个泛型实体类ResultMapRequest<T> extends Request<T>,对Volley有所了解的话,都知道Volley的相关用法,可以自定义请求请求,并把对于处理封装进去。StringRequest、JsonRequest、ImageRequest等。其中StringRequest用于请求一条普通的文本数据,JsonRequest(JsonObjectRequest、JsonArrayRequest)用于请求一条JSON格式的数据,ImageRequest则是用于请求网络上的一张图片。XMLRequest解析处理服务器返回为xml文件的。他们全部都是继承自Request<T>,而我也是在其中做了一些处理,使其能够兼容Gson,解析处理复杂数据,包括泛型,集合的复杂组合。只要传入对应数据集的Type即可。

package com.asiainfo.orderdishes.http.volley;

import android.util.Log;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;
import com.google.gson.Gson;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;

/**
 * @author gjr
 * 直接将服务器返回内容,转换为对应实体类抛出
 * @param <T>对应接口文档建立的实体类
 */
public class ResultMapRequest<T> extends Request<T> {

    private final Listener<T> mListener;

    private Gson mGson;

    private Type modelClass;

    public ResultMapRequest(int method, String url, Type model, Listener<T> listener,
                            ErrorListener errorListener) {
        super(method, url, errorListener);
        mGson = new Gson();
        modelClass = model;
        mListener = listener;
    }

    public ResultMapRequest(String url, Type model, Listener<T> listener,
                            ErrorListener errorListener) {
        this(Method.GET, url, model, listener, errorListener);
    }

    @Override
    protected Response<T> parseNetworkResponse(NetworkResponse response) {
        try {
            String jsonString = new String(response.data,
                    HttpHeaderParser.parseCharset(response.headers));
            Log.d("VolleyLogTag", "result : " + jsonString);
            //关键在此处,将服务器内容解析为String字符串,之后再根据对应接口文档生成的实体类的modelClass,生成对应对象
            T result = mGson.fromJson(jsonString, modelClass);
            return Response.success(result,
                    HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        }
    }

    @Override
    protected void deliverResponse(T response) {
        mListener.onResponse(response);
    }
}

那么在新建请求的时候就可以如下面这样调用:

 /**
     * 获取当前商家的所有菜品信息,并且本地缓存
     */
    public void VolleyQueryAllDishes() {
        String param = "/appController/queryAllDishesInfoByMerchantId.do?childMerchantId=" + baseApp.getLoginInfo().getChildMerchantId();
        Type type = new TypeToken<ResultMap<queryAllDishesByMerchantIdData>>() {
        }.getType();
        Log.i("Volley", "url:" + Constants.address + param);
        ResultMapRequest<ResultMap<queryAllDishesByMerchantIdData>> resultMapRequest = new ResultMapRequest<ResultMap<queryAllDishesByMerchantIdData>>(
                Constants.address + param,
                type,
                new Response.Listener<ResultMap<queryAllDishesByMerchantIdData>>() {
                    @Override
                    public void onResponse(
                            ResultMap<queryAllDishesByMerchantIdData> response) {
                        switch (Integer.valueOf(response.getErrcode())) {
                            case 0:
                                response.getData().getDishes();
                                BackLogin updateDishesData = new BackLogin();
                                updateDishesData.setType(2);
                                updateDishesData.setDbEntity(dbEntity);
                                updateDishesData.setDishes(response.getData().getDishes());
                                updateDishesData.setInfo(response.getData().getInfo());
                                EventBus.getDefault().post(updateDishesData);
                                baseApp.setLoadDishes(false);
                                break;
                            default:
                                showShortTip(response.getMsg() + "!");
                                dismissLoadingDialog();
                                break;
                        }
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e(VolleyLogTag,
                        "VolleyError:" + error.getMessage(), error);
                dismissLoadingDialog();
                showShortTip("网络或服务器异常,自动更新菜单失败!");
            }
        });
        requestQueue.add(resultMapRequest);
        resultMapRequest.setRetryPolicy(new DefaultRetryPolicy(10 * 1000, 1,
                1.0f));
    }
其中的ResultMap<queryAllDishesByMerchantIdData>就是根据queryAllDishesInfoByMerchantId.do接口的接口文档建立的实体类,由于我们接口返回数据最外层是固定的,errcode错误码,msg提示信息,data请求查询成功则返回 queryAllDishesByMerchantIdData,否则返回空

package com.asiainfo.orderdishes.entity.volley;

/**
 * ClassName: ResultMap 网络响应实体类模板
 * date:      2015年3月28日 下午15:36
 *
 * @author gjr
 * @param <T> 不同响应返回不同内容
 */
public class ResultMap<T> {

    private String errcode;
    private String msg;
    private T data;

    public void setErrcode(String errcode) {
        this.errcode = errcode;
    }

    public String getErrcode() {
        return this.errcode;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return this.msg;
    }

    public void setError(Errors error) {
        this.errcode = error.getCode();
        this.msg = error.getMsg();
    }


    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
至此,第一步完成,从服务器获取数据,通过Volley+Gson的结合,接口文档对应的实体类。

注意:如果开发过程中,接口文档有变,要对应修改实体类,否则数据解析必然抛异常。上面返回成功后通过EventBus向后台线程发送数据,更新本地数据库。
2.建立本地数据库表,利用LitePal来实现对象映射,首先是将服务器数据对象进行分割,将实体对象内不断分割,分离出最小对象,从最小对象开始对应关联关系,确认是一对一,还是一对多,还是多对多。需要使用的时候在从数据库中条件查询对应数据。这部分代码有很多是业务逻辑相关的,比较多,所以这里就不贴了。



 






  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值