在做项目的时候难免需要保存一下配置文件,我们经常使用的就是SharedPreferences,但是当我们清除掉缓存或者卸载后重新安装这些配置文件内容就不存在了,当我们想卸载后重新安装这些配置文件还在,那只能将这些配置文件保存到本地了,用的时候去读取,保存本地有两种,保存为TXT或者是保存为xml
第一种:把配置文件保存为TXT到本地
1、我们需要一个操作文件的工具类,这里已经写好
import android.graphics.Bitmap;
import android.os.Environment;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
/**
* date : 2021/4/23 2:05 PM
* description :文件工具类
*/
public class FileUtils {
/**
* 读取txt文件的内容
*
* @param filePath 想要读取的文件对象
* @return 返回文件内容
*/
public static String txt2String(String filePath) {
File file = new File(filePath);
if (!file.exists()) {
return "";
}
StringBuilder result = new StringBuilder();
try {
// 构造一个BufferedReader类来读取文件
BufferedReader br = new BufferedReader(new FileReader(file));
String s = null;
// 使用readLine方法,一次读一行
while ((s = br.readLine()) != null) {
result.append(System.lineSeparator() + s);
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return result.toString();
}
/**
* 写入TXT文件
*/
public static boolean writeTxtFile(String content, String filePath) {
File file = new File(filePath);
if (!file.exists()) {
return false;
}
RandomAccessFile mm = null;
boolean flag = false;
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(content.getBytes("utf-8"));
fileOutputStream.close();
flag = true;
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
/**
* Checks if is sd card available.检查SD卡是否可用
*/
public static boolean isSdCardAvailable() {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}
/**
* Gets the SD root file.获取SD卡根目录
*/
public static File getSDRootFile() {
if (isSdCardAvailable()) {
return Environment.getExternalStorageDirectory();
} else {
return null;
}
}
/**
* 获取导入图片文件的目录信息
*/
public static File getBatchImportDirectory() {
// 获取根目录
File sdRootFile = getSDRootFile();
File file = null;
if (sdRootFile != null && sdRootFile.exists()) {
file = new File(sdRootFile, "Face-Import");
if (!file.exists()) {
file.mkdirs();
}
}
return file;
}
/**
* 获取导入图片成功的目录信息
*/
public static File getBatchImportSuccessDirectory() {
File sdRootFile = getSDRootFile();
File file = null;
if (sdRootFile != null && sdRootFile.exists()) {
file = new File(sdRootFile, "Success-Import");
if (!file.exists()) {
file.mkdirs();
}
}
return file;
}
/**
* 判断文件是否存在
*/
public static File isFileExist(String fileDirectory, String fileName) {
File file = new File(fileDirectory + "/" + fileName);
try {
if (!file.exists()) {
return null;
}
} catch (Exception e) {
return null;
}
return file;
}
/**
* 删除文件
*/
public static void deleteFile(String filePath) {
try {
// 找到文件所在的路径并删除该文件
File file = new File(filePath);
file.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* 获取不带扩展名的文件名
* */
public static String getFileNameNoEx(String filename) {
if ((filename != null) && (filename.length() > 0)) {
int dot = filename.lastIndexOf('.');
if ((dot > -1) && (dot < (filename.length()))) {
return filename.substring(0, dot);
}
}
return filename;
}
/**
* 保存图片
*/
public static boolean saveBitmap(File file, Bitmap bitmap) {
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
public static boolean copyFile(String oldPath, String newPath) {
InputStream inStream = null;
FileOutputStream fs = null;
boolean result = false;
try {
int bytesum = 0;
int byteread = 0;
File oldfile = new File(oldPath);
// 判断目录是否存在
File newfile = new File(newPath);
File newFileDir = new File(newfile.getPath().replace(newfile.getName(), ""));
if (!newFileDir.exists()) {
newFileDir.mkdirs();
}
if (oldfile.exists()) { // 文件存在时
inStream = new FileInputStream(oldPath); // 读入原文件
fs = new FileOutputStream(newPath);
byte[] buffer = new byte[1444];
int length;
while ((byteread = inStream.read(buffer)) != -1) {
bytesum += byteread; // 字节数 文件大小
System.out.println(bytesum);
fs.write(buffer, 0, byteread);
}
result = true;
} else {
result = false;
}
} catch (Exception e) {
System.out.println("复制单个文件操作出错");
e.printStackTrace();
} finally {
if (inStream != null) {
try {
inStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fs != null) {
try {
fs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
}
2,、需要一个保存读取文件的工具类,同时检测文件是否存在,文件里面是否有内容等
import android.os.Environment;
import android.util.Log;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by Forrest.
* User: Administrator
* Date: 2021/5/7
* Description:
*/
public class SaveConfigUtils {
//设置gateFaceConfig的根路径
public static final String folder = Environment.getExternalStorageDirectory() + File.separator + "Settings";
// 配置文件路径
public static final String filePath = folder + "/" + "Ceshi.txt";
//判断文件是否存在
public static boolean isConfigExit() {
File file1 = new File(folder);
//判断Settings文件夹是否存在
if (!file1.exists()) {
file1.mkdirs();
}
//判断gateFaceConfig.txt文件是否存在,存在返回true,不存在创建文件并更新文件
File file = new File(filePath);
if (file.exists()) {
return true;
} else {
try {
file.createNewFile();
modityJson();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
}
public static String configMessage() {
String configMessage = FileUtils.txt2String(filePath);
return configMessage;
}
/**
* 判断SDCard是否可用
*
* @return
*/
public static boolean isSDCardEnable() {
return Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED);
}
/**
* 读取配置文件内容
*
* @return
*/
public static Boolean initConfig() {
//得到gateFaceConfig.txt文件里面的内容
String configMessage = FileUtils.txt2String(filePath);
//gateFaceConfig.txt里面的内容为空返回false
if (configMessage.equals("")) {
Log.e("facesdk", "文件不存在");
return false;
}
//gateFaceConfig.txt里面的内容不为空就为SingleBaseConfig赋值
Log.e("人脸识别", filePath + "文件存在" + configMessage);
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(configMessage);
if (!identify(jsonObject)) {
return false;
}
SingleBaseConfig.getBaseConfig().setName(jsonObject.getString("name"));// RGB检测帧回显
SingleBaseConfig.getBaseConfig().setSex(jsonObject.getString("sex"));// NIR或depth实时视频预览
SingleBaseConfig.getBaseConfig().setAge(jsonObject.getString("age"));// 默认为false。可选项为"true"、"false",是否开启调试显示,将会作用到所有视频流识别页面,包含1:N、1:1采集人脸图片环节。
return true;
} catch (Exception e) {
e.printStackTrace();
Log.e("facesdk", "文件内容异常,请检测是否规范");
return false;
}
}
// 校验sdcard里的txt文件内容是否正常
public static boolean identify(JSONObject jsonObject) {
try {
Boolean display = (Boolean) jsonObject.get("display");
Boolean isNirOrDepth = (Boolean) jsonObject.get("isNirOrDepth");
Boolean debug = (Boolean) jsonObject.get("debug");
int videoDirection = Integer.parseInt(jsonObject.getString("videoDirection"));
if (!(videoDirection == 0 || videoDirection == 90 || videoDirection == 180 || videoDirection == 270)) {
return false;
}
String detectFrame = (String) jsonObject.get("detectFrame");
if (!(detectFrame.equals("wireframe") || detectFrame.equals("fixedarea"))) {
return false;
}
// int radius = (int) jsonObject.get("radius");
int detectDirection = (int) jsonObject.get("detectDirection");
if (!(detectDirection == 0 || detectDirection == 90 || detectDirection == 180
|| detectDirection == 270)) {
return false;
}
String trackType = (String) jsonObject.get("trackType");
if (!(trackType.equals("max") || trackType.equals("first") || trackType.equals("none"))) {
return false;
}
int minimumFace = (int) jsonObject.get("minimumFace");
if (minimumFace < 30) {
return false;
}
float blur = Float.valueOf(jsonObject.get("blur") + "");
if (blur > 1 || blur < 0) {
return false;
}
int illumination = (int) jsonObject.get("illumination");
if (illumination < 0 || illumination > 255) {
return false;
}
float gesture = Float.valueOf(jsonObject.get("gesture") + "");
float pitch = Float.valueOf(jsonObject.get("pitch") + "");
if (pitch < -90 || pitch > 90) {
return false;
}
float roll = Float.valueOf(jsonObject.get("roll") + "");
if (roll < -90 || roll > 90) {
return false;
}
float yaw = Float.valueOf(jsonObject.get("yaw") + "");
if (yaw < -90 || yaw > 90) {
return false;
}
float occlusion = Float.valueOf(jsonObject.get("occlusion") + "");
if (occlusion < 0 || occlusion > 1) {
return false;
}
float leftEye = Float.valueOf(jsonObject.get("leftEye") + "");
if (leftEye < 0 || leftEye > 1) {
return false;
}
float rightEye = Float.valueOf(jsonObject.get("rightEye") + "");
if (rightEye < 0 || rightEye > 1) {
return false;
}
float nose = Float.valueOf(jsonObject.get("nose") + "");
if (nose < 0 || nose > 1) {
return false;
}
float mouth = Float.valueOf(jsonObject.get("mouth") + "");
if (mouth < 0 || mouth > 1) {
return false;
}
float leftCheek = Float.valueOf(jsonObject.get("leftCheek") + "");
if (leftCheek < 0 || leftCheek > 1) {
return false;
}
float rightCheek = Float.valueOf(jsonObject.get("rightCheek") + "");
if (rightCheek < 0 || rightCheek > 1) {
return false;
}
float chinContour = Float.valueOf(jsonObject.get("chinContour") + "");
if (chinContour < 0 || chinContour > 1) {
return false;
}
float completeness = Float.valueOf(jsonObject.get("completeness") + "");
if (completeness < 0 || completeness > 1) {
return false;
}
int rgbAndNirThreshold = Integer.valueOf(jsonObject.get("rgbAndNirThreshold") + "");
if (rgbAndNirThreshold < 0 || rgbAndNirThreshold > 100) {
return false;
}
int cameraLightThreshold = Integer.valueOf(jsonObject.get("cameraLightThreshold") + "");
if (cameraLightThreshold < 0 || cameraLightThreshold > 100) {
return false;
}
int liveThreshold = Integer.valueOf(jsonObject.get("liveThreshold") + "");
if (liveThreshold < 0 || liveThreshold > 100) {
return false;
}
int idThreshold = Integer.valueOf(jsonObject.get("IdThreshold") + "");
if (idThreshold < 0 || idThreshold > 100) {
return false;
}
int activeModel = Integer.valueOf(jsonObject.get("activeModel") + "");
if (!(activeModel == 1 || activeModel == 2 || activeModel == 3)) {
return false;
}
int timeLapse = Integer.valueOf(jsonObject.get("timeLapse") + "");
int type = Integer.valueOf(jsonObject.get("type") + "");
if (!(type == 0 || type == 1 || type == 2 || type == 3 || type == 4)) {
return false;
}
float rgbLiveScore = Float.valueOf(jsonObject.get("rgbLiveScore") + "");
if (rgbLiveScore < 0 || rgbLiveScore > 1) {
return false;
}
float nirLiveScore = Float.valueOf(jsonObject.get("nirLiveScore") + "");
if (nirLiveScore < 0 || nirLiveScore > 1) {
return false;
}
float depthLiveScore = Float.valueOf(jsonObject.get("depthLiveScore") + "");
if (depthLiveScore < 0 || depthLiveScore > 1) {
return false;
}
int cameraType = jsonObject.getInt("cameraType");
if (!(cameraType == 0 || cameraType == 1 || cameraType == 2 || cameraType == 3 ||
cameraType == 4 || cameraType == 5 || cameraType == 6)) {
return false;
}
int mirrorRGB = jsonObject.getInt("mirrorRGB");
if (!(mirrorRGB == 0 || mirrorRGB == 1)) {
return false;
}
int mirrorNIR = jsonObject.getInt("mirrorNIR");
if (!(mirrorNIR == 0 || mirrorNIR == 1)) {
return false;
}
int getBestImageScore = jsonObject.getInt("bestImageScore");
if (getBestImageScore < 0 || getBestImageScore > 100) {
return false;
}
int rgbAndNirWidth = jsonObject.getInt("rgbAndNirWidth");
int rgbAndNirHeight = jsonObject.getInt("rgbAndNirHeight");
int depthWidth = jsonObject.getInt("depthWidth");
int depthHeight = jsonObject.getInt("depthHeight");
} catch (Exception e) {
String errorMessage = getErrorInfoFromException(e);
e.printStackTrace();
Log.e("facesdk", "文件内容格式异常,请检测是否规范");
return false;
}
return true;
}
/**
* 修改配置文件内容并重新读取配置
*/
public static boolean modityJson() {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("name", SingleBaseConfig.getBaseConfig().getName());
jsonObject.put("sex", SingleBaseConfig.getBaseConfig().getSex());
jsonObject.put("age", SingleBaseConfig.getBaseConfig().getAge());
// 修改内容写入配置文件
FileUtils.writeTxtFile(jsonObject.toString(), filePath);
// 重新读取配置文件内容
initConfig();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public static String getErrorInfoFromException(Exception e) {
try {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
return "\r\n" + sw.toString() + "\r\n";
} catch (Exception e2) {
return "bad getErrorInfoFromException";
}
}
/**
* 判断数字正则表达式
*
* @param str
* @return
*/
public boolean isNumeric(String str) {
Pattern pattern = Pattern.compile("[0-9]");
Matcher isNum = pattern.matcher(str);
if (!isNum.matches()) {
return false;
}
return true;
}
/**
* 判断字符正则表达式
*
* @param str
* @return
*/
public boolean isString(String str) {
return str.matches("[a-zA-Z]+");
}
// 对象属性赋值
public static <T> T gotObjectByObject(Object object, Class<T> clazz) throws Exception {
T t = null;
if (clazz != null && object != null) {
t = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String key = field.getName();
try {
Field field1 = object.getClass().getDeclaredField(key);
field1.setAccessible(true);
Object val = field1.get(object);
field.set(t, val);
} catch (Exception e) {
t = null;
System.out.println(object.getClass().getName() + "没有该属性: " + key);
}
}
}
return t;
}
}
3、配置一下需要保存的参数
/**
* Created by Forrest.
* User: Administrator
* Date: 2021/5/7
* Description:
*/
public class FileConfig {
private String name="张三";
private String sex="男";
private String age="12";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
4、配置FileConfig为单例
/**
* date : 2021/4/23 11:23 AM
* description :配置BaseConfig单例
*/
public class SingleBaseConfig {
private static FileConfig baseConfig;
private SingleBaseConfig() {
}
public static FileConfig getBaseConfig() {
if (baseConfig == null) {
baseConfig = new FileConfig();
}
return baseConfig;
}
public static void copyInstance(FileConfig result) {
baseConfig = result;
}
}
5、然后就是保存和读取的操作了
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_savetxt:
SingleBaseConfig.getBaseConfig().setName(mEtName.getText().toString());
SingleBaseConfig.getBaseConfig().setSex(mEtSex.getText().toString());
SingleBaseConfig.getBaseConfig().setAge(mEtAge.getText().toString());
SaveConfigUtils.modityJson();
break;
case R.id.btn_readtxt:
String name = SingleBaseConfig.getBaseConfig().getName();
String sex = SingleBaseConfig.getBaseConfig().getSex();
String age = SingleBaseConfig.getBaseConfig().getAge();
mTvShowtxt.setText(SaveConfigUtils.configMessage());
Log.e("Ceshi文件", "name=" + name);
Log.e("Ceshi文件", "sex=" + sex);
Log.e("Ceshi文件", "age=" + age);
break;
}
}
第二种、把配置文件保存为xml到本地
1、保存方法
/**
* 保存配置文件到本地
*/
public void setConfig() {
try {
File file = new File(Environment.getExternalStorageDirectory() + File.separator + "Settings", "Ceshi.xml");
Log.e(TAG, "" + file);
FileOutputStream fos = new FileOutputStream(file);
// 获得一个序列化工具
XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(fos, "utf-8");
// 设置文件头
serializer.startDocument("utf-8", true);
serializer.startTag(null, "persons");
serializer.startTag(null, "person");
serializer.attribute(null, "id", String.valueOf(0));
// TODO 写入姓名
serializer.startTag(null, "name");
serializer.text(mEtName.getText().toString());
serializer.endTag(null, "name");
// TODO 写入性别
serializer.startTag(null, "sex");
serializer.text(mEtSex.getText().toString());
serializer.endTag(null, "sex");
// TODO 写入年纪
serializer.startTag(null, "age");
serializer.text(mEtAge.getText().toString());
serializer.endTag(null, "age");
serializer.endTag(null, "person");
serializer.endTag(null, "persons");
serializer.endDocument();
fos.close();
Toast.makeText(SaveConfigActivity.this, "保存成功", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(SaveConfigActivity.this, "保存失败", Toast.LENGTH_SHORT).show();
}
}
2、读取方法
/**
* 读取本地配置文件
*/
public void getConfig() {
try {
File path = new File(Environment.getExternalStorageDirectory() + File.separator + "Settings", "Ceshi.xml");
FileInputStream fis = new FileInputStream(path);
// 获得pull解析器对象
XmlPullParser parser = Xml.newPullParser();
// 指定解析的文件和编码格式
parser.setInput(fis, "utf-8");
int eventType = parser.getEventType(); // 获得事件类型
String id = null;
String name = null;
String sex = null;
String age = null;
while (eventType != XmlPullParser.END_DOCUMENT) {
String tagName = parser.getName(); // 获得当前节点的名称
switch (eventType) {
case XmlPullParser.START_TAG: // 当前等于开始节点 <person
if ("persons".equals(tagName)) { // <persons
} else if ("person".equals(tagName)) { // <person id="1"
id = parser.getAttributeValue(null, "id");
} else if ("name".equals(tagName)) { // <versioncode
name = parser.nextText();
} else if ("sex".equals(tagName)) { // <soakingvoice
sex = parser.nextText();
} else if ("age".equals(tagName)) { // <voiceprompt
age = parser.nextText();
}
break;
case XmlPullParser.END_TAG: // </persons
if ("person".equals(tagName)) {
Log.e(TAG, "id---" + id);
Log.e(TAG, "name---" + name);
Log.e(TAG, "sex---" + sex);
Log.e(TAG, "age---" + age);
mTvShowxml.setText("name:" + name + "\rsex:" + sex + "\rage:" + age);
}
break;
default:
break;
}
eventType = parser.next(); // 获得下一个事件类型
}
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
两种方法都可以保存配置文件到本地,另外SharedPreferences现在已经被mmvk所代替,下面介绍下mmvk的使用方法
mmvk
1、添加依赖
implementation 'com.tencent:mmkv-static:1.0.23'
2、添加Application配置,放到onCreate里面
//缓存的文件在Settings文件夹下的mmvk文件夹
String dir = Environment.getExternalStorageDirectory() + File.separator + "Settings"+"/mmvk";
MMKV.initialize(dir);
SpUtils.getInstance();
3、使用方法
//保存
SpUtils.encode("int",10);
SpUtils.encode("bool",false);
SpUtils.encode("long",10);
SpUtils.encode("float",10.f);
SpUtils.encode("double",10.5);
SpUtils.encode("string","10");
byte[] bytes = {'m', 'm', 'k', 'v'};
SpUtils.encode("bytes",bytes);
//读取
LogUtils.e(SpUtils.decodeInt("int"));
LogUtils.e(SpUtils.decodeBoolean("bool"));
LogUtils.e(SpUtils.decodeLong("long"));
LogUtils.e(SpUtils.decodeFloat("float"));
LogUtils.e(SpUtils.decodeDouble("double"));
LogUtils.e(SpUtils.decodeString("string"));
LogUtils.e(SpUtils.decodeBytes("bytes"));
package com.dhy.health.saveconfig;
import android.os.Parcelable;
import com.tencent.mmkv.MMKV;
import java.util.Collections;
import java.util.Set;
/**
* Created by Forrest.
* User: Administrator
* Date: 2021/3/25
* Description:
*/
public class SpUtils {
private static SpUtils mInstance;
private static MMKV mv;
private SpUtils() {
mv = MMKV.defaultMMKV();
}
/**
* 初始化MMKV,只需要初始化一次,建议在Application中初始化
*
*/
public static SpUtils getInstance() {
if (mInstance == null) {
synchronized (SpUtils.class) {
if (mInstance == null) {
mInstance = new SpUtils();
}
}
}
return mInstance;
}
/**
* 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
*
* @param key
* @param object
*/
public static void encode(String key, Object object) {
if (object instanceof String) {
mv.encode(key, (String) object);
} else if (object instanceof Integer) {
mv.encode(key, (Integer) object);
} else if (object instanceof Boolean) {
mv.encode(key, (Boolean) object);
} else if (object instanceof Float) {
mv.encode(key, (Float) object);
} else if (object instanceof Long) {
mv.encode(key, (Long) object);
} else if (object instanceof Double) {
mv.encode(key, (Double) object);
} else if (object instanceof byte[] ) {
mv.encode(key, (byte[]) object);
} else {
mv.encode(key, object.toString());
}
}
public static void encodeSet(String key, Set<String> sets) {
mv.encode(key, sets);
}
public static void encodeParcelable(String key, Parcelable obj) {
mv.encode(key, obj);
}
/**
* 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值
*/
public static Integer decodeInt(String key) {
return mv.decodeInt(key, 0);
}
public static Double decodeDouble(String key) {
return mv.decodeDouble(key, 0.00);
}
public static Long decodeLong(String key) {
return mv.decodeLong(key, 0L);
}
public static Boolean decodeBoolean(String key) {
return mv.decodeBool(key, false);
}
public static Float decodeFloat(String key) {
return mv.decodeFloat(key, 0F);
}
public static byte[] decodeBytes(String key) {
return mv.decodeBytes(key);
}
public static String decodeString(String key) {
return mv.decodeString(key,"");
}
public static Set<String> decodeStringSet(String key) {
return mv.decodeStringSet(key, Collections.<String>emptySet());
}
public static Parcelable decodeParcelable(String key) {
return mv.decodeParcelable(key, null);
}
/**
* 移除某个key对
*
* @param key
*/
public static void removeKey(String key) {
mv.removeValueForKey(key);
}
/**
* 清除所有key
*/
public static void clearAll() {
mv.clearAll();
}
}