前段时间,项目中引入了xUtils 3(个人不是很喜欢,太大了...),用到了其中的DB模块(orm),以前用过hibernate,所以对这种ORM框架也一点也不陌生。但开发过程中遇到了个问题,就是定义的实体类的某个字段是一个int数组(其实就是权限id数组),这种类型xUtils是没有默认转换器来进行转换的,后来跟了下源码,看到了以下几个转换器,才确定确实是不支持。
再跟了下源码,发现在这些转换器都是在ColumnConverterFactory中的静态代码块中初始并存到Map中,心想可以直接自定义一个ColumnConverter,再修改ColumnConverterFactory源码来实现自定义的字段转换器。但仔细再看了一下ColumnConverterFactory的源码,发现在了xUtils本身就提供了自定义ColumnConverter的入口静态方法:registerColumnConverter(Class columnType, ColumnConverter columnConverter)(想想也是...),代码如下:
public static void registerColumnConverter(Class columnType, ColumnConverter columnConverter) { columnType_columnConverter_map.put(columnType.getName(), columnConverter); } ... private static final ConcurrentHashMap<String, ColumnConverter> columnType_columnConverter_map; static { columnType_columnConverter_map = new ConcurrentHashMap<String, ColumnConverter>(); BooleanColumnConverter booleanColumnConverter = new BooleanColumnConverter(); columnType_columnConverter_map.put(boolean.class.getName(), booleanColumnConverter); columnType_columnConverter_map.put(Boolean.class.getName(), booleanColumnConverter); ByteArrayColumnConverter byteArrayColumnConverter = new ByteArrayColumnConverter(); columnType_columnConverter_map.put(byte[].class.getName(), byteArrayColumnConverter); ByteColumnConverter byteColumnConverter = new ByteColumnConverter(); columnType_columnConverter_map.put(byte.class.getName(), byteColumnConverter); columnType_columnConverter_map.put(Byte.class.getName(), byteColumnConverter);其中:columnType就是你需要自定义的类型,如前面提到的int数组;columnConverter是自定义的字段转换器。中需要在Application创建的时候调用一下该方法就行。
下面来说说怎么自定义字段转换器。
通过上面的xUtils的类图可以发现,xUtils提供了一个转换器的接口ColumnConverter,因些我们只要实现这一接口即可
public interface ColumnConverter<T> { T getFieldValue(final Cursor cursor, int index); Object fieldValue2DbValue(T fieldValue); ColumnDbType getColumnDbType(); }其中:
getFieldValue方法为从数据库中获取数据再将对应的数据库字段值转换成定义的实体对象的字段值(如Sting转换成int[])的方法;
fieldValue2DbValue方法则将实体对象的字段值转换成数据库需要的字段类型的值
getColumnDbType方法是决定泛型T将会转换成怎样的数据库类型进行存储的,ColumnDbType的源码:
public enum ColumnDbType { INTEGER("INTEGER"), REAL("REAL"), TEXT("TEXT"), BLOB("BLOB"); private String value; ColumnDbType(String value) { this.value = value; } @Override public String toString() { return value; } }所以我们要自定义转换器也是非常简单的事情,以下是我将int[]转换成String进行数据库存储的自定义ColumnConverter:
public class IntArrayColumnConverter implements ColumnConverter<int[]> { @Override public int[] getFieldValue(final Cursor cursor, int index) { if (cursor.isNull(index)) { return null; } else { String valueStr = cursor.getString(index); if (TextUtils.isEmpty(valueStr)) { return new int[0]; } else { String[] valueStrs = valueStr.split(","); int[] values = new int[valueStrs.length]; for (int i = 0; i < values.length; i++) { values[i] = Integer.parseInt(valueStrs[i]); } return values; } } } @Override public Object fieldValue2DbValue(int[] fieldValue) { StringBuilder sb = new StringBuilder(); for (int i = 0; i <fieldValue.length; i++) { sb.append(fieldValue[i]); if (i < fieldValue.length - 1) { sb.append(","); } } return sb.toString(); } @Override public ColumnDbType getColumnDbType() { return ColumnDbType.TEXT; } }大家只要将int[]改成自定义的类型,再按自定的要求进行实现即可。
由于在网上换的资料中很少有提及xUtils存储自定义数据库类型的例子,所以就把它记录下来,也提供了一种解决问题的思路:看源码! 大神可忽略...