解析数据帧 android蓝牙数据帧解析 物联网数据帧解析2.0

请先参阅我的上篇文章:解析数据帧 android蓝牙数据帧解析 物联网数据帧解析
本篇文章主要是针对数据帧解析而做的小工具,.本篇可以说是2.0版
主要解决一个问题:把写死的截取位置变成动态获取的位置,能够做到即使修改协议帧也能少改代码,快速更改。
例如
原来写String subdata = data.substring(2,4)
    @Field(value=ORI,location=1)
现在String subdata;
本次升级:
1:优化代码,去除冗余
2:属性值的解析类型,使用注解,名称为value的值,取消原来属性的默认值
3:使用抽象方法返回值,替代原来主动给Pattern 和 ori_data赋值

有了以上的优化,编写解析的bean会更清晰明了.

使用方法如下:

package com.gprs.blue.bean.frame.receive;

import android.support.annotation.StringDef;


public class TestBean extends BaseHarvesterBean<TestBean> {

    @FieldMeta1(location = 2,value = ORI)
    public String data1;
    @FieldMeta1(location = 6,value = BCD+REVERSE)
    public String data2;
    @FieldMeta1(location = 3,value = FLOAT1+REVERSE)
    public float data3;
    @FieldMeta1(location = 4,value = FLOAT1)
    public float data4;
    @FieldMeta1(location = 5,value = REVERSE+FLOAT2)
    public int data5;
  
    @Override
    public String getPattern() {
        return "111122334455557788999999";
    }

    @Override
    public TestBean mappingData() {
        return TestBean.this;
    }

    public TestBean(String data) {
	super(data)
    }
 
    public String toStrings() {
        return "TestBean{" +
                "data1='" + data1 + '\'' +
                ", data2='" + data2 +
                ", data3=" + data3 +
                ", data4=" + data4 +
                ", data5=" + data5 +
                '}';
    }
    public static void main(String[] args) {
        System.out.println(new TestBean("0e0a0b0c0d01020304050607").toStrings(ONE));
    }

}

打印结果如下


核心的BaseHarvesterBeanbean

package com.xt.blueatuo.bean.parse;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 解析数据帧的通用类
 *1 如果只需要2个数据可以只定义2个变量
 *2 子类在java中反射的元素是无排序到,但是在android中按照首字母排序,在子类location中需要指定顺序
 */
public abstract class BaseHarvesterBean<T extends BaseHarvesterBean<T>> {
    public boolean isParseError = true;
    /**
     * 要原始的字符串
     */
    public final String ORI = "ORI";
    /**
     * 要反转后的原始的字符串
     */
    public final String REVERSE = "REVERSE";

    public final String BCD = "BCD";
    /**
     * 保留小数 1:1位小数 2:两位小数...
     */
    public final String FLOAT1 = "FLOAT1";
    public final String FLOAT2 = "FLOAT2";
    public final String FLOAT3 = "FLOAT3";
    public final String FLOAT4 = "FLOAT4";
    /**
     * 待解析的原始数据
     */
    public String ori_data;
    /**
     * 解析规则的正则
     */
    public final String regex = "(.)\\1+";

    /**
     * 解析模版,长度和 ori_data 相等
     * example:aabbccccddddMMMM  or  1111223333445566(建议写数字,方便查找)
     */
    public String data_pattern;
    private final T subbean;


    /**
     * 返回data_pattern需要的值
     */
    public abstract String getPattern();

    /**
     * 返回子类自己
     */
    public abstract T mappingData();

    public BaseHarvesterBean(String data) {
        this.ori_data = data;
        this.data_pattern = getPattern();
        subbean = mappingData();
        mappingData(subbean);
    }

    /**
     * 构造函数调完后,可以再次解析数据
     * @param data
     */
    public void parseData(String data) {
        ori_data = data;
        mappingData(subbean);
    }

    /**
     * 映射模板
     * @param bean 待解析的bean
     */
    public void mappingData(T bean) {
        //校验模板和待解析数据是否为空 ,校验数据长度和模板长度是否相等
        if (ori_data == null || ori_data.length() == 0 ||
                data_pattern == null || data_pattern.length() == 0 ||
                ori_data.length() < data_pattern.length())
            return;
        //计算下标,并存储到tempLocation
        ArrayList<Integer> tempLocation = new ArrayList<>();
        tempLocation.add(0);
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(data_pattern);
        while (matcher.find()) {
            String group = matcher.group(0);
            tempLocation.add(tempLocation.get(tempLocation.size() - 1) + group.length());
        }
        fillData(tempLocation, bean);
    }

