小米开源文件管理器MiCodeFileExplorer-源码研究(3)-使用最多的工具类Util

Util.java,使用最广泛~
代码中很多地方,都写了注释说明~基本不需要怎么解释了~

package net.micode.fileexplorer.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;

import net.micode.fileexplorer.FileViewActivity;
import net.micode.fileexplorer.GlobalConsts;
import net.micode.fileexplorer.R;
import net.micode.fileexplorer.model.FavoriteItem;
import net.micode.fileexplorer.model.FileInfo;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.util.Log;
import android.view.ActionMode;
import android.view.View;
import android.widget.TextView;
/**工具类,包含了很多通用的工具方法,被项目中的很多类调用。*/
public class Util {
	//这个文件夹里面存储的内容是app2sd产生的文件夹,也就是是你手机上所有安装到SD卡的应用程序的缓存文件夹。
	//androidsecure文件夹可以删除吗?
    //如果删除之后,软件不能正常使用,和系统没有关系。
	//删的话除了会可能导致移动至sd卡的程序损坏,数据丢失,并不会造成什么严重后果。只要把移动到sd卡的损坏程序卸载,重装,手机就完全没有损伤,文件夹也会在再次app2sd时自动重建的。
	private static String ANDROID_SECURE = "/mnt/sdcard/.android_secure";
    //android.util.Log.log第1个参数,用到“tag”,和log4j中Logger.getLogger(getClass())用法不太一样
	private static final String LOG_TAG = "Util";

