Android中经常使用到操作XML,其中有一对XmlSerializer和XmlPullParser封装的很好,可是操作起来很复杂,虽然不难,但是感觉做了一点小事却写了一大堆的代码。有点烦,因此封装一下。
其思路为:根据传入的数据,获取字节码后进行反射解析,然后在存储。思路很简单,此demo只写了一个基本的List<T>类型的,其它类型道理与此大同小异,就当这个是抛砖引玉了。
对于一些Model可能有些字段是不需要序列化的,这里可以使用注解来操作
/** * XML操作工具类 * @author chenhao24 * */ public class XMLUtils{ public interface XMLProgressCallback{ void onBefore(List<?> data); void onProgress(int index); void onFinished(); } /** * 解析XML数据 * @param path * @param clazz * @return */ public static List<Object> pullParserData(String path, Class<?> clazz,XMLProgressCallback callback){ if (clazz == null || path == null || TextUtils.isEmpty(path)) { return null; } File destFile = new File(path); if(! destFile.exists()){ return null; } List<Object> resData = null; Map<String, Method> mdatas = new HashMap<String, Method>(); String[] classNames = parseFields(clazz, mdatas, StaticDatas.METHOD_SET); List<Object> data = queryData(destFile, resData, mdatas, classNames); callback.onBefore(data); return data; } /** * 从XML中读取数据 * @param destFile * @param resData * @param mdatas * @param classNames * @return */ private static List<Object> queryData(File destFile, List<Object> resData,Map<String, Method> mdatas, String[] classNames) { XmlPullParser pullParser = Xml.newPullParser(); InputStream inputStream; try { inputStream = new FileInputStream(destFile); pullParser.setInput(inputStream, StaticDatas.UTF8); int eventType = pullParser.getEventType(); Object obj = null; while (eventType != XmlPullParser.END_DOCUMENT) { String tagName = pullParser.getName(); if (eventType == XmlPullParser.START_TAG) { if (tagName.equals(StaticDatas.XML_ROOT)) { resData = new ArrayList<Object>(); eventType = pullParser.next(); continue; } if (tagName.equals(classNames[0])) { obj = Class.forName(classNames[1]).newInstance(); eventType = pullParser.next(); continue; } for (Iterator<Entry<String, Method>> iter = mdatas.entrySet().iterator(); iter.hasNext();) { Entry<String, Method> entry = iter.next(); String key = entry.getKey(); if(key.equals(tagName)){ Method method = entry.getValue(); method.invoke(obj, pullParser.nextText()); } } } if (eventType == XmlPullParser.END_TAG) { if (tagName.equals(classNames[0])) { resData.add(obj); } } eventType = pullParser.next(); } } catch (Exception e) { e.printStackTrace(); } return resData; } /** * 持久化数据到本地xml * @param path * @param data * @throws Exception */ public static void serializerData(String path,List<?> data,XMLProgressCallback callback){ if(data == null || path == null || TextUtils.isEmpty(path) || data.isEmpty()){ return; } callback.onBefore(data); File destFile = new File(path); try { if(destFile.exists()){ destFile.delete(); destFile.createNewFile(); } Map<String, Method> mdatas = new HashMap<String, Method>(); String className = parseFields(data,mdatas,StaticDatas.METHOD_GET)[0]; insertData(mdatas,data,destFile,className,callback); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } callback.onFinished(); } /** * 解析字段和Get方法 * @param clazz * @param mdatas * @return */ private static String[] parseFields(Class<?> clazz,Map<String, Method> mdatas,String methodType) { Field[] fields = clazz.getDeclaredFields(); Method[] methods = clazz.getMethods(); for (Field field : fields) { String fieldName = field.getName().toLowerCase(Locale.ENGLISH); for (Method method : methods) { //转小写 String methodName = method.getName().toLowerCase(Locale.ENGLISH); // 根据 field和get匹配 if (methodName.startsWith(methodType) && methodName.endsWith(fieldName)) { mdatas.put(fieldName, method); } else { continue; } } } String clazzName = clazz.getName(); return new String[]{clazzName.substring(clazzName.lastIndexOf(".") + 1).toLowerCase(Locale.ENGLISH),clazzName}; } /** * 获取字节码并解析出字段和该字段对应的get方法 * @param data * @param mdatas * @return */ private static String[] parseFields(List<?> data,Map<String, Method> mdatas,String methodType) { Class<?> clazz = data.get(0).getClass(); return parseFields(clazz,mdatas,methodType); } /** * 对数据进行解析并存储到xml中 * 这个方法写的不好,解析类和操作XML的代码混合在一起 * 而且还有个 双重循环。暂时先不处理 * @param mdatas * @param data * @param destFile * @param clazzName * @throws Exception */ private static void insertData(Map<String, Method> mdatas,List<?> data,File destFile,String clazzName,XMLProgressCallback callback) throws Exception{ // 此处进行存储 XmlSerializer xmlCreater = Xml.newSerializer(); FileOutputStream outputStream = new FileOutputStream(destFile); xmlCreater.setOutput(outputStream, StaticDatas.UTF8); xmlCreater.startDocument(StaticDatas.UTF8, true); // XML_ROOT 常量 写死 的 根节点 list xmlCreater.startTag(null, StaticDatas.XML_ROOT); for (Object mtmp : data) { // 此处开始循环创建 xmlCreater.startTag(null, clazzName); int index = 0; for (Iterator<Entry<String, Method>> iter = mdatas.entrySet().iterator(); iter.hasNext();) { callback.onProgress(++ index); Entry<String, Method> entry = iter.next(); String key = entry.getKey(); Method method = entry.getValue(); Object obj = method.invoke(mtmp, new Object[]{}); xmlCreater.startTag(null, key); xmlCreater.text(obj.toString()); xmlCreater.endTag(null, key); } // 循环创建结束 xmlCreater.endTag(null, clazzName); } xmlCreater.endTag(null, StaticDatas.XML_ROOT); xmlCreater.endDocument(); xmlCreater.flush(); if(outputStream != null){ outputStream.close(); } xmlCreater = null; } }