    /**
     * 数据赋值
     * @param location 模板对应的下标集合
     * @param bean     待赋值的bean
     */
    public void fillData(ArrayList<Integer> location, T bean) {
        try {
            Class<? extends BaseHarvesterBean> aClass = bean.getClass();
            Field[] fields = aClass.getDeclaredFields();
            List<Field> list = new ArrayList<>();
            for (Field field:fields) {
                if (field.getAnnotation(FieldMeta.class) != null)
                    list.add(field);
            }
            Collections.sort(list, new Comparator<Field>() {
                @Override
                public int compare(Field lhs, Field rhs) {
                    return lhs.getAnnotation(FieldMeta.class).location()-rhs.getAnnotation(FieldMeta.class).location();
                }
            });
            for (int i = 0; i < list.size(); i++) {
//                // 获取属性注解的值
                String anno_value = list.get(i).getAnnotation(FieldMeta.class).value();
//                //获取属性类型
                String type = list.get(i).getGenericType().toString();
//                //可访问私有变量
                list.get(i).setAccessible(true);
//                //截取pattern后的值
                String sub_data = ori_data.substring(location.get(i), location.get(i + 1));
//
                if (type.contains("String")) {//定义的类型为String
                    if (ORI.equals(anno_value) || BCD.equals(anno_value)) {//原始数据
                        list.get(i).set(bean, sub_data);
                    } else if (anno_value.length() ==10 && anno_value.contains(REVERSE)) {//反转的原始数据
                        list.get(i).set(bean, reverseData(sub_data));
                    }
                } else if (type.contains("float")) {//定义的类型为float
                    if (anno_value.contains(REVERSE))
                        sub_data = reverseData(sub_data);
                    int temp = Integer.parseInt(sub_data, anno_value.contains(BCD)?10:16);
                    float f = 0f;
                    if (anno_value.contains("1")) {
                        f = Float.parseFloat(plusDot(temp, 1));
                    } else if (anno_value.contains("2")) {
                        f = Float.parseFloat(plusDot(temp, 2));
                    } else if (anno_value.contains("3")) {
                        f = Float.parseFloat(plusDot(temp, 3));
                    } else if (anno_value.contains("4")) {
                        f = Float.parseFloat(plusDot(temp, 4));
                    }
                        list.get(i).set(bean, f);
                } else if (type.contains("int")) {
                    if (anno_value.contains(REVERSE))
                        sub_data = reverseData(sub_data);
                    int temp = Integer.parseInt(sub_data, anno_value.contains(BCD)?10:16);
                    list.get(i).set(bean, temp);
                 }
            }
            isParseError = false;
        } catch (Exception e) {
            isParseError = true;
            e.printStackTrace();
        }
    }

    /**
     * 高低位转换的工具 地址 反转
     *
     * @param data
     * @return
     */
    public static String reverseData(String data) {
        int length = data.length() / 2;
        String result = "";
        for (int i = 0; i < length; i++) {
            result += data.substring(data.length() - 2, data.length());
            data = data.substring(0, data.length() - 2);
        }
        return result;
    }

    /**
     * 给数据加小数点精确
     */
    public static String plusDot(int data, int mod) {
        String daString = String.valueOf(data);
        if (daString.length() <= mod) {
            int len = daString.length();
            for (int i = 0; i <= mod - len; i++)
                daString = "0" + daString;
        }
        String begin = daString.substring(0, daString.length() - mod);
        String end = daString.substring(daString.length() - mod,
                daString.length());
        return begin + "." + end;
    }

    /**
     * 是否可以转换为10进制
     * @return true:可以转换
     */
    public boolean isParseAble(String data) {
        return data.matches("\\d+");
    }


    /**
     * 给数据加小数点精确
     */
    public static String plusDot(String data, int mod, boolean needReverse, boolean isHex) {
        long val = Long.parseLong(data, isHex ? 16 : 10);
        if (needReverse) {
            val = Long.parseLong(reverseData(data), isHex ? 16 : 10);
        }
        String daString = String.valueOf(val);
        if (daString.length() <= mod) {
            int len = daString.length();
            for (int i = 0; i <= mod - len; i++)
                daString = "0" + daString;
        }
        String begin = daString.substring(0, daString.length() - mod);
        String end = daString.substring(daString.length() - mod,
                daString.length());
        return begin + "." + end;
    }

}



提供注解的类

package com.xt.blueatuo.bean.parse;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by admin on 2018/3/1.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface FieldMeta {
    /**
     * 排序信息
     * @return
     */
    int location();

    /**
     * 值为BaseHarvesterBean 中定义到常量
     * @return
     */
    String value() default "";
}

本篇文字写的过于简单,请先看上篇文字。如果你有更好的办法,欢迎一起来次牛逼。




展开阅读全文

没有更多推荐了,返回首页