	//获得SD卡的存储状态,“mounted”表示已经就绪
	public static boolean isSDCardReady() {
		return Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED);
	}

	// if path1 contains path2
	public static boolean containsPath(String path1, String path2) {
		String path = path2;
		while (path != null) {
			if (path.equalsIgnoreCase(path1))
				return true;

			if (path.equals(GlobalConsts.ROOT_PATH))
				break;
			path = new File(path).getParent();
		}

		return false;
	}

	//2个路径相加的时候,是否需要加上文件分隔符
	public static String makePath(String path1, String path2) {
		if (path1.endsWith(File.separator))
			return path1 + path2;

		return path1 + File.separator + path2;
	}

	//获得SD卡的存储目录
	public static String getSdDirectory() {
		return Environment.getExternalStorageDirectory().getPath();
	}

	//判断1个文件是否为“普通文件”,ANDROID_SECURE下的文件都不是普通的
	public static boolean isNormalFile(String fullName) {
		return !fullName.equals(ANDROID_SECURE);
	}

	//根据文件路径,获得Java文件File,再包装成FileInfo
	public static FileInfo GetFileInfo(String filePath) {
		File lFile = new File(filePath);
		if (!lFile.exists())
			return null;

		FileInfo lFileInfo = new FileInfo();
		lFileInfo.canRead = lFile.canRead();
		lFileInfo.canWrite = lFile.canWrite();
		lFileInfo.isHidden = lFile.isHidden();
		lFileInfo.fileName = Util.getNameFromFilepath(filePath);
		lFileInfo.ModifiedDate = lFile.lastModified();
		lFileInfo.IsDir = lFile.isDirectory();
		lFileInfo.filePath = filePath;
		lFileInfo.fileSize = lFile.length();
		return lFileInfo;
	}

	//根据File对象,和FilenameFilter等选项,获得包装的FileInfo
	//需要注意多少,如果File是个目录,Count就是当前目录下的文件的个数。如果是普通文件,就计算文件大小。
	//这个时候,我们知道Count字段的含义了
	public static FileInfo GetFileInfo(File f, FilenameFilter filter,
			boolean showHidden) {
		FileInfo lFileInfo = new FileInfo();
		String filePath = f.getPath();
		File lFile = new File(filePath);
		lFileInfo.canRead = lFile.canRead();
		lFileInfo.canWrite = lFile.canWrite();
		lFileInfo.isHidden = lFile.isHidden();
		lFileInfo.fileName = f.getName();
		lFileInfo.ModifiedDate = lFile.lastModified();
		lFileInfo.IsDir = lFile.isDirectory();
		lFileInfo.filePath = filePath;
		if (lFileInfo.IsDir) {
			int lCount = 0;
			File[] files = lFile.listFiles(filter);

			// null means we cannot access this dir
			if (files == null) {
				return null;
			}

			for (File child : files) {
				if ((!child.isHidden() || showHidden)
						&& Util.isNormalFile(child.getAbsolutePath())) {
					lCount++;
				}
			}
			lFileInfo.Count = lCount;

		} else {

			lFileInfo.fileSize = lFile.length();

		}
		return lFileInfo;
	}

	/*
	 * 采用了新的办法获取APK图标,之前的失败是因为android中存在的一个BUG,通过 appInfo.publicSourceDir =
	 * apkPath;来修正这个问题,详情参见:
	 * http://code.google.com/p/android/issues/detail?id=9151
	 */
	public static Drawable getApkIcon(Context context, String apkPath) {
		//Android系统为我们提供了很多服务管理类,包括ActivityManager、PowerManager(电源管理)、AudioManager(音频管理)。
		//PackageManager主要是管理应用程序包,通过它就可以获取应用程序信息
		PackageManager pm = context.getPackageManager();
		PackageInfo info = pm.getPackageArchiveInfo(apkPath,
				PackageManager.GET_ACTIVITIES);
		if (info != null) {
			ApplicationInfo appInfo = info.applicationInfo;
			appInfo.sourceDir = apkPath;
			appInfo.publicSourceDir = apkPath;
			try {
				return appInfo.loadIcon(pm);
			} catch (OutOfMemoryError e) {
				Log.e(LOG_TAG, e.toString());
			}
		}
		return null;
	}

	//获得文件的扩展名
	public static String getExtFromFilename(String filename) {
		int dotPosition = filename.lastIndexOf(‘.‘);
		if (dotPosition != -1) {
			return filename.substring(dotPosition + 1, filename.length());
		}
		return "";
	}

	//获得去掉“文件后缀”的文件名字,比如“C:/a/b/c.png”,输出“C:/a/b/c”
	public static String getNameFromFilename(String filename) {
		int dotPosition = filename.lastIndexOf(‘.‘);
		if (dotPosition != -1) {
			return filename.substring(0, dotPosition);
		}
		return "";
	}

    //从文件路径中,获得路径
	public static String getPathFromFilepath(String filepath) {
		int pos = filepath.lastIndexOf(‘/‘);
		if (pos != -1) {
			return filepath.substring(0, pos);
		}
		return "";
	}

	//从文件路径中,获得文件名(带后缀,如果有)
	public static String getNameFromFilepath(String filepath) {
		int pos = filepath.lastIndexOf(‘/‘);
		if (pos != -1) {
			return filepath.substring(pos + 1);
		}
		return "";
	}

	// return new file path if successful, or return null
	public static String copyFile(String src, String dest) {
		File file = new File(src);
		if (!file.exists() || file.isDirectory()) {
			Log.v(LOG_TAG, "copyFile: file not exist or is directory, " + src);
			return null;
		}
		FileInputStream fi = null;
		FileOutputStream fo = null;
		try {
			fi = new FileInputStream(file);
			File destPlace = new File(dest);
			if (!destPlace.exists()) {
				if (!destPlace.mkdirs())
					return null;
			}

			String destPath = Util.makePath(dest, file.getName());
			File destFile = new File(destPath);
			int i = 1;
			while (destFile.exists()) {
				String destName = Util.getNameFromFilename(file.getName())
						+ " " + i++ + "."
						+ Util.getExtFromFilename(file.getName());
				destPath = Util.makePath(dest, destName);
				destFile = new File(destPath);
			}

			if (!destFile.createNewFile())
				return null;

			fo = new FileOutputStream(destFile);
			int count = 102400;
			byte[] buffer = new byte[count];
			int read = 0;
			while ((read = fi.read(buffer, 0, count)) != -1) {
				fo.write(buffer, 0, read);
			}

			// TODO: set access privilege

			return destPath;
		} catch (FileNotFoundException e) {
			Log.e(LOG_TAG, "copyFile: file not found, " + src);
			e.printStackTrace();
		} catch (IOException e) {
			Log.e(LOG_TAG, "copyFile: " + e.toString());
		} finally {
			try {
				if (fi != null)
					fi.close();
				if (fo != null)
					fo.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return null;
	}

	// does not include sd card folder
	private static String[] SysFileDirs = new String[] { "miren_browser/imagecaches" };

	//判断一个文件是否需要显示,根据Setting中的设置。特别说明:某个系统文件目录,不显示。
	public static boolean shouldShowFile(String path) {
		return shouldShowFile(new File(path));
	}

	//判断一个文件是否需要显示,根据Setting中的设置。特别说明:某个系统文件目录,不显示。
	public static boolean shouldShowFile(File file) {
		boolean show = Settings.instance().getShowDotAndHiddenFiles();
		if (show)
			return true;

		if (file.isHidden())
			return false;

		if (file.getName().startsWith("."))
			return false;

		String sdFolder = getSdDirectory();
		for (String s : SysFileDirs) {
			if (file.getPath().startsWith(makePath(sdFolder, s)))
				return false;
		}

		return true;
	}

	//根据上下文对象Context,获得默认的收藏集合
	public static ArrayList<FavoriteItem> getDefaultFavorites(Context context) {
		ArrayList<FavoriteItem> list = new ArrayList<FavoriteItem>();
		list.add(new FavoriteItem(context.getString(R.string.favorite_photo),
				makePath(getSdDirectory(), "DCIM/Camera")));
		list.add(new FavoriteItem(context.getString(R.string.favorite_sdcard),
				getSdDirectory()));
		// list.add(new FavoriteItem(context.getString(R.string.favorite_root),
		// getSdDirectory()));
		list.add(new FavoriteItem(context
				.getString(R.string.favorite_screen_cap), makePath(
				getSdDirectory(), "MIUI/screen_cap")));
		list.add(new FavoriteItem(
				context.getString(R.string.favorite_ringtone), makePath(
						getSdDirectory(), "MIUI/ringtone")));
		return list;
	}

	//向View中的某个TextView设置文本
	public static boolean setText(View view, int id, String text) {
		TextView textView = (TextView) view.findViewById(id);
		if (textView == null)
			return false;

		textView.setText(text);
		return true;
	}

	//向View中的某个TextView设置文本
	public static boolean setText(View view, int id, int text) {
		TextView textView = (TextView) view.findViewById(id);
		if (textView == null)
			return false;

		textView.setText(text);
		return true;
	}

	// comma separated number
	public static String convertNumber(long number) {
		return String.format("%,d", number);
	}

	// storage, G M K B
	public static String convertStorage(long size) {
		long kb = 1024;
		long mb = kb * 1024;
		long gb = mb * 1024;

		if (size >= gb) {
			return String.format("%.1f GB", (float) size / gb);
		} else if (size >= mb) {
			float f = (float) size / mb;
			return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
		} else if (size >= kb) {
			float f = (float) size / kb;
			return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
		} else
			return String.format("%d B", size);
	}

	public static class SDCardInfo {
		public long total;

		public long free;
	}

	//获得SD卡的各种信息,总容量大小和剩余容量大小等
	public static SDCardInfo getSDCardInfo() {
		String sDcString = android.os.Environment.getExternalStorageState();

		if (sDcString.equals(android.os.Environment.MEDIA_MOUNTED)) {
			File pathFile = android.os.Environment
					.getExternalStorageDirectory();

			try {
				android.os.StatFs statfs = new android.os.StatFs(
						pathFile.getPath());

				// 获取SDCard上BLOCK总数
				long nTotalBlocks = statfs.getBlockCount();

				// 获取SDCard上每个block的SIZE
				long nBlocSize = statfs.getBlockSize();

				// 获取可供程序使用的Block的数量
				long nAvailaBlock = statfs.getAvailableBlocks();

				// 获取剩下的所有Block的数量(包括预留的一般程序无法使用的块)
				long nFreeBlock = statfs.getFreeBlocks();

				SDCardInfo info = new SDCardInfo();
				// 计算SDCard 总容量大小MB
				info.total = nTotalBlocks * nBlocSize;

				// 计算 SDCard 剩余大小MB
				info.free = nAvailaBlock * nBlocSize;

				return info;
			} catch (IllegalArgumentException e) {
				Log.e(LOG_TAG, e.toString());
			}
		}

		return null;
	}

	//显示一条系统通知
	public static void showNotification(Context context, Intent intent,
			String title, String body, int drawableId) {
		NotificationManager manager = (NotificationManager) context
				.getSystemService(Context.NOTIFICATION_SERVICE);
		Notification notification = new Notification(drawableId, body,
				System.currentTimeMillis());
		notification.flags = Notification.FLAG_AUTO_CANCEL;
		notification.defaults = Notification.DEFAULT_SOUND;
		if (intent == null) {
			// FIXEME: category tab is disabled
			intent = new Intent(context, FileViewActivity.class);
		}
		PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
				intent, PendingIntent.FLAG_ONE_SHOT);
		notification.setLatestEventInfo(context, title, body, contentIntent);
		manager.notify(drawableId, notification);
	}

	//格式化毫秒格式的时间
	public static String formatDateString(Context context, long time) {
		DateFormat dateFormat = android.text.format.DateFormat
				.getDateFormat(context);
		DateFormat timeFormat = android.text.format.DateFormat
				.getTimeFormat(context);
		Date date = new Date(time);
		return dateFormat.format(date) + " " + timeFormat.format(date);
	}

	public static void updateActionModeTitle(ActionMode mode, Context context,
			int selectedNum) {
		if (mode != null) {
			mode.setTitle(context.getString(R.string.multi_select_title,
					selectedNum));
			if (selectedNum == 0) {
				mode.finish();
			}
		}
	}

	//MimeType
	public static HashSet<String> sDocMimeTypesSet = new HashSet<String>() {
		{
			add("text/plain");
			add("text/plain");
			add("application/pdf");
			add("application/msword");
			add("application/vnd.ms-excel");
			add("application/vnd.ms-excel");
		}
	};

	public static String sZipFileMimeType = "application/zip";

	public static int CATEGORY_TAB_INDEX = 0;
	public static int SDCARD_TAB_INDEX = 1;
}

