图片自动更新成U盘里指定的图片
背景:
UI上经常会有一些默认的图片,比如广告图片、加载网络图片时预显示的图片等。对于演示的软件,我们希望这些图片在不修改软件的情况下是可以变化的。如果不这样做,那就必须用新的图片重新编译软件,不灵活。
实现方法:
1、显示图片时,先从data/data/..../files目录下查找指定的图片,有就显示它,没有就使用默认的图片。
2、在u盘里创建一个目录,存放一些指定的png图片,盒子插上U盘后,就会把这些图片拷贝到files下指定的目录,然后刷新UI,图片就被更新成了新的图片。
具体实现:
假如UI上有一个ImageView imgView,没有要求自动更新之前,我们的代码可能为:
imgView.setImageResource(R.mipmap.ic_water_logo_neutral);
这里的参数是资源id,编译时就生成好了。现在我们要用本地的PNG原始图片,显然就不能使用setImageResource了,我们必须使用setImageDrawable。
1、把本地PNG图片转成Drawable。
/**
* 将USB里的PNG图片转化成Drawable对象
* @param: 图片的路径
* @return
*/
public static Drawable externalStorageImageToDrawable(String path) {
try {
Drawable drawable = BitmapDrawable.createFromPath(path);
return drawable;
} catch (Exception e) {
LogUtil.d("error msg:" + e.getMessage());
}
return null;
}
2、插上U盘后把图片拷贝到files目录下。
插上U盘系统会发送Intent.ACTION_MEDIA_MOUNTED广播,我们在接收这个广播的地方把图片拷贝到files目录。
public void onReceive(Context context, Intent intent) {
Uri uri = intent.getData();
if (uri != null) {
path = uri.getPath();
}
if ((intent.getAction().equals("com.droidvold.action.MEDIA_UNMOUNTED") || intent.getAction().equals("com.droidvold.action.MEDIA_EJECT")) && !path.equals("/dev/null")) {
EventBus.getDefault().post(new UsbEvent(UsbEvent.UNMOUNTED, path));
} else if (intent.getAction().equals(Intent.ACTION_MEDIA_MOUNTED) || intent.getAction().equals("com.droidvold.action.MEDIA_MOUNTED")) {
copyLogosToFilesDir(context, path);
}
}
private void copyLogosToFilesDir(Context context, String usbPath) {
String filesDir = context.getFilesDir().getAbsolutePath() + File.separator + "logos";
String usbLogoDir = usbPath + File.separator + "logos";
File usbFile = new File(usbLogoDir);
if (usbFile.exists()) {
FileUtils.copyFolder(usbLogoDir, filesDir);
}
}
public static void copyFolder(String srcDir, String destDir) {
try {
Log.d(TAG, "copyFolder: srcDir = " + srcDir);
Log.d(TAG, "copyFolder: destDir = " + destDir);
File destFile = new File(destDir);
if (destFile.exists()) {
deleteFolderFile(destDir, true);
}
destFile.mkdir();
File srcFile = new File(srcDir);
String[] files = srcFile.list();
File temp;
for (String file : files) {
Log.d(TAG, "copyFolder: file = " + file);
if (srcDir.endsWith(File.separator)) {
temp = new File(srcDir + file);
} else {
temp = new File(srcDir + File.separator + file);
}
if (temp.isDirectory()) { //如果是子文件夹
copyFolder(srcDir + File.separator + file, destDir + File.separator + file);
} else if (!temp.exists()) {
Log.e(TAG, "copyFolder: oldFile not exist.");
return;
} else if (!temp.isFile()) {
Log.e(TAG, "copyFolder: oldFile not file.");
return;
} else if (!temp.canRead()) {
Log.e(TAG, "copyFolder: oldFile cannot read.");
return;
} else {
FileInputStream fileInputStream = new FileInputStream(temp);
FileOutputStream fileOutputStream = new FileOutputStream(destDir + File.separator + temp.getName());
byte[] buffer = new byte[1024];
int byteRead;
while ((byteRead = fileInputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, byteRead);
}
fileInputStream.close();
fileOutputStream.flush();
fileOutputStream.close();
}
}
} catch (Exception e) {
Log.e(TAG, "error msg: " + e.getMessage());
} finally {
}
}
/**
* 删除目录及目录下所有的文件
* @param filePath
* @param deleteThisPath
*/
public static void deleteFolderFile(String filePath, boolean deleteThisPath) {
Log.d("wujiang", "deleteFolderFile: call this fun");
if (!TextUtils.isEmpty(filePath)) {
try {
File file = new File(filePath);
if (file.isDirectory()) {
File files[] = file.listFiles();
for (int i = 0; i < files.length; i++) {
deleteFolderFile(files[i].getAbsolutePath(), true);
}
}
if (deleteThisPath) {
if (!file.isDirectory()) { //如果是文件,删除
file.delete();
} else { //目录
if (file.listFiles().length == 0) { //目录下没有文件或者目录,删除
file.delete();
}
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3、更新imgView。
新的图片已经拷贝到了files目录,我们就可以更新imgView了。根据前面的思路,设置imgView图片方法如下:
imgView.setImageDrawable(getDrawable());
public Drawable getDrawable() {
Drawable drawable;
String logosPath = BaseApplication.get().getFilesDir().getAbsolutePath() + File.separator + "logos";
File file = new File(logosPath);
if (file.exists()) {
String imagePath = logosPath + File.separator + "customer_water_logo.png";
File file1 = new File(imagePath);
if (file1.exists()) {
drawable = Utils.externalStorageImageToDrawable(imagePath);
} else {
drawable = BaseApplication.get().getResources().getDrawable(R.drawable.ic_water_logo_sei, null);
}
} else {
drawable = BaseApplication.get().getResources().getDrawable(R.drawable.ic_water_logo_sei, null);
}
return drawable;
}
改进 :
如果我现在拔掉U盘再插上,imgView将会被再次更新,但是U盘的图片并没有改变,相当于做了无用功。怎么避免这种情况呢?就是说要做到图片没变的情况下,插上U盘不要去更新imgView。
首先,怎么判断图片内容是否变化了呢?我们可以得到图片的MD5数据,比较U盘里的图片和files目录下图片的MD5值是否相等,相等就是同样的图片,反之是不同的图片。
获取MD5的方法如下:
/**
* 得到指定目录文件的MD5值
* @param :文件的绝对目录
* @return
* @throws IOException
*/
public static String getMd5(String fname) throws IOException {
MessageDigest mDigest = MessageDigest.getInstance("MD5");
if (mDigest == null) {
return "";
}
FileInputStream fins = new FileInputStream(fname);
byte[] data = new byte[1024];
int nread = 0;
while ((nread = fins.read(data)) != -1) {
mDigest.update(data, 0, nread);
}
byte[] md5data = mDigest.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < md5data.length; i++) {
sb.append(Integer.toString((md5data[i] & 0xff) + 0x100, 16).substring(1));
}
fins.close();
return sb.toString();
}
然后我们改进copyLogosToFilesDir方法,该方法有返回值,返回true表示有把U盘的图片拷贝到files目录下,不需要更新UI;返回false表示没有进行拷贝动作,这个时候就不需要更新UI了。
/**
* 拷贝文件到 files 目录
* @param context
* @param usbPath
* @return true: 拷贝了; false: 没有拷贝
*/
private boolean copyLogosToFilesDir(Context context, String usbPath) {
Map<String, String> usbPathFilesHashMap = new HashMap<>();
Map<String, String> filesPathFilesHashMap = new HashMap<>();
String filesDir = context.getFilesDir().getAbsolutePath() + File.separator + "logos";
String usbLogoDir = usbPath + File.separator + "logos";
usbPathFilesHashMap.clear();
filesPathFilesHashMap.clear();
try {
File usbFile = new File(usbLogoDir);
if (usbFile.exists()) {
Log.d("wujiang", "copyLogosToFilesDir: usbFile exists");
String[] usbPathFiles = usbFile.list();
File usb_temp;
//得到U盘里所有图片的MD5值, 以文件名作为key, MD5值为value
for (String file : usbPathFiles) {
usb_temp = new File(usbLogoDir + File.separator + file);
String md5 = Md5Helper.getMd5(usb_temp.getAbsolutePath());
usbPathFilesHashMap.put(usb_temp.getName(), md5);
}
} else {
return false;
}
File filesFile = new File(filesDir);
if (filesFile.exists()) {
Log.d("wujiang", "copyLogosToFilesDir: filesFile exists");
String[] filesPathFiles = filesFile.list();
File files_temp;
//得到files目录下所有图片的MD5值, 以文件名作为key, MD5值为value
for (String file : filesPathFiles) {
files_temp = new File(filesDir + File.separator + file);
String md5 = Md5Helper.getMd5(files_temp.getAbsolutePath());
filesPathFilesHashMap.put(files_temp.getName(), md5);
}
//查看files里的图片在usb里有无完全相同的图片
for (Map.Entry<String, String> entry : filesPathFilesHashMap.entrySet()) {
String fileName = entry.getKey();
String md5Value = entry.getValue();
String usbMd5Value = usbPathFilesHashMap.get(fileName);
if (!md5Value.equals(usbMd5Value)) {
FileUtils.copyFolder(usbLogoDir, filesDir);
return true;
}
}
} else {
FileUtils.copyFolder(usbLogoDir, filesDir);
return true;
}
} catch (Exception e) {
Log.d("wujiang", "copyLogosToFilesDir: error = " + e.getMessage());
}
Log.d("wujiang", "copyLogosToFilesDir: no need copy usb files to files path");
return false;
}