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;
public class CursorHelper {
private final Map<Class<?>, Map<String, Field>> mClassMap = new WeakHashMap<>();
private final Map<Class<?>, ITypeCover> mCoverMap = new WeakHashMap<>();
@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;
}
@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();
}
public interface ITypeCover {
Object cover(Class<?> targetType, Object value);
Class<?> inputType();
}
}