遇到一个奇怪的问题,为了验证某个函数,写了个main函数执行,结果发生了奇葩事项~

在Java环境下的工程中执行以下代码,正常输出。

public class Test {
	public static void main(String[] args) {
			System.out.println(getNameFromFilename("C:/a/b/c.png"));
		}
	public static String getNameFromFilename(String filename) {
		int dotPosition = filename.lastIndexOf(‘.‘);
		if (dotPosition != -1) {
			return filename.substring(0, dotPosition);
		}
		return "";
	}
}

打印“C:/a/b/c”

在Android环境下的工程中,竟然直接把JVM搞崩溃了,不明所以啊~
Invalid layout of java.lang.String at value
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (javaClasses.cpp:129), pid=8236, tid=3188
#  fatal error: Invalid layout of preloaded class
#
# JRE version: 7.0_17-b02
# Java VM: Java HotSpot(TM) 64-Bit Server VM (23.7-b01 mixed mode windows-amd64 compressed oops)
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# J:\AndroidCenter\MiCodeFileExplorer\hs_err_pid8236.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.sun.com/bugreport/crash.jsp
#

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-15 08:19:41

小米开源文件管理器MiCodeFileExplorer-源码研究(3)-使用最多的工具类Util的相关文章

小米开源文件管理器MiCodeFileExplorer初步研究

