一,前期基礎知識儲備
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<SvgIdBean> stringIdList = gson.fromJson(strValue, new TypeToken<List<SvgIdBean>>() {
}.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<DeviceInfo> 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");
//多組<deviceinfo>...</deviceinfo>
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<DeviceInfo> 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<WBSvgItem> list = new ArrayList<>();
List<WBSvgLineItem> listLine = new ArrayList<>();
List<String> 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<String, Integer> 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<String, Integer> 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<String> idList, HashMap<String, Integer> 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<String, Integer> 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);
存在設備的外部的公共環境下。