11月下旬已经走了一大半了,因为本月事情较多,还未来得及记录。这两天整理了一下过去一个月不完全懂的东西,分为两部分杂记,此为第一篇。
《11月杂记(一)——String拼接,Json读写,Xml读写,Hashmap使用,File存储》
《11月杂记(二)——SVG解析,RecyclerView删除列表,List统计+去重,RGB与HSB互转,获取图片像素RGB与图片主颜色》
1.String拼接与截取
1)字符串拼接
int r = rgb[0];
int g = rgb[1];
int b = rgb[2];
// rgb转换
int colorInfo = Color.rgb(r, g, b);
String colorRgb = ColorUtils.int2RgbString(colorInfo); // Blankj工具类,转换得#7d0331
StringBuffer fillBuffer = new StringBuffer("fill: "); // 拼接 fill:
String colorStyleInfo = String.valueOf(fillBuffer.append(colorRgb)); //结果为fill: #7d0331
2)字符串截取
① 截取某特定字符为界的字符
// "fill: #876d71"
String styleValue = xmlPullParser.getAttributeValue(0);
// 以数组的形式进行解析
String[] strs = styleValue.split(" ");
String strName = strs[0]; // fill:
String strValue = strs[1]; // #876d71
// "663_472_22"
String idValue = xmlPullParser.getAttributeValue(2);
String[] strPos = idValue.split("_");
String positionX = strPos[0]; // 663
String positionY = strPos[1]; // 472
String testSize = strPos[2]; // 22
② 截取某特定位置的字符
//截取#之前的字符串
String str = "sdfs#d";
String s1 = str.substring(0, str.indexOf("#")); // sdfs
String initIdArray = "{'idArray':[{'id': '199'},{'id': '200'},{'id': '211'}]}";
String strValue = initIdArray.substring(11); // 裁剪掉左边中括号前面的部分
// 取字符长度,间接获取最后一位的索引值
strValue = strValue.substring(0, strValue.length() - 1); // 去掉最后的大括号 构造完整的集合
Log.d(TAG, "parseId: " + initIdArray);/*{'idArray':[{'id': '199'},{'id': '200'},{'id': '211'}]}*/
Log.d(TAG, "parseId: " + strValue); /*[{'id': '199'},{'id': '200'},{'id': '211'}]*/
2.Json读写
implementation 'com.google.code.gson:gson:2.6.2'
引入Gson库,使用 com.google.gson 包下的JsonObject进行Json文件的编写——即代码中给定数据,然后利用JsonObject构造Json文件,并且将数据写入其中,最后保存起来。
① 代码构造Json文件;
private void buildJson1() {
//构建数组 []
JsonArray array = new JsonArray();
for (int i = 0; i < 3; i++) {
JsonObject object = new JsonObject();
object.addProperty("id", "s" + i);
array.add(object);
}
JsonArray array2 = new JsonArray();
for (int i = 0; i < 3; i++) {
JsonObject object = new JsonObject();
object.addProperty("colorId", "colorId" + i);
object.addProperty("colorNum", "colorNum" + i);
array2.add(object);
}
//构建key:value键值对 {}
jsonObject.add("userArray", array);
jsonObject.add("userArray2", array2);
Log.d(TAG, "buildJson1: " + jsonObject.toString());
}
得到的结果如下:构造了两个集合,分别用于装载不同的字符数据。
② 代码解析Json文件中的一部分数组;
private void parseId() {
String initIdArray = "{'idArray':[{'id': '188'},{'id': '199'},{'id': '200'},{'id': '211'}]}";
String strValue = initIdArray.substring(11); // 裁剪掉左边中括号前面的部分
strValue = strValue.substring(0, strValue.length() - 1); // 去掉最后的大括号 构造完整的集合
Log.d(TAG, "parseId: " + initIdArray);/*{'idArray':[{'id': '188'},{'id': '199'},{'id': '200'},{'id': '211'}]}*/
Log.d(TAG, "parseId: " + strValue); /*[{'id': '188'},{'id': '199'},{'id': '200'},{'id': '211'}]*/
//Json数组 转为 List
Gson gson = new Gson();
List stringIdList = gson.fromJson(strValue, new TypeToken>() {
}.getType());
for (int i = 0; i < stringIdList.size(); i++) {
Log.d(TAG, "parseId: " + stringIdList.get(i).getId());
}
}
上面使用的JavaBean如下:
public class SvgIdBean {
private String id;
public SvgIdBean(String id) {
this.id = id;
}
}
得到的结果如下:
③ 正式项目中解析正式Json的方法;
上面的方法中其实是解析了Json的一个集合而言,并不是一个完整的Json文件,现取完整数据源如下:
分为两组集合进行解析,完整的解析方法如下:
引入Blankj万能工具库:
implementation 'com.blankj:utilcode:1.25.9'
private void initSelectedItemList() {
String initIdArray = IdJsonUtils.readJsonData(svgTitle, context);
Log.d(TAG, "initSelectedItemList: initIdArray," + initIdArray);
JSONArray jsonIdElements = JsonUtils.getJSONArray(initIdArray, "idArray", new JSONArray());
Log.d(TAG, "initSelectedItemList: jsonId,," + jsonIdElements + ",," + jsonIdElements.length());
for (int i = 0; i < jsonIdElements.length(); i++) {
try {
String stringId = jsonIdElements.getJSONObject(i).getString("id");
stringIdList.add(stringId);
} catch (JSONException e) {
e.printStackTrace();
}
}
JSONArray jsonColorElements = JsonUtils.getJSONArray(initIdArray, "colorArray", new JSONArray());
String colorNum = "";
String colorId = "";
Log.d(TAG, "initSelectedItemList: jsonColor,," + jsonColorElements);
for (int i = 0; i < jsonColorElements.length(); i++) {
try {
colorId = jsonColorElements.getJSONObject(i).getString("colorId");
colorNum = jsonColorElements.getJSONObject(i).getString("colorNum");
colorMap.put(colorId, Integer.valueOf(colorNum));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
使用工具类,传入Json的字符段名称后进行解析,结果如下:
然后分别遍历名称为“idArray”和“colorArray”的数组,就可以分别获取完整的数据。
3.XML读写
① XML文件的写入;
给定数据后,写入Xml有两种方法,一是使用XmlSerializer类,而是使用Document类。
/**
* 写入XML数据 的两种方法
*/
private void WriteXmlToSdcardByXmlSerial() {
List deviceInfoList = new ArrayList<>();
DeviceInfo deviceInfo = new DeviceInfo("M1942型手枪", 1, 188, "M1942", "干");
DeviceInfo deviceInfo3 = new DeviceInfo("M3A1冲锋枪", 2, 199, "M3A1", "斗");
deviceInfoList.add(deviceInfo);
deviceInfoList.add(deviceInfo3);
try {
//-------内部-----------
// // 指定流目录
// OutputStream os = openFileOutput("persons.xml", Context.MODE_PRIVATE);
// // 设置指定目录
// serializer.setOutput(os, "UTF-8");
//--------外部---------
//xml文件的序列号器 帮助生成一个xml文件
copyAssetAndWrite("device_test.xml");
File file = new File(getCacheDir(), "device_test.xml");
FileOutputStream fos = new FileOutputStream(file);
Log.d(TAG, "WriteXmlToSdcardByXmlSerial: 绝对路径,," + file.getAbsolutePath()); // /data/user/0/com.seotm.coloring/cache/device_test.xml
//获取到xml的序列号
XmlSerializer serializer = Xml.newSerializer();
//序列化初始化
serializer.setOutput(fos, "utf-8");
//创建xml
serializer.startDocument("utf-8", true);
//顶层element有且只有一个
serializer.startTag(null, "xml_data");
serializer.startTag(null, "user");
serializer.attribute(null, "name", "wujn");
serializer.endTag(null, "user");
//多组...
serializer.startTag(null, "deviceinfos");
for (int i = 0; i < deviceInfoList.size(); i++) {
serializer.startTag(null, "deviceinfo");
serializer.attribute(null, "id", String.valueOf(deviceInfoList.get(i).getId()));
serializer.startTag(null, "name");
serializer.text(deviceInfoList.get(i).getName());
serializer.endTag(null, "name");
serializer.startTag(null, "price");
serializer.text(String.valueOf(deviceInfoList.get(i).getPrice()));
serializer.endTag(null, "price");
serializer.startTag(null, "company");
serializer.text(deviceInfoList.get(i).getCompany());
serializer.endTag(null, "company");
serializer.startTag(null, "usage");
serializer.text(deviceInfoList.get(i).getUsage());
serializer.endTag(null, "usage");
serializer.endTag(null, "deviceinfo");
}
serializer.endTag(null, "deviceinfos");
//顶层element有且只有一个
serializer.endTag(null, "xml_data");
//关闭文档
serializer.endDocument();
//写入流关闭
fos.flush();
fos.close();
Log.d(TAG, "WriteXmlToSdcardByXmlSerial: xml数据已导出");
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void WriteXmlToSdcardByDom() {
List deviceInfoList = new ArrayList<>();
DeviceInfo deviceInfo = new DeviceInfo("M1伽兰德步枪 ", 21, 668, "M1", "奔");
DeviceInfo deviceInfo3 = new DeviceInfo("M2火焰喷射器", 33, 7999, "M2", "焱");
deviceInfoList.add(deviceInfo);
deviceInfoList.add(deviceInfo3);
try {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = null;
documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.newDocument();
document.setXmlStandalone(true);
document.setXmlVersion("1.0");
//根节点
Element root = document.createElement("xml_data");
//user节点
Element userE = document.createElement("user");
userE.setAttribute("name", "wujn");
root.appendChild(userE);
//deviceinfos节点
Element devsE = document.createElement("deviceinfos");
for (int i = 0; i < deviceInfoList.size(); i++) {
//单个deviceinfo节点
Element devE = document.createElement("deviceinfo");
devE.setAttribute("id", String.valueOf(deviceInfoList.get(i).getId()));
Element nameE = document.createElement("name");
nameE.setTextContent(deviceInfoList.get(i).getName());
devE.appendChild(nameE);
Element priceE = document.createElement("price");
priceE.setTextContent(String.valueOf(deviceInfoList.get(i).getPrice()));
devE.appendChild(priceE);
Element companyE = document.createElement("company");
companyE.setTextContent(deviceInfoList.get(i).getCompany());
devE.appendChild(companyE);
Element usageE = document.createElement("usage");
usageE.setTextContent(deviceInfoList.get(i).getUsage());
devE.appendChild(usageE);
//添加deviceinfo节点
devsE.appendChild(devE);
}
root.appendChild(devsE);
document.appendChild(root);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
//转成string
transformer.setOutputProperty("encoding", "utf-8");
StringWriter stringWriter = new StringWriter();
transformer.transform(new DOMSource(document), new StreamResult(stringWriter));
//xml文件的序列号器 帮助生成一个xml文件
copyAssetAndWrite("device_test_dom.xml");
File file = new File(getCacheDir(), "device_test_dom.xml");
Log.d(TAG, "WriteXmlToSdcardByDom: Dom绝对路径," + file.getAbsolutePath());
FileOutputStream fos = new FileOutputStream(file);
fos.write(stringWriter.toString().getBytes());
//写入流关闭
fos.flush();
fos.close();
Log.d(TAG, "WriteXmlToSdcardByXmlSerial: xml数据已导出");
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}
}
使用到的JavaBean如下:
public class DeviceInfo {
String name;
int id;
int price;
String company;
String usage;
public DeviceInfo(String name,int id,int price,String company,String usage){
this.name = name;
this.id = id;
this.price = price;
this.company = company;
this.usage = usage;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getUsage() {
return usage;
}
public void setUsage(String usage) {
this.usage = usage;
}
}
因为文件内容以流的形式进行传输,所以存储到一个位置,这里将其写入缓存中,代码如下:
/**
* 将文件写入缓存
*/
private boolean copyAssetAndWrite(String fileName) {
try {
File cacheDir = getCacheDir();
if (!cacheDir.exists()) {
cacheDir.mkdirs();
}
File outFile = new File(cacheDir, fileName);
if (!outFile.exists()) {
boolean res = outFile.createNewFile();
if (!res) {
return false;
}
} else {
if (outFile.length() > 10) {//表示已经写入一次
return true;
}
}
InputStream is = getAssets().open(fileName);
FileOutputStream fos = new FileOutputStream(outFile);
byte[] buffer = new byte[1024];
int byteCount;
while ((byteCount = is.read(buffer)) != -1) {
fos.write(buffer, 0, byteCount);
}
fos.flush();
is.close();
fos.close();
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
得到的结果如下:路径为——/data/user/0/com.seotm.coloring/cache/block_path_test.xml
② XML读取;
以读取SVG的内容为例,
读取方法如下:使用XmlPullParser类进行读取
private void parseSvgXml(int resId) {
XmlPullParserFactory factory = null;
InputStream is = null;
try {
is = getResources().openRawResource(resId); //将xml文件导入输入流
factory = XmlPullParserFactory.newInstance(); //构造工厂实例
factory.setNamespaceAware(true); //设置xml命名空间为true
XmlPullParser xmlPullParser = factory.newPullParser(); //创建解析对象
xmlPullParser.setInput(is, "UTF-8"); //设置输入流和编码方式
int evtType = xmlPullParser.getEventType(); // 产生第一个时间
List list = new ArrayList<>();
List listLine = new ArrayList<>();
List colorDataList = new ArrayList<>();
String title = "";
//获取地图的整个上下左右位置,
float left = -1;
float right = -1;
float top = -1;
float bottom = -1;
while (evtType != XmlPullParser.END_DOCUMENT) {
switch (evtType) {
case XmlPullParser.START_TAG:
String tagName = xmlPullParser.getName();
if (tagName.equals("title")) {
title = xmlPullParser.nextText();
}
if (tagName.equals("path")) {
int tagCount = xmlPullParser.getAttributeCount();
if (tagCount == 3) {
/*g - block*/
String styleName = xmlPullParser.getAttributeName(0);
String styleValue = xmlPullParser.getAttributeValue(0); // 即为填充颜色
String[] strs = styleValue.split(" "); // "fill: #876d71"
String strValue = strs[1]; // #876d71
colorDataList.add(strValue);
String pathName = xmlPullParser.getAttributeName(1);
String pathValue = xmlPullParser.getAttributeValue(1); // 即为pathdata
String idName = xmlPullParser.getAttributeName(2);
String idValue = xmlPullParser.getAttributeValue(2); // 即为id 包含数字位置和大小信息
String[] strPos = idValue.split("_"); // "663_472_22"
String positionX = strPos[0]; // 663
String positionY = strPos[1]; // 472
String testSize = strPos[2]; // 22
Log.d(TAG, "parseSvgXml: svg_id,," + Arrays.toString(strPos) + ",," + testSize);
@SuppressLint("RestrictedApi")
Path path = PathParser.createPathFromPathData(pathValue);
WBSvgItem wbSvgItem = new WBSvgItem(path);// 设置路径
wbSvgItem.setDrawColor(strValue);// 设置描边颜色
wbSvgItem.setCenterPosition(positionX, positionY);//设置画数字的区域
wbSvgItem.setTextSize(Integer.parseInt(testSize));
wbSvgItem.setId(idValue);
RectF rect = new RectF();
path.computeBounds(rect, true);
left = left == -1 ? rect.left : Math.min(left, rect.left);
right = right == -1 ? rect.right : Math.max(right, rect.right);
top = top == -1 ? rect.top : Math.min(top, rect.top);
bottom = bottom == -1 ? rect.bottom : Math.max(bottom, rect.bottom);
list.add(wbSvgItem);
} else {
/*g - line*/
String styleName = xmlPullParser.getAttributeName(0);
String styleValue = xmlPullParser.getAttributeValue(0);
String[] strs = styleValue.split(" ");
String strValue = strs[1];
String pathName = xmlPullParser.getAttributeName(1);
String pathValue = xmlPullParser.getAttributeValue(1);
@SuppressLint("RestrictedApi")
Path path = PathParser.createPathFromPathData(pathValue);
WBSvgLineItem wbSvgItem = new WBSvgLineItem(path);//设置路径
wbSvgItem.setDrawColor(strValue);//设置描边颜色
listLine.add(wbSvgItem);
}
}
break;
case XmlPullParser.END_TAG:
break;
}
evtType = xmlPullParser.next();
}
svgTitle = title;
itemList = list;
fixedItemList = list;
itemListLine = listLine;
colorList = colorDataList;
allColorMap = ColorTypeUtils.frequencyOfListElements(colorDataList);
// 利用HashSet去重 元素的位置乱掉了 所以换一种方式
colorTypeList = ColorTypeUtils.removeDuplicate(colorDataList);
initSelectedItemList();
totalRect = new RectF(left, top, right, bottom);//设置地图的上下左右位置
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4.Hashmap的使用
存取一对一对的数据特别合适使用Hashmap。
// 声明
private HashMap colorMap;
// 初始化
colorMap = new HashMap<>();
// 取值
String colortype = "#ff77ll";
int clickNumColor = colorMap.get(colortype);
// 给值
colorId = jsonColorElements.getJSONObject(i).getString("colorId");
colorNum = jsonColorElements.getJSONObject(i).getString("colorNum");
colorMap.put(colorId, Integer.valueOf(colorNum));
// 遍历
for (Map.Entry entry : colorMap.entrySet()) {
JsonObject object = new JsonObject();
object.addProperty("colorId", entry.getKey());
object.addProperty("colorNum", entry.getValue());
array2.add(object);
}
提供两篇参考文章:
《HashMap的基本使用》关于Key Value 键值对的基本使用;
《HashMap循环遍历方式及其性能对比》 HashMap几种遍历方式的使用;
另外有一点要注意的是布尔类型的值只有两个,不适合用作key值,而要做为Value使用。
5.File存储
前文中XML编写好后,因为是中间文件,所以是存入了缓存中,路径为:/data/user/0/com.seotm.coloring/cache/block_path_test.xml
前文中Json编写好后,因为不是中间文件,是应用内重要的使用文件,所以需要存在本地,使用的方法如下:
/**
* 描述 封装 用以创建,存储和读取Json的工具类
* 一副图使用一个Json 注意文件夹的命名 提取SVG中图片的title名s
* 文件夹名——/storage/emulated/0/Android/data/com.seotm.coloring/files/TemplateInfoJson
* 文件名——art_01_flower_templateInfo
*/
public class IdJsonUtils {
private static final String TAG = "IdJsonUtils";
private static final String FILENAME = "_templateInfo.json";
/*
* 将Json格式的数据存入外部存储
* {"idArray":[{"id":"120_9"},{"id":"87_12"},{"id":"108_47"}]}
* */
public static void saveJsonData(List idList, HashMap colorMap,
String svgName, Context context) {
JsonArray array = new JsonArray();
for (int i = 0; i < idList.size(); i++) {
JsonObject object = new JsonObject();
object.addProperty("id", idList.get(i));
array.add(object);
}
JsonArray array2 = new JsonArray();
for (Map.Entry entry : colorMap.entrySet()) {
JsonObject object = new JsonObject();
object.addProperty("colorId", entry.getKey());
object.addProperty("colorNum", entry.getValue());
array2.add(object);
}
JsonObject jsonObject = new JsonObject();
jsonObject.add("idArray", array);
jsonObject.add("colorArray", array2);
Log.d(TAG, "saveJsonData: " + jsonObject.toString());
String fileName = "";
File saveJsonFile = context.getExternalFilesDir("TemplateInfoJson");
if (saveJsonFile != null) {
fileName = saveJsonFile.getAbsolutePath() + File.separator + svgName + FILENAME;
Log.d(TAG, "saveJsonData: 存," + fileName);
}
File file2 = new File(fileName);
try {
FileOutputStream fos = new FileOutputStream(file2);
Writer write = new OutputStreamWriter(fos, "UTF-8");
write.write(jsonObject.toString());
write.flush();
write.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* 从对应外部存储的地方读取Json数据
* {"idArray":[{"id":"120_9"},{"id":"87_12"},{"id":"108_47"}]}
* */
public static String readJsonData(String svgName, Context context) {
String fileName = "";
File saveJsonFile = context.getExternalFilesDir("TemplateInfoJson");
if (saveJsonFile != null) {
fileName = saveJsonFile.getAbsolutePath() + File.separator + svgName + FILENAME;
Log.d(TAG, "readJsonData: 取," + fileName);
}
File file2 = new File(fileName);
FileInputStream fis = null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
try {
fis = new FileInputStream(file2);
reader = new BufferedReader(new InputStreamReader(fis));
String line = "";
while ((line = reader.readLine()) != null) {
content.append(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Log.d(TAG, "readJsonData: " + content.toString());
return content.toString();
}
}
得到的结果如下:
文件夹名——/storage/emulated/0/Android/data/com.seotm.coloring/files/TemplateInfoJson
文件名——art_01_flower_templateInfo
File saveJsonFile = context.getExternalFilesDir("TemplateInfoJson");
if (saveJsonFile != null) {
fileName = saveJsonFile.getAbsolutePath() + File.separator + svgName + FILENAME;
}
File file2 = new File(fileName);
存在设备的外部的公共环境下。