2011年对着书本Android应用开发揭秘,写了2个月的HelloWorld. 现在想复习并深入,我没有耐心再去一点点地敲代码了. 4年前自己是个学生,实习,现在有工作,只能业余时间研究. 这一点是非常不同的. 我希望通过研究别人的"成熟产品",更好地全面学习. 以目标为导向,具体来说,通过研究别人的一个产品,进而全面掌握,在研究的过程中, 把若干问题都解决了,从而达成"快速进步"的目标. 我们学习Java,学习Android开发,不是为了玩玩而已,也不能紧紧是&

小米开源文件管理器MiCodeFileExplorer-源码研究(1)-2个模型Model

上篇说到,把小米的Java代码整理成了5个包,其中1个是net.micode.fileexplorer.model.这个包就2个模型类,最基本了,FileInfo和FavoriteItem. package net.micode.fileexplorer.model; /** 抽象了一个文件最基本的信息 */ public class FileInfo { // 文件名 public String fileName; // 文件路径 public String filePath; // 文件大小

小米开源文件管理器MiCodeFileExplorer-源码研究(6)-媒体文件MediaFile和文件类型MimeUtils

接着之前的第4篇,本篇的2个类,仍然是工具类.MediaFile,媒体文件,定义了一大堆的常量,真正的有用的方法就几个.isAudioFileType.isVideoFileType之类的. MimeUtils,文件类型工具类,定义了一大堆的   add("application/zip", "zip");   某种扩展格式,对应的mime类型.   通过阅读代码观察到的2点现象,我有2点猜测:现象1.注释是英文的,很溜的那种~2.好多方法没有被本项目使用.  Ct

小米开源文件管理器MiCodeFileExplorer-源码研究(3)-2个单实例工具类

从本篇开始,讲解net.micode.fileexplorer.util工具包中的类.这个包下的类,功能也比较单一和独立.很多代码的思想和实现,可以用于JavaWeb和Android等多种环境中. 一.单实例活动管理器ActivitiesManager一个单实例的活动管理器,从方法的被调用程度来看,"徒有其名".registerActivity注册活动方法被使用了,而getActivity没有被使用,感觉明显有问题啊~我目前的猜测:大概是查看文件的时候,就会新建立一个活动,并且注册保存

Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)----&gt;第5节: 同线程回收对象

