Android使用反射将Cursor转成对象

Android使用反射将Cursor转成对象

直接上代码

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import android.database.Cursor;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

/**
 * 把Cursor中的数据映射成对象帮助类
 * 适合不追求极限性能的场景。因为有反射,性能会有所下降,测试机为V2025,实测查询1000条文档数据,正常查询耗时92ms,使用此帮助类查询耗时102ms。
 * 10000条数据时,普通查询耗时370ms,此帮助类查询耗时416ms
 * @author yuanchao
 * date 2023/2/2
 */
public class CursorHelper {
    /**
     * 缓存类的字段
     */
    private final Map<Class<?>, Map<String, Field>> mClassMap = new WeakHashMap<>();
    
    /**
     * 转换器缓存
     */
    private final Map<Class<?>, ITypeCover> mCoverMap = new WeakHashMap<>();
    
    /**
     * 将cursor中的数据转换成对象集合
     *
     * @param cursor cursor
     * @param tClass 要转换的目标class
     * @param <T>    要转换的对象类型
     * @return 返回对象集合,非空。
     */
    @NonNull
    public <T> List<T> cursorToObjList(Cursor cursor, Class<T> tClass) {
        if (cursor == null || tClass == null) {
            return Collections.emptyList();
        }
        Map<String, Field> fields = mClassMap.get(tClass);
        if (fields == null) {
            fields = new HashMap<>();
            for (Field declaredField : tClass.getDeclaredFields()) {
                DbName annotation = declaredField.getAnnotation(DbName.class);
                String fieldName = declaredField.getName();
                if (annotation != null) {
                    fieldName = annotation.value();
                }
                declaredField.setAccessible(true);
                fields.put(fieldName, declaredField);
                mClassMap.put(tClass, fields);
            }
        }
        List<T> tList = new ArrayList<>();
        while (cursor.moveToNext()) {
            try {
                T t = tClass.newInstance();
                for (Map.Entry<String, Field> stringFieldEntry : fields.entrySet()) {
                    String fieldName = stringFieldEntry.getKey();
                    int index = cursor.getColumnIndex(fieldName);
                    if (index >= 0) {
                        Field field = stringFieldEntry.getValue();
                        setValue(cursor, index, t, field);
                    }
                }
                tList.add(t);
            } catch (IllegalAccessException | InstantiationException e) {
                e.printStackTrace();
            }
        }
        return tList;
    }
    
    /**
     * 将cursor当前位置中的数据转换成对象
     *
     * @param cursor   cursor
     * @param tClass   要转换的目标class
     * @param position 游标位置
     * @param <T>      要转换的对象类型
     * @return 返回对象,可为空。
     */
    @Nullable
    public <T> T cursorToObj(Cursor cursor, Class<T> tClass, int position) {
        if (cursor == null || tClass == null) {
            return null;
        }
        if (position < 0 || position >= cursor.getCount()) {
            return null;
        }
        Map<String, Field> fields = mClassMap.get(tClass);
        if (fields == null) {
            fields = new HashMap<>();
            for (Field declaredField : tClass.getDeclaredFields()) {
                DbName annotation = declaredField.getAnnotation(DbName.class);
                String fieldName = declaredField.getName();
                if (annotation != null) {
                    fieldName = annotation.value();
                }
                declaredField.setAccessible(true);
                fields.put(fieldName, declaredField);
                mClassMap.put(tClass, fields);
            }
        }
        T t = null;
        if (cursor.moveToPosition(position)) {
            try {
                t = tClass.newInstance();
                for (Map.Entry<String, Field> stringFieldEntry : fields.entrySet()) {
                    String fieldName = stringFieldEntry.getKey();
                    int columnIndex = cursor.getColumnIndex(fieldName);
                    if (columnIndex >= 0) {
                        Field field = stringFieldEntry.getValue();
                        setValue(cursor, columnIndex, t, field);
                    }
                }
            } catch (IllegalAccessException | InstantiationException e) {
                e.printStackTrace();
            }
        }
        return t;
    }
    
    private void setValue(@NonNull Cursor cursor, int columnIndex, @NonNull Object obj, Field field) {
        if (field == null) {
            return;
        }
        try {
            Object value = null;
            Class<?> fieldType = field.getType();
            TypeCover typeCover = field.getAnnotation(TypeCover.class);
            ITypeCover iTypeCover;
            if (typeCover != null) {
                Class<? extends ITypeCover> coverClass = typeCover.value();
                try {
                    iTypeCover = mCoverMap.get(coverClass);
                    if (iTypeCover == null) {
                        iTypeCover = coverClass.newInstance();
                        mCoverMap.put(coverClass, iTypeCover);
                    }
                    Object baseValue = getBaseValue(cursor, columnIndex, iTypeCover.inputType());
                    value = iTypeCover.cover(field.getType(), baseValue);
                } catch (InstantiationException e) {
                    e.printStackTrace();
                }
            } else {
                value = getBaseValue(cursor, columnIndex, fieldType);
            }
            if (value != null) {
                field.set(obj, value);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    
    private Object getBaseValue(@NonNull Cursor cursor, int columnIndex, Class<?> fieldType) {
        Object value = null;
        if (fieldType == String.class) {
            value = cursor.getString(columnIndex);
        } else if (fieldType == int.class || fieldType == Integer.class || fieldType == char.class
                || fieldType == Character.class || fieldType == byte.class || fieldType == Byte.class) {
            value = cursor.getInt(columnIndex);
        } else if (fieldType == long.class || fieldType == Long.class) {
            value = cursor.getLong(columnIndex);
        } else if (fieldType == short.class || fieldType == Short.class) {
            value = cursor.getShort(columnIndex);
        } else if (fieldType == float.class || fieldType == Float.class) {
            value = cursor.getFloat(columnIndex);
        } else if (fieldType == double.class || fieldType == Double.class) {
            value = cursor.getDouble(columnIndex);
        } else if (fieldType == boolean.class || fieldType == Boolean.class) {
            value = cursor.getShort(columnIndex) == 1;
        } else if (fieldType == byte[].class) {
            value = cursor.getBlob(columnIndex);
        }
        return value;
    }
    
    /**
     * 数据库字段名称注解
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface DbName {
        String value();
    }
    
    /**
     * 数据转换注解
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface TypeCover {
        Class<? extends ITypeCover> value();
    }
    
    /**
     * 转换器,把数据库读取的原始数据,转换成另一种数据
     * 例如把json转成对象,把byte[]转成图片等
     */
    public interface ITypeCover {
        /**
         * 转换
         *
         * @param targetType 目标类型
         * @param value      原始数据
         * @return 转换后的数据
         */
        Object cover(Class<?> targetType, Object value);
        
        /**
         * 数据库应该读取的数据类型
         *
         * @return 原始数据类型
         */
        Class<?> inputType();
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值