Netty源码分析第八章: 高性能工具类FastThreadLocal和Recycler 第五节: 同线程回收对象 上一小节剖析了从recycler中获取一个对象, 这一小节分析在创建和回收是同线程的前提下, recycler是如何进行回收的 回顾第三小节的demo中的main方法: public static void main(String[] args){ User user1 = RECYCLER.get(); user1.recycle(); User user2 = RECYCLER

Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)----&gt;第6节: 异线程回收对象

Netty源码分析第八章: 高性能工具类FastThreadLocal和Recycler 第六节: 异线程回收对象 异线程回收对象, 就是创建对象和回收对象不在同一条线程的情况下, 对象回收的逻辑 我们之前小节简单介绍过, 异线程回收对象, 是不会放在当前线程的stack中的, 而是放在一个WeakOrderQueue的数据结构中, 回顾我们之前的一个图: 8-6-1 相关的逻辑, 我们跟到源码中: 首先从回收对象的入口方法开始, DefualtHandle的recycle方法: public

小米开源文件管理器MiCodeFileExplorer-源码研究(9)-入口分析

AndroidManifest.xml是Android应用程序最重要的配置文件. 入口文件和intent-filter <application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@android:style/Theme.Holo.Light" android:uiOptions="splitActionBar

小米开源文件管理器MiCodeFileExplorer-源码研究(4)-文件操作工具类FileOperationHelper

文件操作是非常通用的,注释都写在源代码中了,不多说~需要特别说明的是,任务的异步执行和IOperationProgressListener.拷贝和删除等操作,是比较费时的,采用了异步执行的方式~ Android异步执行,我也是初次了解,在CSDN上找了一篇文章,后续写个单独的例子,单独写1篇介绍.http://blog.csdn.net/xufenghappy6/article/details/7343899异步执行+事件通知 是一种比较流行的模式,比同步等待很多时候要好. 另外,特别需要说明的

Android开源项目 Universal imageloader 源码研究之项目框架

Universal imageloader 的代码并不复杂 重点是缓存,线程池任务 下面都用UML图进行了绘制 基本使用流程就是 初始化配置,设置Options参数,最后Dispaly提交下载 public static void initImageLoader(Context context) { ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(context); config.thr