Android知识大全

来源:互联网 发布:最小的windows平板 编辑:程序博客网 时间:2024/05/02 04:22
@ayw2016-11-24 11:36字数 174355 阅读20

tools

系统 基础知识 tool


Windows系统相关


项目默认路径Kies3下载的临时文件C:\Users\kevin\AppData\Local\Tempwindows10的hosts文件C:\Windows\System32\drivers\etcWindows检测笔记本电池健康情况命令powercfg –energyJDKC:\Program Files\Java\jdk1.8.0_91\JREC:\Program Files\Java\jre1.8.0_91vimvimtutor
windows10默认的host文件内容
  1. # Copyright (c) 1993-2009 Microsoft Corp.
  2. #
  3. # This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
  4. #
  5. # This file contains the mappings of IP addresses to host names. Each
  6. # entry should be kept on an individual line. The IP address should
  7. # be placed in the first column followed by the corresponding host name.
  8. # The IP address and the host name should be separated by at least one
  9. # space.
  10. #
  11. # Additionally, comments (such as these) may be inserted on individual
  12. # lines or following the machine name denoted by a '#' symbol.
  13. #
  14. # For example:
  15. #
  16. # 102.54.94.97 rhino.acme.com # source server
  17. # 38.25.63.10 x.acme.com # x client host
  18. # localhost name resolution is handled within DNS itself.
  19. # 127.0.0.1 localhost
  20. # ::1 localhost

Chrome相关

插件

  • Momentu
  • Save to Pocket
  • OneTab
  • Page Ruler
  • Octotree
  • Postman
  • ChromeADB
  • Vysor
  • Dribbble New Tab
  • Clearly
  • LastPass

Android Utils 相关


ActivityUtils

  1. package com.blankj.utilcode.utils;
  2. import android.content.Context;
  3. import android.content.Intent;
  4. import android.os.Bundle;
  5. /**
  6. * <pre>
  7. * author: Blankj
  8. * blog : http://blankj.com
  9. * time : 2016/9/23
  10. * desc : Activity工具类
  11. * </pre>
  12. */
  13. public class ActivityUtils {
  14. private ActivityUtils() {
  15. throw new UnsupportedOperationException("u can't fuck me...");
  16. }
  17. /**
  18. * 判断是否存在指定Activity
  19. *
  20. * @param context 上下文
  21. * @param packageName 包名
  22. * @param className activity全路径类名
  23. * @return {@code true}: 是<br>{@code false}: 否
  24. */
  25. public static boolean isExistActivity(Context context, String packageName, String className) {
  26. Intent intent = new Intent();
  27. intent.setClassName(packageName, className);
  28. return !(context.getPackageManager().resolveActivity(intent, 0) == null ||
  29. intent.resolveActivity(context.getPackageManager()) == null ||
  30. context.getPackageManager().queryIntentActivities(intent, 0).size() == 0);
  31. }
  32. /**
  33. * 打开指定的Activity
  34. *
  35. * @param context 上下文
  36. * @param packageName 包名
  37. * @param className 全类名
  38. */
  39. public static void launchActivity(Context context, String packageName, String className) {
  40. launchActivity(context, packageName, className, null);
  41. }
  42. /**
  43. * 打开指定的Activity
  44. *
  45. * @param context 上下文
  46. * @param packageName 包名
  47. * @param className 全类名
  48. * @param bundle bundle
  49. */
  50. public static void launchActivity(Context context, String packageName, String className, Bundle bundle) {
  51. context.startActivity(IntentUtils.getComponentNameIntent(packageName, className, bundle));
  52. }
  53. }

AppUtils

  1. package com.blankj.utilcode.utils;
  2. import android.app.ActivityManager;
  3. import android.content.ComponentName;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.content.pm.ApplicationInfo;
  7. import android.content.pm.PackageInfo;
  8. import android.content.pm.PackageManager;
  9. import android.graphics.drawable.Drawable;
  10. import android.net.Uri;
  11. import android.os.Build;
  12. import android.webkit.MimeTypeMap;
  13. import java.io.File;
  14. import java.util.ArrayList;
  15. import java.util.List;
  16. /**
  17. * <pre>
  18. * author: Blankj
  19. * blog : http://blankj.com
  20. * time : 2016/8/2
  21. * desc : App相关工具类
  22. * </pre>
  23. */
  24. public class AppUtils {
  25. private AppUtils() {
  26. throw new UnsupportedOperationException("u can't fuck me...");
  27. }
  28. /**
  29. * 获取安装App(支持6.0)的意图
  30. *
  31. * @param filePath 文件路径
  32. * @return 意图
  33. */
  34. public static Intent getInstallAppIntent(String filePath) {
  35. return getInstallAppIntent(FileUtils.getFileByPath(filePath));
  36. }
  37. /**
  38. * 获取安装App(支持6.0)的意图
  39. *
  40. * @param file 文件
  41. * @return 意图
  42. */
  43. public static Intent getInstallAppIntent(File file) {
  44. if (file == null) return null;
  45. Intent intent = new Intent(Intent.ACTION_VIEW);
  46. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  47. String type;
  48. if (Build.VERSION.SDK_INT < 23) {
  49. type = "application/vnd.android.package-archive";
  50. } else {
  51. type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(FileUtils.getFileExtension(file));
  52. }
  53. return intent.setDataAndType(Uri.fromFile(file), type);
  54. }
  55. /**
  56. * 获取卸载App的意图
  57. *
  58. * @param packageName 包名
  59. * @return 意图
  60. */
  61. public Intent getUninstallAppIntent(String packageName) {
  62. Intent intent = new Intent(Intent.ACTION_DELETE);
  63. intent.setData(Uri.parse("package:" + packageName));
  64. return intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  65. }
  66. /**
  67. * 获取打开App的意图
  68. *
  69. * @param context 上下文
  70. * @param packageName 包名
  71. * @return 意图
  72. */
  73. public static Intent getLaunchAppItent(Context context, String packageName) {
  74. return getIntentByPackageName(context, packageName);
  75. }
  76. /**
  77. * 获取App信息的意图
  78. *
  79. * @param packageName 包名
  80. * @return 意图
  81. */
  82. public static Intent getAppInfoIntent(String packageName) {
  83. Intent intent = new Intent("android.settings.APPLICATION_DETAILS_SETTINGS");
  84. return intent.setData(Uri.parse("package:" + packageName));
  85. }
  86. /**
  87. * 获取App信息分享的意图
  88. *
  89. * @param info 分享信息
  90. * @return 意图
  91. */
  92. public static Intent getShareInfoIntent(String info) {
  93. Intent intent = new Intent(Intent.ACTION_SEND);
  94. intent.setType("text/plain");
  95. return intent.putExtra(Intent.EXTRA_TEXT, info);
  96. }
  97. /**
  98. * 判断App是否安装
  99. *
  100. * @param context 上下文
  101. * @param packageName 包名
  102. * @return {@code true}: 已安装<br>{@code false}: 未安装
  103. */
  104. public static boolean isInstallApp(Context context, String packageName) {
  105. return getIntentByPackageName(context, packageName) != null;
  106. }
  107. /**
  108. * 根据包名获取意图
  109. *
  110. * @param context 上下文
  111. * @param packageName 包名
  112. * @return Intent
  113. */
  114. private static Intent getIntentByPackageName(Context context, String packageName) {
  115. return context.getPackageManager().getLaunchIntentForPackage(packageName);
  116. }
  117. /**
  118. * 封装App信息的Bean类
  119. */
  120. public static class AppInfo {
  121. private String name;
  122. private Drawable icon;
  123. private String packageName;
  124. private String packagePath;
  125. private String versionName;
  126. private int versionCode;
  127. private boolean isSD;
  128. private boolean isUser;
  129. public Drawable getIcon() {
  130. return icon;
  131. }
  132. public void setIcon(Drawable icon) {
  133. this.icon = icon;
  134. }
  135. public boolean isSD() {
  136. return isSD;
  137. }
  138. public void setSD(boolean SD) {
  139. isSD = SD;
  140. }
  141. public boolean isUser() {
  142. return isUser;
  143. }
  144. public void setUser(boolean user) {
  145. isUser = user;
  146. }
  147. public String getName() {
  148. return name;
  149. }
  150. public void setName(String name) {
  151. this.name = name;
  152. }
  153. public String getPackageName() {
  154. return packageName;
  155. }
  156. public void setPackageName(String packagName) {
  157. this.packageName = packagName;
  158. }
  159. public String getPackagePath() {
  160. return packagePath;
  161. }
  162. public void setPackagePath(String packagePath) {
  163. this.packagePath = packagePath;
  164. }
  165. public int getVersionCode() {
  166. return versionCode;
  167. }
  168. public void setVersionCode(int versionCode) {
  169. this.versionCode = versionCode;
  170. }
  171. public String getVersionName() {
  172. return versionName;
  173. }
  174. public void setVersionName(String versionName) {
  175. this.versionName = versionName;
  176. }
  177. /**
  178. * @param name 名称
  179. * @param icon 图标
  180. * @param packageName 包名
  181. * @param packagePath 包路径
  182. * @param versionName 版本号
  183. * @param versionCode 版本Code
  184. * @param isSD 是否安装在SD卡
  185. * @param isUser 是否是用户程序
  186. */
  187. public AppInfo(String name, Drawable icon, String packageName, String packagePath,
  188. String versionName, int versionCode, boolean isSD, boolean isUser) {
  189. this.setName(name);
  190. this.setIcon(icon);
  191. this.setPackageName(packageName);
  192. this.setPackagePath(packagePath);
  193. this.setVersionName(versionName);
  194. this.setVersionCode(versionCode);
  195. this.setSD(isSD);
  196. this.setUser(isUser);
  197. }
  198. // @Override
  199. // public String toString() {
  200. // return getName() + "\n"
  201. // + getIcon() + "\n"
  202. // + getPackageName() + "\n"
  203. // + getPackagePath() + "\n"
  204. // + getVersionName() + "\n"
  205. // + getVersionCode() + "\n"
  206. // + isSD() + "\n"
  207. // + isUser() + "\n";
  208. // }
  209. }
  210. /**
  211. * 获取当前App信息
  212. * <p>AppInfo(名称,图标,包名,版本号,版本Code,是否安装在SD卡,是否是用户程序)</p>
  213. *
  214. * @param context 上下文
  215. * @return 当前应用的AppInfo
  216. */
  217. public static AppInfo getAppInfo(Context context) {
  218. PackageManager pm = context.getPackageManager();
  219. PackageInfo pi = null;
  220. try {
  221. pi = pm.getPackageInfo(context.getApplicationContext().getPackageName(), 0);
  222. } catch (PackageManager.NameNotFoundException e) {
  223. e.printStackTrace();
  224. }
  225. return pi != null ? getBean(pm, pi) : null;
  226. }
  227. /**
  228. * 得到AppInfo的Bean
  229. *
  230. * @param pm 包的管理
  231. * @param pi 包的信息
  232. * @return AppInfo类
  233. */
  234. private static AppInfo getBean(PackageManager pm, PackageInfo pi) {
  235. ApplicationInfo ai = pi.applicationInfo;
  236. String name = ai.loadLabel(pm).toString();
  237. Drawable icon = ai.loadIcon(pm);
  238. String packageName = pi.packageName;
  239. String packagePath = ai.sourceDir;
  240. String versionName = pi.versionName;
  241. int versionCode = pi.versionCode;
  242. boolean isSD = (ApplicationInfo.FLAG_SYSTEM & ai.flags) != ApplicationInfo.FLAG_SYSTEM;
  243. boolean isUser = (ApplicationInfo.FLAG_SYSTEM & ai.flags) != ApplicationInfo.FLAG_SYSTEM;
  244. return new AppInfo(name, icon, packageName, packagePath, versionName, versionCode, isSD, isUser);
  245. }
  246. /**
  247. * 获取所有已安装App信息
  248. * <p>{@link #getBean(PackageManager, PackageInfo)}(名称,图标,包名,包路径,版本号,版本Code,是否安装在SD卡,是否是用户程序)</p>
  249. * <p>依赖上面的getBean方法</p>
  250. *
  251. * @param context 上下文
  252. * @return 所有已安装的AppInfo列表
  253. */
  254. public static List<AppInfo> getAllAppsInfo(Context context) {
  255. List<AppInfo> list = new ArrayList<>();
  256. PackageManager pm = context.getPackageManager();
  257. // 获取系统中安装的所有软件信息
  258. List<PackageInfo> installedPackages = pm.getInstalledPackages(0);
  259. for (PackageInfo pi : installedPackages) {
  260. if (pi != null) {
  261. list.add(getBean(pm, pi));
  262. }
  263. }
  264. return list;
  265. }
  266. /**
  267. * 判断当前App处于前台还是后台
  268. * <p>需添加权限 {@code <uses-permission android:name="android.permission.GET_TASKS"/>}</p>
  269. * <p>并且必须是系统应用该方法才有效</p>
  270. *
  271. * @param context 上下文
  272. * @return {@code true}: 后台<br>{@code false}: 前台
  273. */
  274. public static boolean isAppBackground(Context context) {
  275. ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
  276. @SuppressWarnings("deprecation")
  277. List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
  278. if (!tasks.isEmpty()) {
  279. ComponentName topActivity = tasks.get(0).topActivity;
  280. if (!topActivity.getPackageName().equals(context.getPackageName())) {
  281. return true;
  282. }
  283. }
  284. return false;
  285. }
  286. }

BarUtils

  1. package com.blankj.utilcode.utils;
  2. import android.app.Activity;
  3. import android.content.Context;
  4. import android.os.Build;
  5. import android.util.TypedValue;
  6. import android.view.Window;
  7. import android.view.WindowManager;
  8. import java.lang.reflect.Method;
  9. /**
  10. * <pre>
  11. * author: Blankj
  12. * blog : http://blankj.com
  13. * time : 2016/9/23
  14. * desc : 栏相关工具类
  15. * </pre>
  16. */
  17. public class BarUtils {
  18. private BarUtils() {
  19. throw new UnsupportedOperationException("u can't fuck me...");
  20. }
  21. /**
  22. * 设置透明状态栏(api大于19方可使用)
  23. * <p>可在Activity的onCreat()中调用</p>
  24. * <p>需在顶部控件布局中加入以下属性让内容出现在状态栏之下</p>
  25. * <p>android:clipToPadding="true"</p>
  26. * <p>android:fitsSystemWindows="true"</p>
  27. *
  28. * @param activity activity
  29. */
  30. public static void setTransparentStatusBar(Activity activity) {
  31. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  32. //透明状态栏
  33. activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
  34. //透明导航栏
  35. activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
  36. }
  37. }
  38. /**
  39. * 隐藏状态栏
  40. * <p>也就是设置全屏,一定要在setContentView之前调用,否则报错</p>
  41. * <p>此方法Activity可以继承AppCompatActivity</p>
  42. * <p>启动的时候状态栏会显示一下再隐藏,比如QQ的欢迎界面</p>
  43. * <p>在配置文件中Activity加属性android:theme="@android:style/Theme.NoTitleBar.Fullscreen"</p>
  44. * <p>如加了以上配置Activity不能继承AppCompatActivity,会报错</p>
  45. *
  46. * @param activity activity
  47. */
  48. public static void hideStatusBar(Activity activity) {
  49. activity.requestWindowFeature(Window.FEATURE_NO_TITLE);
  50. activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  51. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  52. }
  53. /**
  54. * 获取状态栏高度
  55. *
  56. * @param context 上下文
  57. * @return 状态栏高度
  58. */
  59. public static int getStatusBarHeight(Context context) {
  60. int result = 0;
  61. int resourceId = context.getResources()
  62. .getIdentifier("status_bar_height", "dimen", "android");
  63. if (resourceId > 0) {
  64. result = context.getResources().getDimensionPixelSize(resourceId);
  65. }
  66. return result;
  67. }
  68. /**
  69. * 判断状态栏是否存在
  70. *
  71. * @param activity activity
  72. * @return {@code true}: 存在<br>{@code false}: 不存在
  73. */
  74. public static boolean isStatusBarExists(Activity activity) {
  75. WindowManager.LayoutParams params = activity.getWindow().getAttributes();
  76. return (params.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != WindowManager.LayoutParams.FLAG_FULLSCREEN;
  77. }
  78. /**
  79. * 获取ActionBar高度
  80. *
  81. * @param activity activity
  82. * @return ActionBar高度
  83. */
  84. public static int getActionBarHeight(Activity activity) {
  85. TypedValue tv = new TypedValue();
  86. if (activity.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
  87. return TypedValue.complexToDimensionPixelSize(tv.data, activity.getResources().getDisplayMetrics());
  88. }
  89. return 0;
  90. }
  91. /**
  92. * 显示通知栏
  93. * <p>需添加权限 {@code <uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>}</p>
  94. *
  95. * @param context 上下文
  96. * @param isSettingPanel {@code true}: 打开设置<br>{@code false}: 打开通知
  97. */
  98. public static void showNotificationBar(Context context, boolean isSettingPanel) {
  99. String methodName = (Build.VERSION.SDK_INT <= 16) ? "expand"
  100. : (isSettingPanel ? "expandSettingsPanel" : "expandNotificationsPanel");
  101. invokePanels(context, methodName);
  102. }
  103. /**
  104. * 隐藏通知栏
  105. * <p>需添加权限 {@code <uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>}</p>
  106. *
  107. * @param context 上下文
  108. */
  109. public static void hideNotificationBar(Context context) {
  110. String methodName = (Build.VERSION.SDK_INT <= 16) ? "collapse" : "collapsePanels";
  111. invokePanels(context, methodName);
  112. }
  113. /**
  114. * 反射唤醒通知栏
  115. *
  116. * @param context 上下文
  117. * @param methodName 方法名
  118. */
  119. private static void invokePanels(Context context, String methodName) {
  120. try {
  121. Object service = context.getSystemService("statusbar");
  122. Class<?> statusBarManager = Class.forName("android.app.StatusBarManager");
  123. Method expand = statusBarManager.getMethod(methodName);
  124. expand.invoke(service);
  125. } catch (Exception e) {
  126. e.printStackTrace();
  127. }
  128. }
  129. }

CameraUtils

  1. package com.blankj.utilcode.utils;
  2. import android.app.Activity;
  3. import android.content.ContentResolver;
  4. import android.content.Intent;
  5. import android.database.Cursor;
  6. import android.graphics.Bitmap;
  7. import android.net.Uri;
  8. import android.os.Bundle;
  9. import android.provider.MediaStore;
  10. import java.io.File;
  11. import java.io.IOException;
  12. /**
  13. * <pre>
  14. * author: Blankj
  15. * blog : http://blankj.com
  16. * time : 2016/9/19
  17. * desc : 相机相关工具类
  18. * </pre>
  19. */
  20. public class CameraUtils {
  21. private CameraUtils() {
  22. throw new UnsupportedOperationException("u can't fuck me...");
  23. }
  24. /**
  25. * 获取打开照程序界面的Intent
  26. */
  27. public static Intent getOpenCameraIntent() {
  28. return new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  29. }
  30. /**
  31. * 获取跳转至相册选择界面的Intent
  32. */
  33. public static Intent getImagePickerIntent() {
  34. Intent intent = new Intent(Intent.ACTION_PICK, null);
  35. return intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
  36. }
  37. /**
  38. * 获取[跳转至相册选择界面,并跳转至裁剪界面,默认可缩放裁剪区域]的Intent
  39. */
  40. public static Intent getImagePickerIntent(int outputX, int outputY, Uri fromFileURI,
  41. Uri saveFileURI) {
  42. return getImagePickerIntent(1, 1, outputX, outputY, true, fromFileURI, saveFileURI);
  43. }
  44. /**
  45. * 获取[跳转至相册选择界面,并跳转至裁剪界面,默认可缩放裁剪区域]的Intent
  46. */
  47. public static Intent getImagePickerIntent(int aspectX, int aspectY, int outputX, int outputY, Uri fromFileURI,
  48. Uri saveFileURI) {
  49. return getImagePickerIntent(aspectX, aspectY, outputX, outputY, true, fromFileURI, saveFileURI);
  50. }
  51. /**
  52. * 获取[跳转至相册选择界面,并跳转至裁剪界面,可以指定是否缩放裁剪区域]的Intent
  53. *
  54. * @param aspectX 裁剪框尺寸比例X
  55. * @param aspectY 裁剪框尺寸比例Y
  56. * @param outputX 输出尺寸宽度
  57. * @param outputY 输出尺寸高度
  58. * @param canScale 是否可缩放
  59. * @param fromFileURI 文件来源路径URI
  60. * @param saveFileURI 输出文件路径URI
  61. */
  62. public static Intent getImagePickerIntent(int aspectX, int aspectY, int outputX, int outputY, boolean canScale,
  63. Uri fromFileURI, Uri saveFileURI) {
  64. Intent intent = new Intent(Intent.ACTION_PICK);
  65. intent.setDataAndType(fromFileURI, "image/*");
  66. intent.putExtra("crop", "true");
  67. intent.putExtra("aspectX", aspectX <= 0 ? 1 : aspectX);
  68. intent.putExtra("aspectY", aspectY <= 0 ? 1 : aspectY);
  69. intent.putExtra("outputX", outputX);
  70. intent.putExtra("outputY", outputY);
  71. intent.putExtra("scale", canScale);
  72. // 图片剪裁不足黑边解决
  73. intent.putExtra("scaleUpIfNeeded", true);
  74. intent.putExtra("return-data", false);
  75. intent.putExtra(MediaStore.EXTRA_OUTPUT, saveFileURI);
  76. intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
  77. // 去除人脸识别
  78. return intent.putExtra("noFaceDetection", true);
  79. }
  80. /**
  81. * 获取[跳转至相册选择界面,并跳转至裁剪界面,默认可缩放裁剪区域]的Intent
  82. */
  83. public static Intent getCameraIntent(Uri saveFileURI) {
  84. Intent mIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  85. return mIntent.putExtra(MediaStore.EXTRA_OUTPUT, saveFileURI);
  86. }
  87. /**
  88. * 获取[跳转至裁剪界面,默认可缩放]的Intent
  89. */
  90. public static Intent getCropImageIntent(int outputX, int outputY, Uri fromFileURI,
  91. Uri saveFileURI) {
  92. return getCropImageIntent(1, 1, outputX, outputY, true, fromFileURI, saveFileURI);
  93. }
  94. /**
  95. * 获取[跳转至裁剪界面,默认可缩放]的Intent
  96. */
  97. public static Intent getCropImageIntent(int aspectX, int aspectY, int outputX, int outputY, Uri fromFileURI,
  98. Uri saveFileURI) {
  99. return getCropImageIntent(aspectX, aspectY, outputX, outputY, true, fromFileURI, saveFileURI);
  100. }
  101. /**
  102. * 获取[跳转至裁剪界面]的Intent
  103. */
  104. public static Intent getCropImageIntent(int aspectX, int aspectY, int outputX, int outputY, boolean canScale,
  105. Uri fromFileURI, Uri saveFileURI) {
  106. Intent intent = new Intent("com.android.camera.action.CROP");
  107. intent.setDataAndType(fromFileURI, "image/*");
  108. intent.putExtra("crop", "true");
  109. // X方向上的比例
  110. intent.putExtra("aspectX", aspectX <= 0 ? 1 : aspectX);
  111. // Y方向上的比例
  112. intent.putExtra("aspectY", aspectY <= 0 ? 1 : aspectY);
  113. intent.putExtra("outputX", outputX);
  114. intent.putExtra("outputY", outputY);
  115. intent.putExtra("scale", canScale);
  116. // 图片剪裁不足黑边解决
  117. intent.putExtra("scaleUpIfNeeded", true);
  118. intent.putExtra("return-data", false);
  119. // 需要将读取的文件路径和裁剪写入的路径区分,否则会造成文件0byte
  120. intent.putExtra(MediaStore.EXTRA_OUTPUT, saveFileURI);
  121. // true-->返回数据类型可以设置为Bitmap,但是不能传输太大,截大图用URI,小图用Bitmap或者全部使用URI
  122. intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
  123. // 取消人脸识别功能
  124. intent.putExtra("noFaceDetection", true);
  125. return intent;
  126. }
  127. /**
  128. * 获得选中相册的图片
  129. *
  130. * @param context 上下文
  131. * @param data onActivityResult返回的Intent
  132. * @return bitmap
  133. */
  134. public static Bitmap getChoosedImage(Activity context, Intent data) {
  135. if (data == null) return null;
  136. Bitmap bm = null;
  137. ContentResolver cr = context.getContentResolver();
  138. Uri originalUri = data.getData();
  139. try {
  140. bm = MediaStore.Images.Media.getBitmap(cr, originalUri);
  141. } catch (IOException e) {
  142. e.printStackTrace();
  143. }
  144. return bm;
  145. }
  146. /**
  147. * 获得选中相册的图片路径
  148. *
  149. * @param context 上下文
  150. * @param data onActivityResult返回的Intent
  151. * @return
  152. */
  153. public static String getChoosedImagePath(Activity context, Intent data) {
  154. if (data == null) return null;
  155. String path = "";
  156. ContentResolver resolver = context.getContentResolver();
  157. Uri originalUri = data.getData();
  158. if (null == originalUri) return null;
  159. String[] projection = {MediaStore.Images.Media.DATA};
  160. Cursor cursor = resolver.query(originalUri, projection, null, null, null);
  161. if (null != cursor) {
  162. try {
  163. int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
  164. cursor.moveToFirst();
  165. path = cursor.getString(column_index);
  166. } catch (IllegalArgumentException e) {
  167. e.printStackTrace();
  168. } finally {
  169. try {
  170. if (!cursor.isClosed()) {
  171. cursor.close();
  172. }
  173. } catch (Exception e) {
  174. e.printStackTrace();
  175. }
  176. }
  177. }
  178. return StringUtils.isEmpty(path) ? originalUri.getPath() : null;
  179. }
  180. /**
  181. * 获取拍照之后的照片文件(JPG格式)
  182. *
  183. * @param data onActivityResult回调返回的数据
  184. * @param filePath 文件路径
  185. * @return 文件
  186. */
  187. public static File getTakePictureFile(Intent data, String filePath) {
  188. if (data == null) return null;
  189. Bundle extras = data.getExtras();
  190. if (extras == null) return null;
  191. Bitmap photo = extras.getParcelable("data");
  192. File file = new File(filePath);
  193. if (ImageUtils.save(photo, file, Bitmap.CompressFormat.JPEG)) return file;
  194. return null;
  195. }
  196. }

ConstUtils

  1. package com.blankj.utilcode.utils;
  2. /**
  3. * <pre>
  4. * author: Blankj
  5. * blog : http://blankj.com
  6. * time : 2016/8/11
  7. * desc : 常量相关工具类
  8. * </pre>
  9. */
  10. public class ConstUtils {
  11. private ConstUtils() {
  12. throw new UnsupportedOperationException("u can't fuck me...");
  13. }
  14. /******************** 存储相关常量 ********************/
  15. /**
  16. * Byte与Byte的倍数
  17. */
  18. public static final int BYTE = 1;
  19. /**
  20. * KB与Byte的倍数
  21. */
  22. public static final int KB = 1024;
  23. /**
  24. * MB与Byte的倍数
  25. */
  26. public static final int MB = 1048576;
  27. /**
  28. * GB与Byte的倍数
  29. */
  30. public static final int GB = 1073741824;
  31. public enum MemoryUnit {
  32. BYTE,
  33. KB,
  34. MB,
  35. GB
  36. }
  37. /******************** 时间相关常量 ********************/
  38. /**
  39. * 毫秒与毫秒的倍数
  40. */
  41. public static final int MSEC = 1;
  42. /**
  43. * 秒与毫秒的倍数
  44. */
  45. public static final int SEC = 1000;
  46. /**
  47. * 分与毫秒的倍数
  48. */
  49. public static final int MIN = 60000;
  50. /**
  51. * 时与毫秒的倍数
  52. */
  53. public static final int HOUR = 3600000;
  54. /**
  55. * 天与毫秒的倍数
  56. */
  57. public static final int DAY = 86400000;
  58. public enum TimeUnit {
  59. MSEC,
  60. SEC,
  61. MIN,
  62. HOUR,
  63. DAY
  64. }
  65. /******************** 正则相关常量 ********************/
  66. /**
  67. * 正则:手机号(简单)
  68. */
  69. public static final String REGEX_MOBILE_SIMPLE = "^[1]\\d{10}$";
  70. /**
  71. * 正则:手机号(精确)
  72. * <p>移动:134(0-8)、135、136、137、138、139、147、150、151、152、157、158、159、178、182、183、184、187、188</p>
  73. * <p>联通:130、131、132、145、155、156、175、176、185、186</p>
  74. * <p>电信:133、153、173、177、180、181、189</p>
  75. * <p>全球星:1349</p>
  76. * <p>虚拟运营商:170</p>
  77. */
  78. public static final String REGEX_MOBILE_EXACT = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|(147))\\d{8}$";
  79. /**
  80. * 正则:电话号码
  81. */
  82. public static final String REGEX_TEL = "^0\\d{2,3}[- ]?\\d{7,8}";
  83. /**
  84. * 正则:身份证号码15位
  85. */
  86. public static final String REGEX_IDCARD15 = "^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$";
  87. /**
  88. * 正则:身份证号码18位
  89. */
  90. public static final String REGEX_IDCARD18 = "^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9Xx])$";
  91. /**
  92. * 正则:邮箱
  93. */
  94. public static final String REGEX_EMAIL = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$";
  95. /**
  96. * 正则:URL
  97. */
  98. public static final String REGEX_URL = "http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?";
  99. /**
  100. * 正则:汉字
  101. */
  102. public static final String REGEX_CHZ = "^[\\u4e00-\\u9fa5]+$";
  103. /**
  104. * 正则:用户名,取值范围为a-z,A-Z,0-9,"_",汉字,不能以"_"结尾,用户名必须是6-20位
  105. */
  106. public static final String REGEX_USERNAME = "^[\\w\\u4e00-\\u9fa5]{6,20}(?<!_)$";
  107. /**
  108. * 正则:yyyy-MM-dd格式的日期校验,已考虑平闰年
  109. */
  110. public static final String REGEX_DATE = "^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$";
  111. /**
  112. * 正则:IP地址
  113. */
  114. public static final String REGEX_IP = "((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)";
  115. }

ConvertUtils

  1. package com.blankj.utilcode.utils;
  2. import android.content.Context;
  3. import android.content.res.Resources;
  4. import android.graphics.Bitmap;
  5. import android.graphics.BitmapFactory;
  6. import android.graphics.drawable.BitmapDrawable;
  7. import android.graphics.drawable.Drawable;
  8. import java.io.ByteArrayInputStream;
  9. import java.io.ByteArrayOutputStream;
  10. import java.io.IOException;
  11. import java.io.InputStream;
  12. import java.io.OutputStream;
  13. import java.io.UnsupportedEncodingException;
  14. import java.util.Locale;
  15. import static com.blankj.utilcode.utils.ConstUtils.BYTE;
  16. import static com.blankj.utilcode.utils.ConstUtils.GB;
  17. import static com.blankj.utilcode.utils.ConstUtils.KB;
  18. import static com.blankj.utilcode.utils.ConstUtils.MB;
  19. /**
  20. * <pre>
  21. * author: Blankj
  22. * blog : http://blankj.com
  23. * time : 2016/8/13
  24. * desc : 转换相关工具类
  25. * </pre>
  26. */
  27. public class ConvertUtils {
  28. static final char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
  29. /**
  30. * byteArr转hexString
  31. * <p>例如:</p>
  32. * bytes2HexString(new byte[] { 0, (byte) 0xa8 }) returns 00A8
  33. *
  34. * @param bytes byte数组
  35. * @return 16进制大写字符串
  36. */
  37. public static String bytes2HexString(byte[] bytes) {
  38. char[] ret = new char[bytes.length << 1];
  39. for (int i = 0, j = 0; i < bytes.length; i++) {
  40. ret[j++] = hexDigits[bytes[i] >>> 4 & 0x0f];
  41. ret[j++] = hexDigits[bytes[i] & 0x0f];
  42. }
  43. return new String(ret);
  44. }
  45. /**
  46. * hexString转byteArr
  47. * <p>例如:</p>
  48. * hexString2Bytes("00A8") returns { 0, (byte) 0xA8 }
  49. *
  50. * @param hexString 十六进制字符串
  51. * @return 字节数组
  52. */
  53. public static byte[] hexString2Bytes(String hexString) {
  54. int len = hexString.length();
  55. if (len % 2 != 0) {
  56. throw new IllegalArgumentException("长度不是偶数");
  57. }
  58. char[] hexBytes = hexString.toUpperCase().toCharArray();
  59. byte[] ret = new byte[len >>> 1];
  60. for (int i = 0; i < len; i += 2) {
  61. ret[i >> 1] = (byte) (hex2Dec(hexBytes[i]) << 4 | hex2Dec(hexBytes[i + 1]));
  62. }
  63. return ret;
  64. }
  65. /**
  66. * hexChar转int
  67. *
  68. * @param hexChar hex单个字节
  69. * @return 0..15
  70. */
  71. private static int hex2Dec(char hexChar) {
  72. if (hexChar >= '0' && hexChar <= '9') {
  73. return hexChar - '0';
  74. } else if (hexChar >= 'A' && hexChar <= 'F') {
  75. return hexChar - 'A' + 10;
  76. } else {
  77. throw new IllegalArgumentException();
  78. }
  79. }
  80. /**
  81. * charArr转byteArr
  82. *
  83. * @param chars 字符数组
  84. * @return 字节数组
  85. */
  86. public static byte[] chars2Bytes(char[] chars) {
  87. int len = chars.length;
  88. byte[] bytes = new byte[len];
  89. for (int i = 0; i < len; i++) {
  90. bytes[i] = (byte) (chars[i]);
  91. }
  92. return bytes;
  93. }
  94. /**
  95. * byteArr转charArr
  96. *
  97. * @param bytes 字节数组
  98. * @return 字符数组
  99. */
  100. public static char[] bytes2Chars(byte[] bytes) {
  101. int len = bytes.length;
  102. char[] chars = new char[len];
  103. for (int i = 0; i < len; i++) {
  104. chars[i] = (char) (bytes[i] & 0xff);
  105. }
  106. return chars;
  107. }
  108. /**
  109. * 字节数转以unit为单位的size
  110. *
  111. * @param byteNum 字节数
  112. * @param unit <ul>
  113. * <li>{@link ConstUtils.MemoryUnit#BYTE}: 字节</li>
  114. * <li>{@link ConstUtils.MemoryUnit#KB} : 千字节</li>
  115. * <li>{@link ConstUtils.MemoryUnit#MB} : 兆</li>
  116. * <li>{@link ConstUtils.MemoryUnit#GB} : GB</li>
  117. * </ul>
  118. * @return 以unit为单位的size
  119. */
  120. public static double byte2Size(long byteNum, ConstUtils.MemoryUnit unit) {
  121. if (byteNum < 0) return -1;
  122. switch (unit) {
  123. default:
  124. case BYTE:
  125. return (double) byteNum / BYTE;
  126. case KB:
  127. return (double) byteNum / KB;
  128. case MB:
  129. return (double) byteNum / MB;
  130. case GB:
  131. return (double) byteNum / GB;
  132. }
  133. }
  134. /**
  135. * 以unit为单位的size转字节数
  136. *
  137. * @param size 大小
  138. * @param unit <ul>
  139. * <li>{@link ConstUtils.MemoryUnit#BYTE}: 字节</li>
  140. * <li>{@link ConstUtils.MemoryUnit#KB} : 千字节</li>
  141. * <li>{@link ConstUtils.MemoryUnit#MB} : 兆</li>
  142. * <li>{@link ConstUtils.MemoryUnit#GB} : GB</li>
  143. * </ul>
  144. * @return 字节数
  145. */
  146. public static long size2Byte(long size, ConstUtils.MemoryUnit unit) {
  147. if (size < 0) return -1;
  148. switch (unit) {
  149. default:
  150. case BYTE:
  151. return size * BYTE;
  152. case KB:
  153. return size * KB;
  154. case MB:
  155. return size * MB;
  156. case GB:
  157. return size * GB;
  158. }
  159. }
  160. /**
  161. * 字节数转合适大小
  162. * <p>保留3位小数</p>
  163. *
  164. * @param byteNum 字节数
  165. * @return 1...1024 unit
  166. */
  167. public static String byte2FitSize(long byteNum) {
  168. if (byteNum < 0) {
  169. return "shouldn't be less than zero!";
  170. } else if (byteNum < KB) {
  171. return String.format(Locale.getDefault(), "%.3fB", (double) byteNum);
  172. } else if (byteNum < MB) {
  173. return String.format(Locale.getDefault(), "%.3fKB", (double) byteNum / KB);
  174. } else if (byteNum < GB) {
  175. return String.format(Locale.getDefault(), "%.3fMB", (double) byteNum / MB);
  176. } else {
  177. return String.format(Locale.getDefault(), "%.3fGB", (double) byteNum / GB);
  178. }
  179. }
  180. /**
  181. * inputStream转outputStream
  182. *
  183. * @param is 输入流
  184. * @return outputStream子类
  185. */
  186. public static ByteArrayOutputStream input2OutputStream(InputStream is) {
  187. if (is == null) return null;
  188. try {
  189. ByteArrayOutputStream os = new ByteArrayOutputStream();
  190. byte[] b = new byte[KB];
  191. int len;
  192. while ((len = is.read(b, 0, KB)) != -1) {
  193. os.write(b, 0, len);
  194. }
  195. return os;
  196. } catch (IOException e) {
  197. e.printStackTrace();
  198. return null;
  199. } finally {
  200. FileUtils.closeIO(is);
  201. }
  202. }
  203. /**
  204. * outputStream转inputStream
  205. *
  206. * @param out 输出流
  207. * @return inputStream子类
  208. */
  209. public ByteArrayInputStream output2InputStream(OutputStream out) {
  210. if (out == null) return null;
  211. return new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray());
  212. }
  213. /**
  214. * inputStream转byteArr
  215. *
  216. * @param is 输入流
  217. * @return 字节数组
  218. */
  219. public static byte[] inputStream2Bytes(InputStream is) {
  220. return input2OutputStream(is).toByteArray();
  221. }
  222. /**
  223. * byteArr转inputStream
  224. *
  225. * @param bytes 字节数组
  226. * @return 输入流
  227. */
  228. public static InputStream bytes2InputStream(byte[] bytes) {
  229. return new ByteArrayInputStream(bytes);
  230. }
  231. /**
  232. * outputStream转byteArr
  233. *
  234. * @param out 输出流
  235. * @return 字节数组
  236. */
  237. public static byte[] outputStream2Bytes(OutputStream out) {
  238. if (out == null) return null;
  239. return ((ByteArrayOutputStream) out).toByteArray();
  240. }
  241. /**
  242. * outputStream转byteArr
  243. *
  244. * @param bytes 字节数组
  245. * @return 字节数组
  246. */
  247. public static OutputStream bytes2OutputStream(byte[] bytes) {
  248. ByteArrayOutputStream os = null;
  249. try {
  250. os = new ByteArrayOutputStream();
  251. os.write(bytes);
  252. return os;
  253. } catch (IOException e) {
  254. e.printStackTrace();
  255. return null;
  256. } finally {
  257. FileUtils.closeIO(os);
  258. }
  259. }
  260. /**
  261. * inputStream转string按编码
  262. *
  263. * @param is 输入流
  264. * @param charsetName 编码格式
  265. * @return 字符串
  266. */
  267. public static String inputStream2String(InputStream is, String charsetName) {
  268. if (is == null || StringUtils.isSpace(charsetName)) return null;
  269. try {
  270. return new String(inputStream2Bytes(is), charsetName);
  271. } catch (UnsupportedEncodingException e) {
  272. e.printStackTrace();
  273. return null;
  274. }
  275. }
  276. /**
  277. * string转inputStream按编码
  278. *
  279. * @param string 字符串
  280. * @param charsetName 编码格式
  281. * @return 输入流
  282. */
  283. public static InputStream string2InputStream(String string, String charsetName) {
  284. if (string == null || StringUtils.isSpace(charsetName)) return null;
  285. try {
  286. return new ByteArrayInputStream(string.getBytes(charsetName));
  287. } catch (UnsupportedEncodingException e) {
  288. e.printStackTrace();
  289. return null;
  290. }
  291. }
  292. /**
  293. * outputStream转string按编码
  294. *
  295. * @param out 输出流
  296. * @param charsetName 编码格式
  297. * @return 字符串
  298. */
  299. public static String outputStream2String(OutputStream out, String charsetName) {
  300. if (out == null) return null;
  301. try {
  302. return new String(outputStream2Bytes(out), charsetName);
  303. } catch (UnsupportedEncodingException e) {
  304. e.printStackTrace();
  305. return null;
  306. }
  307. }
  308. /**
  309. * string转outputStream按编码
  310. *
  311. * @param string 字符串
  312. * @param charsetName 编码格式
  313. * @return 输入流
  314. */
  315. public static OutputStream string2OutputStream(String string, String charsetName) {
  316. if (string == null || StringUtils.isSpace(charsetName)) return null;
  317. try {
  318. return bytes2OutputStream(string.getBytes(charsetName));
  319. } catch (UnsupportedEncodingException e) {
  320. e.printStackTrace();
  321. return null;
  322. }
  323. }
  324. /**
  325. * bitmap转byteArr
  326. *
  327. * @param bitmap bitmap对象
  328. * @param format 格式
  329. * @return 字节数组
  330. */
  331. public static byte[] bitmap2Bytes(Bitmap bitmap, Bitmap.CompressFormat format) {
  332. if (bitmap == null) return null;
  333. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  334. bitmap.compress(format, 100, baos);
  335. return baos.toByteArray();
  336. }
  337. /**
  338. * byteArr转bitmap
  339. *
  340. * @param bytes 字节数组
  341. * @return bitmap对象
  342. */
  343. public static Bitmap bytes2Bitmap(byte[] bytes) {
  344. return (bytes == null || bytes.length == 0) ? null : BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
  345. }
  346. /**
  347. * drawable转bitmap
  348. *
  349. * @param drawable drawable对象
  350. * @return bitmap对象
  351. */
  352. public static Bitmap drawable2Bitmap(Drawable drawable) {
  353. return drawable == null ? null : ((BitmapDrawable) drawable).getBitmap();
  354. }
  355. /**
  356. * bitmap转drawable
  357. *
  358. * @param res resources对象
  359. * @param bitmap bitmap对象
  360. * @return drawable对象
  361. */
  362. public static Drawable bitmap2Drawable(Resources res, Bitmap bitmap) {
  363. return bitmap == null ? null : new BitmapDrawable(res, bitmap);
  364. }
  365. /**
  366. * drawable转byteArr
  367. *
  368. * @param drawable drawable对象
  369. * @param format 格式
  370. * @return 字节数组
  371. */
  372. public static byte[] drawable2Bytes(Drawable drawable, Bitmap.CompressFormat format) {
  373. return bitmap2Bytes(drawable2Bitmap(drawable), format);
  374. }
  375. /**
  376. * byteArr转drawable
  377. *
  378. * @param res resources对象
  379. * @param bytes 字节数组
  380. * @return drawable对象
  381. */
  382. public static Drawable bytes2Drawable(Resources res, byte[] bytes) {
  383. return bitmap2Drawable(res, bytes2Bitmap(bytes));
  384. }
  385. /**
  386. * dp转px
  387. *
  388. * @param context 上下文
  389. * @param dpValue dp值
  390. * @return px值
  391. */
  392. public static int dp2px(Context context, float dpValue) {
  393. final float scale = context.getResources().getDisplayMetrics().density;
  394. return (int) (dpValue * scale + 0.5f);
  395. }
  396. /**
  397. * px转dp
  398. *
  399. * @param context 上下文
  400. * @param pxValue px值
  401. * @return dp值
  402. */
  403. public static int px2dp(Context context, float pxValue) {
  404. final float scale = context.getResources().getDisplayMetrics().density;
  405. return (int) (pxValue / scale + 0.5f);
  406. }
  407. /**
  408. * sp转px
  409. *
  410. * @param context 上下文
  411. * @param spValue sp值
  412. * @return px值
  413. */
  414. public static int sp2px(Context context, float spValue) {
  415. final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
  416. return (int) (spValue * fontScale + 0.5f);
  417. }
  418. /**
  419. * px转sp
  420. *
  421. * @param context 上下文
  422. * @param pxValue px值
  423. * @return sp值
  424. */
  425. public static int px2sp(Context context, float pxValue) {
  426. final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
  427. return (int) (pxValue / fontScale + 0.5f);
  428. }
  429. }

DeviceUtils

  1. package com.blankj.utilcode.utils;
  2. import android.content.Context;
  3. import android.net.wifi.WifiInfo;
  4. import android.net.wifi.WifiManager;
  5. import android.os.Build;
  6. import java.io.IOException;
  7. import java.io.InputStreamReader;
  8. import java.io.LineNumberReader;
  9. /**
  10. * <pre>
  11. * author: Blankj
  12. * blog : http://blankj.com
  13. * time : 2016/8/1
  14. * desc : 设备相关工具类
  15. * </pre>
  16. */
  17. public class DeviceUtils {
  18. private DeviceUtils() {
  19. throw new UnsupportedOperationException("u can't fuck me...");
  20. }
  21. /**
  22. * 获取设备MAC地址
  23. * <p>需添加权限 {@code <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>}</p>
  24. *
  25. * @param context 上下文
  26. * @return MAC地址
  27. */
  28. public static String getMacAddress(Context context) {
  29. WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
  30. WifiInfo info = wifi.getConnectionInfo();
  31. if (info != null) {
  32. String macAddress = info.getMacAddress();
  33. if (macAddress != null) {
  34. return macAddress.replace(":", "");
  35. }
  36. }
  37. return null;
  38. }
  39. /**
  40. * 获取设备MAC地址
  41. * <p>需添加权限 {@code <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>}</p>
  42. *
  43. * @return MAC地址
  44. */
  45. public static String getMacAddress() {
  46. String macAddress = null;
  47. LineNumberReader lnr = null;
  48. InputStreamReader isr = null;
  49. try {
  50. Process pp = Runtime.getRuntime().exec("cat /sys/class/net/wlan0/address");
  51. isr = new InputStreamReader(pp.getInputStream());
  52. lnr = new LineNumberReader(isr);
  53. macAddress = lnr.readLine().replace(":", "");
  54. } catch (IOException e) {
  55. e.printStackTrace();
  56. } finally {
  57. FileUtils.closeIO(lnr, isr);
  58. }
  59. return macAddress == null ? "" : macAddress;
  60. }
  61. /**
  62. * 获取设备厂商,如Xiaomi
  63. *
  64. * @return 设备厂商
  65. */
  66. public static String getManufacturer() {
  67. return Build.MANUFACTURER;
  68. }
  69. /**
  70. * 获取设备型号,如MI2SC
  71. *
  72. * @return 设备型号
  73. */
  74. public static String getModel() {
  75. String model = Build.MODEL;
  76. if (model != null) {
  77. model = model.trim().replaceAll("\\s*", "");
  78. } else {
  79. model = "";
  80. }
  81. return model;
  82. }
  83. }

EncodeUtils

  1. package com.blankj.utilcode.utils;
  2. import android.os.Build;
  3. import android.text.Html;
  4. import android.util.Base64;
  5. import java.io.UnsupportedEncodingException;
  6. import java.net.URLDecoder;
  7. import java.net.URLEncoder;
  8. /**
  9. * <pre>
  10. * author: Blankj
  11. * blog : http://blankj.com
  12. * time : 2016/8/7
  13. * desc : 编码解码相关工具类
  14. * </pre>
  15. */
  16. public class EncodeUtils {
  17. private EncodeUtils() {
  18. throw new UnsupportedOperationException("u can't fuck me...");
  19. }
  20. /**
  21. * URL编码
  22. * <p>若想自己指定字符集,可以使用{@link #urlEncode(String input, String charset)}方法</p>
  23. *
  24. * @param input 要编码的字符
  25. * @return 编码为UTF-8的字符串
  26. */
  27. public static String urlEncode(String input) {
  28. return urlEncode(input, "UTF-8");
  29. }
  30. /**
  31. * URL编码
  32. * <p>若系统不支持指定的编码字符集,则直接将input原样返回</p>
  33. *
  34. * @param input 要编码的字符
  35. * @param charset 字符集
  36. * @return 编码为字符集的字符串
  37. */
  38. public static String urlEncode(String input, String charset) {
  39. try {
  40. return URLEncoder.encode(input, charset);
  41. } catch (UnsupportedEncodingException e) {
  42. return input;
  43. }
  44. }
  45. /**
  46. * URL解码
  47. * <p>若想自己指定字符集,可以使用 {@link #urlDecode(String input, String charset)}方法</p>
  48. *
  49. * @param input 要解码的字符串
  50. * @return URL解码后的字符串
  51. */
  52. public static String urlDecode(String input) {
  53. return urlDecode(input, "UTF-8");
  54. }
  55. /**
  56. * URL解码
  57. * <p>若系统不支持指定的解码字符集,则直接将input原样返回</p>
  58. *
  59. * @param input 要解码的字符串
  60. * @param charset 字符集
  61. * @return URL解码为指定字符集的字符串
  62. */
  63. public static String urlDecode(String input, String charset) {
  64. try {
  65. return URLDecoder.decode(input, charset);
  66. } catch (UnsupportedEncodingException e) {
  67. return input;
  68. }
  69. }
  70. /**
  71. * Base64编码
  72. *
  73. * @param input 要编码的字符串
  74. * @return Base64编码后的字符串
  75. */
  76. public static byte[] base64Encode(String input) {
  77. return base64Encode(input.getBytes());
  78. }
  79. /**
  80. * Base64编码
  81. *
  82. * @param input 要编码的字节数组
  83. * @return Base64编码后的字符串
  84. */
  85. public static byte[] base64Encode(byte[] input) {
  86. return Base64.encode(input, Base64.NO_WRAP);
  87. }
  88. /**
  89. * Base64编码
  90. *
  91. * @param input 要编码的字节数组
  92. * @return Base64编码后的字符串
  93. */
  94. public static String base64Encode2String(byte[] input) {
  95. return Base64.encodeToString(input, Base64.NO_WRAP);
  96. }
  97. /**
  98. * Base64解码
  99. *
  100. * @param input 要解码的字符串
  101. * @return Base64解码后的字符串
  102. */
  103. public static byte[] base64Decode(String input) {
  104. return Base64.decode(input, Base64.NO_WRAP);
  105. }
  106. /**
  107. * Base64解码
  108. *
  109. * @param input 要解码的字符串
  110. * @return Base64解码后的字符串
  111. */
  112. public static byte[] base64Decode(byte[] input) {
  113. return Base64.decode(input, Base64.NO_WRAP);
  114. }
  115. /**
  116. * Base64URL安全编码
  117. * <p>将Base64中的URL非法字符�?,/=转为其他字符, 见RFC3548</p>
  118. *
  119. * @param input 要Base64URL安全编码的字符串
  120. * @return Base64URL安全编码后的字符串
  121. */
  122. public static byte[] base64UrlSafeEncode(String input) {
  123. return Base64.encode(input.getBytes(), Base64.URL_SAFE);
  124. }
  125. /**
  126. * Html编码
  127. *
  128. * @param input 要Html编码的字符串
  129. * @return Html编码后的字符串
  130. */
  131. public static String htmlEncode(String input) {
  132. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
  133. return Html.escapeHtml(input);
  134. } else {
  135. // 参照Html.escapeHtml()中代码
  136. StringBuilder out = new StringBuilder();
  137. for (int i = 0, len = input.length(); i < len; i++) {
  138. char c = input.charAt(i);
  139. if (c == '<') {
  140. out.append("&lt;");
  141. } else if (c == '>') {
  142. out.append("&gt;");
  143. } else if (c == '&') {
  144. out.append("&amp;");
  145. } else if (c >= 0xD800 && c <= 0xDFFF) {
  146. if (c < 0xDC00 && i + 1 < len) {
  147. char d = input.charAt(i + 1);
  148. if (d >= 0xDC00 && d <= 0xDFFF) {
  149. i++;
  150. int codepoint = 0x010000 | (int) c - 0xD800 << 10 | (int) d - 0xDC00;
  151. out.append("&#").append(codepoint).append(";");
  152. }
  153. }
  154. } else if (c > 0x7E || c < ' ') {
  155. out.append("&#").append((int) c).append(";");
  156. } else if (c == ' ') {
  157. while (i + 1 < len && input.charAt(i + 1) == ' ') {
  158. out.append("&nbsp;");
  159. i++;
  160. }
  161. out.append(' ');
  162. } else {
  163. out.append(c);
  164. }
  165. }
  166. return out.toString();
  167. }
  168. }
  169. /**
  170. * Html解码
  171. *
  172. * @param input 待解码的字符串
  173. * @return Html解码后的字符串
  174. */
  175. public static String htmlDecode(String input) {
  176. return Html.fromHtml(input).toString();
  177. }
  178. }

EncryptUtils

  1. package com.blankj.utilcode.utils;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.IOException;
  5. import java.nio.MappedByteBuffer;
  6. import java.nio.channels.FileChannel;
  7. import java.security.MessageDigest;
  8. import java.security.NoSuchAlgorithmException;
  9. import java.security.SecureRandom;
  10. import javax.crypto.Cipher;
  11. import javax.crypto.spec.SecretKeySpec;
  12. import static com.blankj.utilcode.utils.ConvertUtils.*;
  13. /**
  14. * <pre>
  15. * author: Blankj
  16. * blog : http://blankj.com
  17. * time : 2016/8/2
  18. * desc : 加密解密相关的工具类
  19. * </pre>
  20. */
  21. public class EncryptUtils {
  22. private EncryptUtils() {
  23. throw new UnsupportedOperationException("u can't fuck me...");
  24. }
  25. /*********************** 哈希加密相关 ***********************/
  26. /**
  27. * MD2加密
  28. *
  29. * @param data 明文字符串
  30. * @return 16进制密文
  31. */
  32. public static String encryptMD2ToString(String data) {
  33. return encryptMD2ToString(data.getBytes());
  34. }
  35. /**
  36. * MD2加密
  37. *
  38. * @param data 明文字节数组
  39. * @return 16进制密文
  40. */
  41. public static String encryptMD2ToString(byte[] data) {
  42. return bytes2HexString(encryptMD2(data));
  43. }
  44. /**
  45. * MD2加密
  46. *
  47. * @param data 明文字节数组
  48. * @return 密文字节数组
  49. */
  50. public static byte[] encryptMD2(byte[] data) {
  51. return encryptAlgorithm(data, "MD2");
  52. }
  53. /**
  54. * MD5加密
  55. *
  56. * @param data 明文字符串
  57. * @return 16进制密文
  58. */
  59. public static String encryptMD5ToString(String data) {
  60. return encryptMD5ToString(data.getBytes());
  61. }
  62. /**
  63. * MD5加密
  64. *
  65. * @param data 明文字符串
  66. * @param salt 盐
  67. * @return 16进制加盐密文
  68. */
  69. public static String encryptMD5ToString(String data, String salt) {
  70. return bytes2HexString(encryptMD5((data + salt).getBytes()));
  71. }
  72. /**
  73. * MD5加密
  74. *
  75. * @param data 明文字节数组
  76. * @return 16进制密文
  77. */
  78. public static String encryptMD5ToString(byte[] data) {
  79. return bytes2HexString(encryptMD5(data));
  80. }
  81. /**
  82. * MD5加密
  83. *
  84. * @param data 明文字节数组
  85. * @param salt 盐字节数组
  86. * @return 16进制加盐密文
  87. */
  88. public static String encryptMD5ToString(byte[] data, byte[] salt) {
  89. byte[] dataSalt = new byte[data.length + salt.length];
  90. System.arraycopy(data, 0, dataSalt, 0, data.length);
  91. System.arraycopy(salt, 0, dataSalt, data.length, salt.length);
  92. return bytes2HexString(encryptMD5(dataSalt));
  93. }
  94. /**
  95. * MD5加密
  96. *
  97. * @param data 明文字节数组
  98. * @return 密文字节数组
  99. */
  100. public static byte[] encryptMD5(byte[] data) {
  101. return encryptAlgorithm(data, "MD5");
  102. }
  103. /**
  104. * MD5加密文件
  105. *
  106. * @param filePath 文件路径
  107. * @return 文件的16进制密文
  108. */
  109. public static String encryptMD5File2String(String filePath) {
  110. return encryptMD5File2String(new File(filePath));
  111. }
  112. /**
  113. * MD5加密文件
  114. *
  115. * @param filePath 文件路径
  116. * @return 文件的MD5校验码
  117. */
  118. public static byte[] encryptMD5File(String filePath) {
  119. return encryptMD5File(new File(filePath));
  120. }
  121. /**
  122. * MD5加密文件
  123. *
  124. * @param file 文件
  125. * @return 文件的16进制密文
  126. */
  127. public static String encryptMD5File2String(File file) {
  128. return encryptMD5File(file) != null ? bytes2HexString(encryptMD5File(file)) : "";
  129. }
  130. /**
  131. * MD5加密文件
  132. *
  133. * @param file 文件
  134. * @return 文件的MD5校验码
  135. */
  136. public static byte[] encryptMD5File(File file) {
  137. FileInputStream fis = null;
  138. try {
  139. fis = new FileInputStream(file);
  140. FileChannel channel = fis.getChannel();
  141. MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
  142. MessageDigest md = MessageDigest.getInstance("MD5");
  143. md.update(buffer);
  144. return md.digest();
  145. } catch (NoSuchAlgorithmException | IOException e) {
  146. e.printStackTrace();
  147. } finally {
  148. FileUtils.closeIO(fis);
  149. }
  150. return null;
  151. }
  152. /**
  153. * SHA1加密
  154. *
  155. * @param data 明文字符串
  156. * @return 16进制密文
  157. */
  158. public static String encryptSHA1ToString(String data) {
  159. return encryptSHA1ToString(data.getBytes());
  160. }
  161. /**
  162. * SHA1加密
  163. *
  164. * @param data 明文字节数组
  165. * @return 16进制密文
  166. */
  167. public static String encryptSHA1ToString(byte[] data) {
  168. return bytes2HexString(encryptSHA1(data));
  169. }
  170. /**
  171. * SHA1加密
  172. *
  173. * @param data 明文字节数组
  174. * @return 密文字节数组
  175. */
  176. public static byte[] encryptSHA1(byte[] data) {
  177. return encryptAlgorithm(data, "SHA-1");
  178. }
  179. /**
  180. * SHA224加密
  181. *
  182. * @param data 明文字符串
  183. * @return 16进制密文
  184. */
  185. public static String encryptSHA224ToString(String data) {
  186. return encryptSHA224ToString(data.getBytes());
  187. }
  188. /**
  189. * SHA224加密
  190. *
  191. * @param data 明文字节数组
  192. * @return 16进制密文
  193. */
  194. public static String encryptSHA224ToString(byte[] data) {
  195. return bytes2HexString(encryptSHA224(data));
  196. }
  197. /**
  198. * SHA224加密
  199. *
  200. * @param data 明文字节数组
  201. * @return 密文字节数组
  202. */
  203. public static byte[] encryptSHA224(byte[] data) {
  204. return encryptAlgorithm(data, "SHA-224");
  205. }
  206. /**
  207. * SHA256加密
  208. *
  209. * @param data 明文字符串
  210. * @return 16进制密文
  211. */
  212. public static String encryptSHA256ToString(String data) {
  213. return encryptSHA256ToString(data.getBytes());
  214. }
  215. /**
  216. * SHA256加密
  217. *
  218. * @param data 明文字节数组
  219. * @return 16进制密文
  220. */
  221. public static String encryptSHA256ToString(byte[] data) {
  222. return bytes2HexString(encryptSHA256(data));
  223. }
  224. /**
  225. * SHA256加密
  226. *
  227. * @param data 明文字节数组
  228. * @return 密文字节数组
  229. */
  230. public static byte[] encryptSHA256(byte[] data) {
  231. return encryptAlgorithm(data, "SHA-256");
  232. }
  233. /**
  234. * SHA384加密
  235. *
  236. * @param data 明文字符串
  237. * @return 16进制密文
  238. */
  239. public static String encryptSHA384ToString(String data) {
  240. return encryptSHA384ToString(data.getBytes());
  241. }
  242. /**
  243. * SHA384加密
  244. *
  245. * @param data 明文字节数组
  246. * @return 16进制密文
  247. */
  248. public static String encryptSHA384ToString(byte[] data) {
  249. return bytes2HexString(encryptSHA384(data));
  250. }
  251. /**
  252. * SHA384加密
  253. *
  254. * @param data 明文字节数组
  255. * @return 密文字节数组
  256. */
  257. public static byte[] encryptSHA384(byte[] data) {
  258. return encryptAlgorithm(data, "SHA-384");
  259. }
  260. /**
  261. * SHA512加密
  262. *
  263. * @param data 明文字符串
  264. * @return 16进制密文
  265. */
  266. public static String encryptSHA512ToString(String data) {
  267. return encryptSHA512ToString(data.getBytes());
  268. }
  269. /**
  270. * SHA512加密
  271. *
  272. * @param data 明文字节数组
  273. * @return 16进制密文
  274. */
  275. public static String encryptSHA512ToString(byte[] data) {
  276. return bytes2HexString(encryptSHA512(data));
  277. }
  278. /**
  279. * SHA512加密
  280. *
  281. * @param data 明文字节数组
  282. * @return 密文字节数组
  283. */
  284. public static byte[] encryptSHA512(byte[] data) {
  285. return encryptAlgorithm(data, "SHA-512");
  286. }
  287. /**
  288. * 对data进行algorithm算法加密
  289. *
  290. * @param data 明文字节数组
  291. * @param algorithm 加密算法
  292. * @return 密文字节数组
  293. */
  294. private static byte[] encryptAlgorithm(byte[] data, String algorithm) {
  295. try {
  296. MessageDigest md = MessageDigest.getInstance(algorithm);
  297. md.update(data);
  298. return md.digest();
  299. } catch (NoSuchAlgorithmException e) {
  300. e.printStackTrace();
  301. }
  302. return new byte[0];
  303. }
  304. /************************ DES加密相关 ***********************/
  305. /**
  306. * DES转变
  307. * <p>法算法名称/加密模式/填充方式</p>
  308. * <p>加密模式有:电子密码本模式ECB、加密块链模式CBC、加密反馈模式CFB、输出反馈模式OFB</p>
  309. * <p>填充方式有:NoPadding、ZerosPadding、PKCS5Padding</p>
  310. */
  311. public static String DES_Transformation = "DES/ECB/NoPadding";
  312. private static final String DES_Algorithm = "DES";
  313. /**
  314. * @param data 数据
  315. * @param key 秘钥
  316. * @param algorithm 采用何种DES算法
  317. * @param transformation 转变
  318. * @param isEncrypt 是否加密
  319. * @return 密文或者明文,适用于DES,3DES,AES
  320. */
  321. public static byte[] DESTemplet(byte[] data, byte[] key, String algorithm, String transformation, boolean isEncrypt) {
  322. try {
  323. SecretKeySpec keySpec = new SecretKeySpec(key, algorithm);
  324. Cipher cipher = Cipher.getInstance(transformation);
  325. SecureRandom random = new SecureRandom();
  326. cipher.init(isEncrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, keySpec, random);
  327. return cipher.doFinal(data);
  328. } catch (Throwable e) {
  329. e.printStackTrace();
  330. }
  331. return null;
  332. }
  333. /**
  334. * DES加密后转为Base64编码
  335. *
  336. * @param data 明文
  337. * @param key 8字节秘钥
  338. * @return Base64密文
  339. */
  340. public static byte[] encryptDES2Base64(byte[] data, byte[] key) {
  341. return EncodeUtils.base64Encode(encryptDES(data, key));
  342. }
  343. /**
  344. * DES加密后转为16进制
  345. *
  346. * @param data 明文
  347. * @param key 8字节秘钥
  348. * @return 16进制密文
  349. */
  350. public static String encryptDES2HexString(byte[] data, byte[] key) {
  351. return bytes2HexString(encryptDES(data, key));
  352. }
  353. /**
  354. * DES加密
  355. *
  356. * @param data 明文
  357. * @param key 8字节秘钥
  358. * @return 密文
  359. */
  360. public static byte[] encryptDES(byte[] data, byte[] key) {
  361. return DESTemplet(data, key, DES_Algorithm, DES_Transformation, true);
  362. }
  363. /**
  364. * DES解密Base64编码密文
  365. *
  366. * @param data Base64编码密文
  367. * @param key 8字节秘钥
  368. * @return 明文
  369. */
  370. public static byte[] decryptBase64DES(byte[] data, byte[] key) {
  371. return decryptDES(EncodeUtils.base64Decode(data), key);
  372. }
  373. /**
  374. * DES解密16进制密文
  375. *
  376. * @param data 16进制密文
  377. * @param key 8字节秘钥
  378. * @return 明文
  379. */
  380. public static byte[] decryptHexStringDES(String data, byte[] key) {
  381. return decryptDES(hexString2Bytes(data), key);
  382. }
  383. /**
  384. * DES解密
  385. *
  386. * @param data 密文
  387. * @param key 8字节秘钥
  388. * @return 明文
  389. */
  390. public static byte[] decryptDES(byte[] data, byte[] key) {
  391. return DESTemplet(data, key, DES_Algorithm, DES_Transformation, false);
  392. }
  393. /************************ 3DES加密相关 ***********************/
  394. /**
  395. * 3DES转变
  396. * <p>法算法名称/加密模式/填充方式</p>
  397. * <p>加密模式有:电子密码本模式ECB、加密块链模式CBC、加密反馈模式CFB、输出反馈模式OFB</p>
  398. * <p>填充方式有:NoPadding、ZerosPadding、PKCS5Padding</p>
  399. */
  400. public static String TripleDES_Transformation = "DESede/ECB/NoPadding";
  401. private static final String TripleDES_Algorithm = "DESede";
  402. /**
  403. * 3DES加密后转为Base64编码
  404. *
  405. * @param data 明文
  406. * @param key 24字节秘钥
  407. * @return Base64密文
  408. */
  409. public static byte[] encrypt3DES2Base64(byte[] data, byte[] key) {
  410. return EncodeUtils.base64Encode(encrypt3DES(data, key));
  411. }
  412. /**
  413. * 3DES加密后转为16进制
  414. *
  415. * @param data 明文
  416. * @param key 24字节秘钥
  417. * @return 16进制密文
  418. */
  419. public static String encrypt3DES2HexString(byte[] data, byte[] key) {
  420. return bytes2HexString(encrypt3DES(data, key));
  421. }
  422. /**
  423. * 3DES加密
  424. *
  425. * @param data 明文
  426. * @param key 24字节密钥
  427. * @return 密文
  428. */
  429. public static byte[] encrypt3DES(byte[] data, byte[] key) {
  430. return DESTemplet(data, key, TripleDES_Algorithm, TripleDES_Transformation, true);
  431. }
  432. /**
  433. * 3DES解密Base64编码密文
  434. *
  435. * @param data Base64编码密文
  436. * @param key 24字节秘钥
  437. * @return 明文
  438. */
  439. public static byte[] decryptBase64_3DES(byte[] data, byte[] key) {
  440. return decrypt3DES(EncodeUtils.base64Decode(data), key);
  441. }
  442. /**
  443. * 3DES解密16进制密文
  444. *
  445. * @param data 16进制密文
  446. * @param key 24字节秘钥
  447. * @return 明文
  448. */
  449. public static byte[] decryptHexString3DES(String data, byte[] key) {
  450. return decrypt3DES(hexString2Bytes(data), key);
  451. }
  452. /**
  453. * 3DES解密
  454. *
  455. * @param data 密文
  456. * @param key 24字节密钥
  457. * @return 明文
  458. */
  459. public static byte[] decrypt3DES(byte[] data, byte[] key) {
  460. return DESTemplet(data, key, TripleDES_Algorithm, TripleDES_Transformation, false);
  461. }
  462. /************************ AES加密相关 ***********************/
  463. /**
  464. * AES转变
  465. * <p>法算法名称/加密模式/填充方式</p>
  466. * <p>加密模式有:电子密码本模式ECB、加密块链模式CBC、加密反馈模式CFB、输出反馈模式OFB</p>
  467. * <p>填充方式有:NoPadding、ZerosPadding、PKCS5Padding</p>
  468. */
  469. public static String AES_Transformation = "AES/ECB/NoPadding";
  470. private static final String AES_Algorithm = "AES";
  471. /**
  472. * AES加密后转为Base64编码
  473. *
  474. * @param data 明文
  475. * @param key 16、24、32字节秘钥
  476. * @return Base64密文
  477. */
  478. public static byte[] encryptAES2Base64(byte[] data, byte[] key) {
  479. return EncodeUtils.base64Encode(encryptAES(data, key));
  480. }
  481. /**
  482. * AES加密后转为16进制
  483. *
  484. * @param data 明文
  485. * @param key 16、24、32字节秘钥
  486. * @return 16进制密文
  487. */
  488. public static String encryptAES2HexString(byte[] data, byte[] key) {
  489. return bytes2HexString(encryptAES(data, key));
  490. }
  491. /**
  492. * AES加密
  493. *
  494. * @param data 明文
  495. * @param key 16、24、32字节秘钥
  496. * @return 密文
  497. */
  498. public static byte[] encryptAES(byte[] data, byte[] key) {
  499. return DESTemplet(data, key, AES_Algorithm, AES_Transformation, true);
  500. }
  501. /**
  502. * AES解密Base64编码密文
  503. *
  504. * @param data Base64编码密文
  505. * @param key 16、24、32字节秘钥
  506. * @return 明文
  507. */
  508. public static byte[] decryptBase64AES(byte[] data, byte[] key) {
  509. return decryptAES(EncodeUtils.base64Decode(data), key);
  510. }
  511. /**
  512. * AES解密16进制密文
  513. *
  514. * @param data 16进制密文
  515. * @param key 16、24、32字节秘钥
  516. * @return 明文
  517. */
  518. public static byte[] decryptHexStringAES(String data, byte[] key) {
  519. return decryptAES(hexString2Bytes(data), key);
  520. }
  521. /**
  522. * AES解密
  523. *
  524. * @param data 密文
  525. * @param key 16、24、32字节秘钥
  526. * @return 明文
  527. */
  528. public static byte[] decryptAES(byte[] data, byte[] key) {
  529. return DESTemplet(data, key, AES_Algorithm, AES_Transformation, false);
  530. }
  531. }

FileUtils

  1. package com.blankj.utilcode.utils;
  2. import java.io.BufferedInputStream;
  3. import java.io.BufferedOutputStream;
  4. import java.io.BufferedReader;
  5. import java.io.Closeable;
  6. import java.io.File;
  7. import java.io.FileInputStream;
  8. import java.io.FileNotFoundException;
  9. import java.io.FileOutputStream;
  10. import java.io.FileReader;
  11. import java.io.FileWriter;
  12. import java.io.FilenameFilter;
  13. import java.io.IOException;
  14. import java.io.InputStream;
  15. import java.io.InputStreamReader;
  16. import java.io.OutputStream;
  17. import java.util.ArrayList;
  18. import java.util.Collections;
  19. import java.util.List;
  20. import static com.blankj.utilcode.utils.ConstUtils.*;
  21. /**
  22. * <pre>
  23. * author: Blankj
  24. * blog : http://blankj.com
  25. * time : 2016/8/11
  26. * desc : 文件相关工具类
  27. * </pre>
  28. */
  29. public class FileUtils {
  30. private FileUtils() {
  31. throw new UnsupportedOperationException("u can't fuck me...");
  32. }
  33. /**
  34. * 根据文件路径获取文件
  35. *
  36. * @param filePath 文件路径
  37. * @return 文件
  38. */
  39. public static File getFileByPath(String filePath) {
  40. return StringUtils.isSpace(filePath) ? null : new File(filePath);
  41. }
  42. /**
  43. * 判断文件是否存在
  44. *
  45. * @param filePath 文件路径
  46. * @return {@code true}: 存在<br>{@code false}: 不存在
  47. */
  48. public static boolean isFileExists(String filePath) {
  49. return isFileExists(getFileByPath(filePath));
  50. }
  51. /**
  52. * 判断文件是否存在
  53. *
  54. * @param file 文件
  55. * @return {@code true}: 存在<br>{@code false}: 不存在
  56. */
  57. public static boolean isFileExists(File file) {
  58. return file != null && file.exists();
  59. }
  60. /**
  61. * 判断是否是目录
  62. *
  63. * @param dirPath 目录路径
  64. * @return {@code true}: 是<br>{@code false}: 否
  65. */
  66. public static boolean isDir(String dirPath) {
  67. return isDir(getFileByPath(dirPath));
  68. }
  69. /**
  70. * 判断是否是目录
  71. *
  72. * @param file 文件
  73. * @return {@code true}: 是<br>{@code false}: 否
  74. */
  75. public static boolean isDir(File file) {
  76. return isFileExists(file) && file.isDirectory();
  77. }
  78. /**
  79. * 判断是否是文件
  80. *
  81. * @param filePath 文件路径
  82. * @return {@code true}: 是<br>{@code false}: 否
  83. */
  84. public static boolean isFile(String filePath) {
  85. return isFile(getFileByPath(filePath));
  86. }
  87. /**
  88. * 判断是否是文件
  89. *
  90. * @param file 文件
  91. * @return {@code true}: 是<br>{@code false}: 否
  92. */
  93. public static boolean isFile(File file) {
  94. return isFileExists(file) && file.isFile();
  95. }
  96. /**
  97. * 判断目录是否存在,不存在则判断是否创建成功
  98. *
  99. * @param dirPath 文件路径
  100. * @return {@code true}: 存在或创建成功<br>{@code false}: 不存在或创建失败
  101. */
  102. public static boolean createOrExistsDir(String dirPath) {
  103. return createOrExistsDir(getFileByPath(dirPath));
  104. }
  105. /**
  106. * 判断目录是否存在,不存在则判断是否创建成功
  107. *
  108. * @param file 文件
  109. * @return {@code true}: 存在或创建成功<br>{@code false}: 不存在或创建失败
  110. */
  111. public static boolean createOrExistsDir(File file) {
  112. // 如果存在,是目录则返回true,是文件则返回false,不存在则返回是否创建成功
  113. return file != null && (file.exists() ? file.isDirectory() : file.mkdirs());
  114. }
  115. /**
  116. * 判断文件是否存在,不存在则判断是否创建成功
  117. *
  118. * @param filePath 文件路径
  119. * @return {@code true}: 存在或创建成功<br>{@code false}: 不存在或创建失败
  120. */
  121. public static boolean createOrExistsFile(String filePath) {
  122. return createOrExistsFile(getFileByPath(filePath));
  123. }
  124. /**
  125. * 判断文件是否存在,不存在则判断是否创建成功
  126. *
  127. * @param file 文件
  128. * @return {@code true}: 存在或创建成功<br>{@code false}: 不存在或创建失败
  129. */
  130. public static boolean createOrExistsFile(File file) {
  131. if (file == null) return false;
  132. // 如果存在,是文件则返回true,是目录则返回false
  133. if (file.exists()) return file.isFile();
  134. if (!createOrExistsDir(file.getParentFile())) return false;
  135. try {
  136. return file.createNewFile();
  137. } catch (IOException e) {
  138. e.printStackTrace();
  139. return false;
  140. }
  141. }
  142. /**
  143. * 判断文件是否存在,存在则在创建之前删除
  144. *
  145. * @param filePath 文件路径
  146. * @return {@code true}: 创建成功<br>{@code false}: 创建失败
  147. */
  148. public static boolean createFileByDeleteOldFile(String filePath) {
  149. return createFileByDeleteOldFile(getFileByPath(filePath));
  150. }
  151. /**
  152. * 判断文件是否存在,存在则在创建之前删除
  153. *
  154. * @param file 文件
  155. * @return {@code true}: 创建成功<br>{@code false}: 创建失败
  156. */
  157. public static boolean createFileByDeleteOldFile(File file) {
  158. if (file == null) return false;
  159. // 文件存在并且删除失败返回false
  160. if (file.exists() && file.isFile() && !file.delete()) return false;
  161. // 创建目录失败返回false
  162. if (!createOrExistsDir(file.getParentFile())) return false;
  163. try {
  164. return file.createNewFile();
  165. } catch (IOException e) {
  166. e.printStackTrace();
  167. return false;
  168. }
  169. }
  170. /**
  171. * 复制或移动目录
  172. *
  173. * @param srcDirPath 源目录路径
  174. * @param destDirPath 目标目录路径
  175. * @param isMove 是否移动
  176. * @return {@code true}: 复制或移动成功<br>{@code false}: 复制或移动失败
  177. */
  178. private static boolean copyOrMoveDir(String srcDirPath, String destDirPath, boolean isMove) {
  179. return copyOrMoveDir(getFileByPath(srcDirPath), getFileByPath(destDirPath), isMove);
  180. }
  181. /**
  182. * 复制或移动目录
  183. *
  184. * @param srcDir 源目录
  185. * @param destDir 目标目录
  186. * @param isMove 是否移动
  187. * @return {@code true}: 复制或移动成功<br>{@code false}: 复制或移动失败
  188. */
  189. private static boolean copyOrMoveDir(File srcDir, File destDir, boolean isMove) {
  190. if (srcDir == null || destDir == null) return false;
  191. // 如果目标目录在源目录中则返回false,看不懂的话好好想想递归怎么结束
  192. // srcPath : F:\\MyGithub\\AndroidUtilCode\\utilcode\\src\\test\\res
  193. // destPath: F:\\MyGithub\\AndroidUtilCode\\utilcode\\src\\test\\res1
  194. // 为防止以上这种情况出现出现误判,须分别在后面加个路径分隔符
  195. String srcPath = srcDir.getPath() + File.separator;
  196. String destPath = destDir.getPath() + File.separator;
  197. if (destPath.contains(srcPath)) return false;
  198. // 源文件不存在或者不是目录则返回false
  199. if (!srcDir.exists() || !srcDir.isDirectory()) return false;
  200. // 目标目录不存在返回false
  201. if (!createOrExistsDir(destDir)) return false;
  202. File[] files = srcDir.listFiles();
  203. for (File file : files) {
  204. File oneDestFile = new File(destPath + file.getName());
  205. if (file.isFile()) {
  206. // 如果操作失败返回false
  207. if (!copyOrMoveFile(file, oneDestFile, isMove)) return false;
  208. } else if (file.isDirectory()) {
  209. // 如果操作失败返回false
  210. if (!copyOrMoveDir(file, oneDestFile, isMove)) return false;
  211. }
  212. }
  213. return !isMove || deleteDir(srcDir);
  214. }
  215. /**
  216. * 复制或移动文件
  217. *
  218. * @param srcFilePath 源文件路径
  219. * @param destFilePath 目标文件路径
  220. * @param isMove 是否移动
  221. * @return {@code true}: 复制或移动成功<br>{@code false}: 复制或移动失败
  222. */
  223. private static boolean copyOrMoveFile(String srcFilePath, String destFilePath, boolean isMove) {
  224. return copyOrMoveFile(getFileByPath(srcFilePath), getFileByPath(destFilePath), isMove);
  225. }
  226. /**
  227. * 复制或移动文件
  228. *
  229. * @param srcFile 源文件
  230. * @param destFile 目标文件
  231. * @param isMove 是否移动
  232. * @return {@code true}: 复制或移动成功<br>{@code false}: 复制或移动失败
  233. */
  234. private static boolean copyOrMoveFile(File srcFile, File destFile, boolean isMove) {
  235. if (srcFile == null || destFile == null) return false;
  236. // 源文件不存在或者不是文件则返回false
  237. if (!srcFile.exists() || !srcFile.isFile()) return false;
  238. // 目标文件存在且是文件则返回false
  239. if (destFile.exists() && destFile.isFile()) return false;
  240. // 目标目录不存在返回false
  241. if (!createOrExistsDir(destFile.getParentFile())) return false;
  242. try {
  243. return writeFileFromIS(destFile, new FileInputStream(srcFile), false)
  244. && !(isMove && !deleteFile(srcFile));
  245. } catch (FileNotFoundException e) {
  246. e.printStackTrace();
  247. return false;
  248. }
  249. }
  250. /**
  251. * 复制目录
  252. *
  253. * @param srcDirPath 源目录路径
  254. * @param destDirPath 目标目录路径
  255. * @return {@code true}: 复制成功<br>{@code false}: 复制失败
  256. */
  257. public static boolean copyDir(String srcDirPath, String destDirPath) {
  258. return copyDir(getFileByPath(srcDirPath), getFileByPath(destDirPath));
  259. }
  260. /**
  261. * 复制目录
  262. *
  263. * @param srcDir 源目录
  264. * @param destDir 目标目录
  265. * @return {@code true}: 复制成功<br>{@code false}: 复制失败
  266. */
  267. public static boolean copyDir(File srcDir, File destDir) {
  268. return copyOrMoveDir(srcDir, destDir, false);
  269. }
  270. /**
  271. * 复制文件
  272. *
  273. * @param srcFilePath 源文件路径
  274. * @param destFilePath 目标文件路径
  275. * @return {@code true}: 复制成功<br>{@code false}: 复制失败
  276. */
  277. public static boolean copyFile(String srcFilePath, String destFilePath) {
  278. return copyFile(getFileByPath(srcFilePath), getFileByPath(destFilePath));
  279. }
  280. /**
  281. * 复制文件
  282. *
  283. * @param srcFile 源文件
  284. * @param destFile 目标文件
  285. * @return {@code true}: 复制成功<br>{@code false}: 复制失败
  286. */
  287. public static boolean copyFile(File srcFile, File destFile) {
  288. return copyOrMoveFile(srcFile, destFile, false);
  289. }
  290. /**
  291. * 移动目录
  292. *
  293. * @param srcDirPath 源目录路径
  294. * @param destDirPath 目标目录路径
  295. * @return {@code true}: 移动成功<br>{@code false}: 移动失败
  296. */
  297. public static boolean moveDir(String srcDirPath, String destDirPath) {
  298. return moveDir(getFileByPath(srcDirPath), getFileByPath(destDirPath));
  299. }
  300. /**
  301. * 移动目录
  302. *
  303. * @param srcDir 源目录
  304. * @param destDir 目标目录
  305. * @return {@code true}: 移动成功<br>{@code false}: 移动失败
  306. */
  307. public static boolean moveDir(File srcDir, File destDir) {
  308. return copyOrMoveDir(srcDir, destDir, true);
  309. }
  310. /**
  311. * 移动文件
  312. *
  313. * @param srcFilePath 源文件路径
  314. * @param destFilePath 目标文件路径
  315. * @return {@code true}: 移动成功<br>{@code false}: 移动失败
  316. */
  317. public static boolean moveFile(String srcFilePath, String destFilePath) {
  318. return moveFile(getFileByPath(srcFilePath), getFileByPath(destFilePath));
  319. }
  320. /**
  321. * 移动文件
  322. *
  323. * @param srcFile 源文件
  324. * @param destFile 目标文件
  325. * @return {@code true}: 移动成功<br>{@code false}: 移动失败
  326. */
  327. public static boolean moveFile(File srcFile, File destFile) {
  328. return copyOrMoveFile(srcFile, destFile, true);
  329. }
  330. /**
  331. * 删除目录
  332. *
  333. * @param dirPath 目录路径
  334. * @return {@code true}: 删除成功<br>{@code false}: 删除失败
  335. */
  336. public static boolean deleteDir(String dirPath) {
  337. return deleteDir(getFileByPath(dirPath));
  338. }
  339. /**
  340. * 删除目录
  341. *
  342. * @param dir 目录
  343. * @return {@code true}: 删除成功<br>{@code false}: 删除失败
  344. */
  345. public static boolean deleteDir(File dir) {
  346. if (dir == null) return false;
  347. // 目录不存在返回true
  348. if (!dir.exists()) return true;
  349. // 不是目录返回false
  350. if (!dir.isDirectory()) return false;
  351. // 现在文件存在且是文件夹
  352. File[] files = dir.listFiles();
  353. for (File file : files) {
  354. if (file.isFile()) {
  355. if (!deleteFile(file)) return false;
  356. } else if (file.isDirectory()) {
  357. if (!deleteDir(file)) return false;
  358. }
  359. }
  360. return dir.delete();
  361. }
  362. /**
  363. * 删除文件
  364. *
  365. * @param srcFilePath 文件路径
  366. * @return {@code true}: 删除成功<br>{@code false}: 删除失败
  367. */
  368. public static boolean deleteFile(String srcFilePath) {
  369. return deleteFile(getFileByPath(srcFilePath));
  370. }
  371. /**
  372. * 删除文件
  373. *
  374. * @param file 文件
  375. * @return {@code true}: 删除成功<br>{@code false}: 删除失败
  376. */
  377. public static boolean deleteFile(File file) {
  378. return file != null && (!file.exists() || file.isFile() && file.delete());
  379. }
  380. /**
  381. * 获取目录下所有文件
  382. *
  383. * @param dirPath 目录路径
  384. * @param isRecursive 是否递归进子目录
  385. * @return 文件链表
  386. */
  387. public static List<File> listFilesInDir(String dirPath, boolean isRecursive) {
  388. return listFilesInDir(getFileByPath(dirPath), isRecursive);
  389. }
  390. /**
  391. * 获取目录下所有文件
  392. *
  393. * @param dir 目录
  394. * @param isRecursive 是否递归进子目录
  395. * @return 文件链表
  396. */
  397. public static List<File> listFilesInDir(File dir, boolean isRecursive) {
  398. if (isRecursive) return listFilesInDir(dir);
  399. if (dir == null || !isDir(dir)) return null;
  400. List<File> list = new ArrayList<>();
  401. Collections.addAll(list, dir.listFiles());
  402. return list;
  403. }
  404. /**
  405. * 获取目录下所有文件包括子目录
  406. *
  407. * @param dirPath 目录路径
  408. * @return 文件链表
  409. */
  410. public static List<File> listFilesInDir(String dirPath) {
  411. return listFilesInDir(getFileByPath(dirPath));
  412. }
  413. /**
  414. * 获取目录下所有文件包括子目录
  415. *
  416. * @param dir 目录
  417. * @return 文件链表
  418. */
  419. public static List<File> listFilesInDir(File dir) {
  420. if (dir == null || !isDir(dir)) return null;
  421. List<File> list = new ArrayList<>();
  422. File[] files = dir.listFiles();
  423. for (File file : files) {
  424. list.add(file);
  425. if (file.isDirectory()) {
  426. list.addAll(listFilesInDir(file));
  427. }
  428. }
  429. return list;
  430. }
  431. /**
  432. * 获取目录下所有后缀名为suffix的文件
  433. * <p>大小写忽略</p>
  434. *
  435. * @param dirPath 目录路径
  436. * @param suffix 后缀名
  437. * @param isRecursive 是否递归进子目录
  438. * @return 文件链表
  439. */
  440. public static List<File> listFilesInDirWithFilter(String dirPath, String suffix, boolean isRecursive) {
  441. return listFilesInDirWithFilter(getFileByPath(dirPath), suffix, isRecursive);
  442. }
  443. /**
  444. * 获取目录下所有后缀名为suffix的文件
  445. * <p>大小写忽略</p>
  446. *
  447. * @param dir 目录
  448. * @param suffix 后缀名
  449. * @param isRecursive 是否递归进子目录
  450. * @return 文件链表
  451. */
  452. public static List<File> listFilesInDirWithFilter(File dir, String suffix, boolean isRecursive) {
  453. if (isRecursive) return listFilesInDirWithFilter(dir, suffix);
  454. if (dir == null || !isDir(dir)) return null;
  455. List<File> list = new ArrayList<>();
  456. File[] files = dir.listFiles();
  457. for (File file : files) {
  458. if (file.getName().toUpperCase().endsWith(suffix.toUpperCase())) {
  459. list.add(file);
  460. }
  461. }
  462. return list;
  463. }
  464. /**
  465. * 获取目录下所有后缀名为suffix的文件包括子目录
  466. * <p>大小写忽略</p>
  467. *
  468. * @param dirPath 目录路径
  469. * @param suffix 后缀名
  470. * @return 文件链表
  471. */
  472. public static List<File> listFilesInDirWithFilter(String dirPath, String suffix) {
  473. return listFilesInDirWithFilter(getFileByPath(dirPath), suffix);
  474. }
  475. /**
  476. * 获取目录下所有后缀名为suffix的文件包括子目录
  477. * <p>大小写忽略</p>
  478. *
  479. * @param dir 目录
  480. * @param suffix 后缀名
  481. * @return 文件链表
  482. */
  483. public static List<File> listFilesInDirWithFilter(File dir, String suffix) {
  484. if (dir == null || !isDir(dir)) return null;
  485. List<File> list = new ArrayList<>();
  486. File[] files = dir.listFiles();
  487. for (File file : files) {
  488. if (file.getName().toUpperCase().endsWith(suffix.toUpperCase())) {
  489. list.add(file);
  490. }
  491. if (file.isDirectory()) {
  492. list.addAll(listFilesInDirWithFilter(file, suffix));
  493. }
  494. }
  495. return list;
  496. }
  497. /**
  498. * 获取目录下所有符合filter的文件
  499. *
  500. * @param dirPath 目录路径
  501. * @param filter 过滤器
  502. * @param isRecursive 是否递归进子目录
  503. * @return 文件链表
  504. */
  505. public static List<File> listFilesInDirWithFilter(String dirPath, FilenameFilter filter, boolean isRecursive) {
  506. return listFilesInDirWithFilter(getFileByPath(dirPath), filter, isRecursive);
  507. }
  508. /**
  509. * 获取目录下所有符合filter的文件
  510. *
  511. * @param dir 目录
  512. * @param filter 过滤器
  513. * @param isRecursive 是否递归进子目录
  514. * @return 文件链表
  515. */
  516. public static List<File> listFilesInDirWithFilter(File dir, FilenameFilter filter, boolean isRecursive) {
  517. if (isRecursive) return listFilesInDirWithFilter(dir, filter);
  518. if (dir == null || !isDir(dir)) return null;
  519. List<File> list = new ArrayList<>();
  520. File[] files = dir.listFiles();
  521. for (File file : files) {
  522. if (filter.accept(file.getParentFile(), file.getName())) {
  523. list.add(file);
  524. }
  525. }
  526. return list;
  527. }
  528. /**
  529. * 获取目录下所有符合filter的文件包括子目录
  530. *
  531. * @param dirPath 目录路径
  532. * @param filter 过滤器
  533. * @return 文件链表
  534. */
  535. public static List<File> listFilesInDirWithFilter(String dirPath, FilenameFilter filter) {
  536. return listFilesInDirWithFilter(getFileByPath(dirPath), filter);
  537. }
  538. /**
  539. * 获取目录下所有符合filter的文件包括子目录
  540. *
  541. * @param dir 目录
  542. * @param filter 过滤器
  543. * @return 文件链表
  544. */
  545. public static List<File> listFilesInDirWithFilter(File dir, FilenameFilter filter) {
  546. if (dir == null || !isDir(dir)) return null;
  547. List<File> list = new ArrayList<>();
  548. File[] files = dir.listFiles();
  549. for (File file : files) {
  550. if (filter.accept(file.getParentFile(), file.getName())) {
  551. list.add(file);
  552. }
  553. if (file.isDirectory()) {
  554. list.addAll(listFilesInDirWithFilter(file, filter));
  555. }
  556. }
  557. return list;
  558. }
  559. /**
  560. * 获取目录下指定文件名的文件包括子目录
  561. * <p>大小写忽略</p>
  562. *
  563. * @param dirPath 目录路径
  564. * @param fileName 文件名
  565. * @return 文件链表
  566. */
  567. public static List<File> searchFileInDir(String dirPath, String fileName) {
  568. return searchFileInDir(getFileByPath(dirPath), fileName);
  569. }
  570. /**
  571. * 获取目录下指定文件名的文件包括子目录
  572. * <p>大小写忽略</p>
  573. *
  574. * @param dir 目录
  575. * @param fileName 文件名
  576. * @return 文件链表
  577. */
  578. public static List<File> searchFileInDir(File dir, String fileName) {
  579. if (dir == null || !isDir(dir)) return null;
  580. List<File> list = new ArrayList<>();
  581. File[] files = dir.listFiles();
  582. for (File file : files) {
  583. if (file.getName().toUpperCase().equals(fileName.toUpperCase())) {
  584. list.add(file);
  585. }
  586. if (file.isDirectory()) {
  587. list.addAll(listFilesInDirWithFilter(file, fileName));
  588. }
  589. }
  590. return list;
  591. }
  592. /**
  593. * 将输入流写入文件
  594. *
  595. * @param filePath 路径
  596. * @param is 输入流
  597. * @param append 是否追加在文件末
  598. * @return {@code true}: 写入成功<br>{@code false}: 写入失败
  599. */
  600. public static boolean writeFileFromIS(String filePath, InputStream is, boolean append) {
  601. return writeFileFromIS(getFileByPath(filePath), is, append);
  602. }
  603. /**
  604. * 将输入流写入文件
  605. *
  606. * @param file 文件
  607. * @param is 输入流
  608. * @param append 是否追加在文件末
  609. * @return {@code true}: 写入成功<br>{@code false}: 写入失败
  610. */
  611. public static boolean writeFileFromIS(File file, InputStream is, boolean append) {
  612. if (file == null || is == null) return false;
  613. if (!createOrExistsFile(file)) return false;
  614. OutputStream os = null;
  615. try {
  616. os = new BufferedOutputStream(new FileOutputStream(file, append));
  617. byte data[] = new byte[KB];
  618. int len;
  619. while ((len = is.read(data, 0, KB)) != -1) {
  620. os.write(data, 0, len);
  621. }
  622. return true;
  623. } catch (IOException e) {
  624. e.printStackTrace();
  625. return false;
  626. } finally {
  627. closeIO(is, os);
  628. }
  629. }
  630. /**
  631. * 将字符串写入文件
  632. *
  633. * @param filePath 文件路径
  634. * @param content 写入内容
  635. * @param append 是否追加在文件末
  636. * @return {@code true}: 写入成功<br>{@code false}: 写入失败
  637. */
  638. public static boolean writeFileFromString(String filePath, String content, boolean append) {
  639. return writeFileFromString(getFileByPath(filePath), content, append);
  640. }
  641. /**
  642. * 将字符串写入文件
  643. *
  644. * @param file 文件
  645. * @param content 写入内容
  646. * @param append 是否追加在文件末
  647. * @return {@code true}: 写入成功<br>{@code false}: 写入失败
  648. */
  649. public static boolean writeFileFromString(File file, String content, boolean append) {
  650. if (file == null || content == null) return false;
  651. if (!createOrExistsFile(file)) return false;
  652. FileWriter fileWriter = null;
  653. try {
  654. fileWriter = new FileWriter(file, append);
  655. fileWriter.write(content);
  656. return true;
  657. } catch (IOException e) {
  658. e.printStackTrace();
  659. return false;
  660. } finally {
  661. closeIO(fileWriter);
  662. }
  663. }
  664. /**
  665. * 指定编码按行读取文件到List
  666. *
  667. * @param filePath 文件路径
  668. * @param charsetName 编码格式
  669. * @return 文件行链表
  670. */
  671. public static List<String> readFile2List(String filePath, String charsetName) {
  672. return readFile2List(getFileByPath(filePath), charsetName);
  673. }
  674. /**
  675. * 指定编码按行读取文件到List
  676. *
  677. * @param file 文件
  678. * @param charsetName 编码格式
  679. * @return 文件行链表
  680. */
  681. public static List<String> readFile2List(File file, String charsetName) {
  682. return readFile2List(file, 0, 0x7FFFFFFF, charsetName);
  683. }
  684. /**
  685. * 指定编码按行读取文件到List
  686. *
  687. * @param filePath 文件路径
  688. * @param st 需要读取的开始行数
  689. * @param end 需要读取的结束行数
  690. * @param charsetName 编码格式
  691. * @return 包含制定行的list
  692. */
  693. public static List<String> readFile2List(String filePath, int st, int end, String
  694. charsetName) {
  695. return readFile2List(getFileByPath(filePath), st, end, charsetName);
  696. }
  697. /**
  698. * 指定编码按行读取文件到List
  699. *
  700. * @param file 文件
  701. * @param st 需要读取的开始行数
  702. * @param end 需要读取的结束行数
  703. * @param charsetName 编码格式
  704. * @return 包含从start行到end行的list
  705. */
  706. public static List<String> readFile2List(File file, int st, int end, String charsetName) {
  707. if (file == null) return null;
  708. if (st > end) return null;
  709. BufferedReader reader = null;
  710. try {
  711. String line;
  712. int curLine = 1;
  713. List<String> list = new ArrayList<>();
  714. if (StringUtils.isSpace(charsetName)) {
  715. reader = new BufferedReader(new FileReader(file));
  716. } else {
  717. reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charsetName));
  718. }
  719. while ((line = reader.readLine()) != null) {
  720. if (curLine > end) break;
  721. if (st <= curLine && curLine <= end) list.add(line);
  722. ++curLine;
  723. }
  724. return list;
  725. } catch (IOException e) {
  726. e.printStackTrace();
  727. return null;
  728. } finally {
  729. closeIO(reader);
  730. }
  731. }
  732. /**
  733. * 指定编码按行读取文件到字符串中
  734. *
  735. * @param filePath 文件路径
  736. * @param charsetName 编码格式
  737. * @return 字符串
  738. */
  739. public static String readFile2String(String filePath, String charsetName) {
  740. return readFile2String(getFileByPath(filePath), charsetName);
  741. }
  742. /**
  743. * 指定编码按行读取文件到字符串中
  744. *
  745. * @param file 文件
  746. * @param charsetName 编码格式
  747. * @return 字符串
  748. */
  749. public static String readFile2String(File file, String charsetName) {
  750. if (file == null) return null;
  751. BufferedReader reader = null;
  752. try {
  753. StringBuilder sb = new StringBuilder();
  754. if (StringUtils.isSpace(charsetName)) {
  755. reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
  756. } else {
  757. reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charsetName));
  758. }
  759. String line;
  760. while ((line = reader.readLine()) != null) {
  761. sb.append(line).append("\r\n");// windows系统换行为\r\n,Linux为\n
  762. }
  763. // 要去除最后的换行符
  764. return sb.delete(sb.length() - 2, sb.length()).toString();
  765. } catch (IOException e) {
  766. e.printStackTrace();
  767. return null;
  768. } finally {
  769. closeIO(reader);
  770. }
  771. }
  772. /**
  773. * 指定编码按行读取文件到字符数组中
  774. *
  775. * @param filePath 文件路径
  776. * @return StringBuilder对象
  777. */
  778. public static byte[] readFile2Bytes(String filePath) {
  779. return readFile2Bytes(getFileByPath(filePath));
  780. }
  781. /**
  782. * 指定编码按行读取文件到字符数组中
  783. *
  784. * @param file 文件
  785. * @return StringBuilder对象
  786. */
  787. public static byte[] readFile2Bytes(File file) {
  788. if (file == null) return null;
  789. try {
  790. return ConvertUtils.inputStream2Bytes(new FileInputStream(file));
  791. } catch (FileNotFoundException e) {
  792. e.printStackTrace();
  793. return null;
  794. }
  795. }
  796. /**
  797. * 简单获取文件编码格式
  798. *
  799. * @param filePath 文件路径
  800. * @return 文件编码
  801. */
  802. public static String getFileCharsetSimple(String filePath) {
  803. return getFileCharsetSimple(getFileByPath(filePath));
  804. }
  805. /**
  806. * 简单获取文件编码格式
  807. *
  808. * @param file 文件
  809. * @return 文件编码
  810. */
  811. public static String getFileCharsetSimple(File file) {
  812. int p = 0;
  813. InputStream is = null;
  814. try {
  815. is = new BufferedInputStream(new FileInputStream(file));
  816. p = (is.read() << 8) + is.read();
  817. } catch (IOException e) {
  818. e.printStackTrace();
  819. } finally {
  820. closeIO(is);
  821. }
  822. switch (p) {
  823. case 0xefbb:
  824. return "UTF-8";
  825. case 0xfffe:
  826. return "Unicode";
  827. case 0xfeff:
  828. return "UTF-16BE";
  829. default:
  830. return "GBK";
  831. }
  832. }
  833. /**
  834. * 获取文件行数
  835. *
  836. * @param filePath 文件路径
  837. * @return 文件行数
  838. */
  839. public static int getFileLines(String filePath) {
  840. return getFileLines(getFileByPath(filePath));
  841. }
  842. /**
  843. * 获取文件行数
  844. *
  845. * @param file 文件
  846. * @return 文件行数
  847. */
  848. public static int getFileLines(File file) {
  849. int count = 1;
  850. InputStream is = null;
  851. try {
  852. is = new BufferedInputStream(new FileInputStream(file));
  853. byte[] buffer = new byte[KB];
  854. int readChars;
  855. while ((readChars = is.read(buffer, 0, KB)) != -1) {
  856. for (int i = 0; i < readChars; ++i) {
  857. if (buffer[i] == '\n') ++count;
  858. }
  859. }
  860. } catch (IOException e) {
  861. e.printStackTrace();
  862. } finally {
  863. closeIO(is);
  864. }
  865. return count;
  866. }
  867. /**
  868. * 获取文件大小
  869. *
  870. * @param filePath 文件路径
  871. * @return 文件大小
  872. */
  873. public static String getFileSize(String filePath) {
  874. return getFileSize(getFileByPath(filePath));
  875. }
  876. /**
  877. * 获取文件大小
  878. * <p>例如:getFileSize(file, ConstUtils.MB); 返回文件大小单位为MB</p>
  879. *
  880. * @param file 文件
  881. * @return 文件大小
  882. */
  883. public static String getFileSize(File file) {
  884. if (!isFileExists(file)) return "";
  885. return ConvertUtils.byte2FitSize(file.length());
  886. }
  887. /**
  888. * 获取文件的MD5校验码
  889. *
  890. * @param filePath 文件
  891. * @return 文件的MD5校验码
  892. */
  893. public static String getFileMD5(String filePath) {
  894. return getFileMD5(getFileByPath(filePath));
  895. }
  896. /**
  897. * 获取文件的MD5校验码
  898. *
  899. * @param file 文件
  900. * @return 文件的MD5校验码
  901. */
  902. public static String getFileMD5(File file) {
  903. return EncryptUtils.encryptMD5File2String(file);
  904. }
  905. /**
  906. * 关闭IO
  907. *
  908. * @param closeables closeable
  909. */
  910. public static void closeIO(Closeable... closeables) {
  911. if (closeables == null) return;
  912. try {
  913. for (Closeable closeable : closeables) {
  914. if (closeable != null) {
  915. closeable.close();
  916. }
  917. }
  918. } catch (IOException e) {
  919. e.printStackTrace();
  920. }
  921. }
  922. /**
  923. * 获取全路径中的最长目录
  924. *
  925. * @param file 文件
  926. * @return filePath最长目录
  927. */
  928. public static String getDirName(File file) {
  929. if (file == null) return null;
  930. return getDirName(file.getPath());
  931. }
  932. /**
  933. * 获取全路径中的最长目录
  934. *
  935. * @param filePath 文件路径
  936. * @return filePath最长目录
  937. */
  938. public static String getDirName(String filePath) {
  939. if (StringUtils.isSpace(filePath)) return filePath;
  940. int lastSep = filePath.lastIndexOf(File.separator);
  941. return lastSep == -1 ? "" : filePath.substring(0, lastSep + 1);
  942. }
  943. /**
  944. * 获取全路径中的文件名
  945. *
  946. * @param file 文件
  947. * @return 文件名
  948. */
  949. public static String getFileName(File file) {
  950. if (file == null) return null;
  951. return getFileName(file.getPath());
  952. }
  953. /**
  954. * 获取全路径中的文件名
  955. *
  956. * @param filePath 文件路径
  957. * @return 文件名
  958. */
  959. public static String getFileName(String filePath) {
  960. if (StringUtils.isSpace(filePath)) return filePath;
  961. int lastSep = filePath.lastIndexOf(File.separator);
  962. return lastSep == -1 ? filePath : filePath.substring(lastSep + 1);
  963. }
  964. /**
  965. * 获取全路径中的不带拓展名的文件名
  966. *
  967. * @param file 文件
  968. * @return 不带拓展名的文件名
  969. */
  970. public static String getFileNameNoExtension(File file) {
  971. if (file == null) return null;
  972. return getFileNameNoExtension(file.getPath());
  973. }
  974. /**
  975. * 获取全路径中的不带拓展名的文件名
  976. *
  977. * @param filePath 文件路径
  978. * @return 不带拓展名的文件名
  979. */
  980. public static String getFileNameNoExtension(String filePath) {
  981. if (StringUtils.isSpace(filePath)) return filePath;
  982. int lastPoi = filePath.lastIndexOf('.');
  983. int lastSep = filePath.lastIndexOf(File.separator);
  984. if (lastSep == -1) {
  985. return (lastPoi == -1 ? filePath : filePath.substring(0, lastPoi));
  986. }
  987. if (lastPoi == -1 || lastSep > lastPoi) {
  988. return filePath.substring(lastSep + 1);
  989. }
  990. return filePath.substring(lastSep + 1, lastPoi);
  991. }
  992. /**
  993. * 获取全路径中的文件拓展名
  994. *
  995. * @param file 文件
  996. * @return 文件拓展名
  997. */
  998. public static String getFileExtension(File file) {
  999. if (file == null) return null;
  1000. return getFileExtension(file.getPath());
  1001. }
  1002. /**
  1003. * 获取全路径中的文件拓展名
  1004. *
  1005. * @param filePath 文件路径
  1006. * @return 文件拓展名
  1007. */
  1008. public static String getFileExtension(String filePath) {
  1009. if (StringUtils.isSpace(filePath)) return filePath;
  1010. int lastPoi = filePath.lastIndexOf('.');
  1011. int lastSep = filePath.lastIndexOf(File.separator);
  1012. if (lastPoi == -1 || lastSep >= lastPoi) return "";
  1013. return filePath.substring(lastPoi);
  1014. }
  1015. }

ImageUtils

  1. package com.blankj.utilcode.utils;
  2. import android.annotation.TargetApi;
  3. import android.content.Context;
  4. import android.content.res.Resources;
  5. import android.graphics.Bitmap;
  6. import android.graphics.Bitmap.CompressFormat;
  7. import android.graphics.Bitmap.Config;
  8. import android.graphics.BitmapFactory;
  9. import android.graphics.BitmapShader;
  10. import android.graphics.Canvas;
  11. import android.graphics.Color;
  12. import android.graphics.ColorMatrix;
  13. import android.graphics.ColorMatrixColorFilter;
  14. import android.graphics.LinearGradient;
  15. import android.graphics.Matrix;
  16. import android.graphics.Paint;
  17. import android.graphics.PorterDuff;
  18. import android.graphics.PorterDuffColorFilter;
  19. import android.graphics.PorterDuffXfermode;
  20. import android.graphics.Rect;
  21. import android.graphics.RectF;
  22. import android.graphics.Shader;
  23. import android.graphics.drawable.BitmapDrawable;
  24. import android.graphics.drawable.Drawable;
  25. import android.hardware.camera2.params.BlackLevelPattern;
  26. import android.media.ExifInterface;
  27. import android.os.Build;
  28. import android.renderscript.Allocation;
  29. import android.renderscript.Element;
  30. import android.renderscript.RenderScript;
  31. import android.renderscript.ScriptIntrinsicBlur;
  32. import java.io.BufferedInputStream;
  33. import java.io.BufferedOutputStream;
  34. import java.io.ByteArrayInputStream;
  35. import java.io.ByteArrayOutputStream;
  36. import java.io.File;
  37. import java.io.FileDescriptor;
  38. import java.io.FileInputStream;
  39. import java.io.FileNotFoundException;
  40. import java.io.FileOutputStream;
  41. import java.io.IOException;
  42. import java.io.InputStream;
  43. import java.io.OutputStream;
  44. import java.util.Date;
  45. /**
  46. * <pre>
  47. * author: Blankj
  48. * blog : http://blankj.com
  49. * time : 2016/8/12
  50. * desc : 图片相关工具类
  51. * </pre>
  52. */
  53. public class ImageUtils {
  54. private ImageUtils() {
  55. throw new UnsupportedOperationException("u can't fuck me...");
  56. }
  57. /**
  58. * bitmap转byteArr
  59. *
  60. * @param bitmap bitmap对象
  61. * @param format 格式
  62. * @return 字节数组
  63. */
  64. public static byte[] bitmap2Bytes(Bitmap bitmap, CompressFormat format) {
  65. return ConvertUtils.bitmap2Bytes(bitmap, format);
  66. }
  67. /**
  68. * byteArr转bitmap
  69. *
  70. * @param bytes 字节数组
  71. * @return bitmap对象
  72. */
  73. public static Bitmap bytes2Bitmap(byte[] bytes) {
  74. return ConvertUtils.bytes2Bitmap(bytes);
  75. }
  76. /**
  77. * drawable转bitmap
  78. *
  79. * @param drawable drawable对象
  80. * @return bitmap对象
  81. */
  82. public static Bitmap drawable2Bitmap(Drawable drawable) {
  83. return ConvertUtils.drawable2Bitmap(drawable);
  84. }
  85. /**
  86. * bitmap转drawable
  87. *
  88. * @param res resources对象
  89. * @param bitmap bitmap对象
  90. * @return drawable对象
  91. */
  92. public static Drawable bitmap2Drawable(Resources res, Bitmap bitmap) {
  93. return ConvertUtils.bitmap2Drawable(res, bitmap);
  94. }
  95. /**
  96. * drawable转byteArr
  97. *
  98. * @param drawable drawable对象
  99. * @param format 格式
  100. * @return 字节数组
  101. */
  102. public static byte[] drawable2Bytes(Drawable drawable, CompressFormat format) {
  103. return ConvertUtils.drawable2Bytes(drawable, format);
  104. }
  105. /**
  106. * byteArr转drawable
  107. *
  108. * @param res resources对象
  109. * @param bytes 字节数组
  110. * @return drawable对象
  111. */
  112. public static Drawable bytes2Drawable(Resources res, byte[] bytes) {
  113. return ConvertUtils.bytes2Drawable(res, bytes);
  114. }
  115. /**
  116. * 计算采样大小
  117. *
  118. * @param options 选项
  119. * @param maxWidth 最大宽度
  120. * @param maxHeight 最大高度
  121. * @return 采样大小
  122. */
  123. private static int calculateInSampleSize(BitmapFactory.Options options, int maxWidth, int maxHeight) {
  124. if (maxWidth == 0 || maxHeight == 0) return 1;
  125. int height = options.outHeight;
  126. int width = options.outWidth;
  127. int inSampleSize = 1;
  128. while ((height >>= 1) >= maxHeight && (width >>= 1) >= maxWidth) {
  129. inSampleSize <<= 1;
  130. }
  131. return inSampleSize;
  132. }
  133. /**
  134. * 获取bitmap
  135. *
  136. * @param file 文件
  137. * @return bitmap
  138. */
  139. public static Bitmap getBitmap(File file) {
  140. if (file == null) return null;
  141. InputStream is = null;
  142. try {
  143. is = new BufferedInputStream(new FileInputStream(file));
  144. return BitmapFactory.decodeStream(is);
  145. } catch (FileNotFoundException e) {
  146. e.printStackTrace();
  147. return null;
  148. } finally {
  149. FileUtils.closeIO(is);
  150. }
  151. }
  152. /**
  153. * 获取bitmap
  154. *
  155. * @param file 文件
  156. * @param maxWidth 最大宽度
  157. * @param maxHeight 最大高度
  158. * @return bitmap
  159. */
  160. public static Bitmap getBitmap(File file, int maxWidth, int maxHeight) {
  161. if (file == null) return null;
  162. InputStream is = null;
  163. try {
  164. BitmapFactory.Options options = new BitmapFactory.Options();
  165. options.inJustDecodeBounds = true;
  166. is = new BufferedInputStream(new FileInputStream(file));
  167. BitmapFactory.decodeStream(is, null, options);
  168. options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
  169. options.inJustDecodeBounds = false;
  170. return BitmapFactory.decodeStream(is, null, options);
  171. } catch (FileNotFoundException e) {
  172. e.printStackTrace();
  173. return null;
  174. } finally {
  175. FileUtils.closeIO(is);
  176. }
  177. }
  178. /**
  179. * 获取bitmap
  180. *
  181. * @param filePath 文件路径
  182. * @return bitmap
  183. */
  184. public static Bitmap getBitmap(String filePath) {
  185. if (StringUtils.isSpace(filePath)) return null;
  186. return BitmapFactory.decodeFile(filePath);
  187. }
  188. /**
  189. * 获取bitmap
  190. *
  191. * @param filePath 文件路径
  192. * @param maxWidth 最大宽度
  193. * @param maxHeight 最大高度
  194. * @return bitmap
  195. */
  196. public static Bitmap getBitmap(String filePath, int maxWidth, int maxHeight) {
  197. if (StringUtils.isSpace(filePath)) return null;
  198. BitmapFactory.Options options = new BitmapFactory.Options();
  199. options.inJustDecodeBounds = true;
  200. BitmapFactory.decodeFile(filePath, options);
  201. options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
  202. options.inJustDecodeBounds = false;
  203. return BitmapFactory.decodeFile(filePath, options);
  204. }
  205. /**
  206. * 获取bitmap
  207. *
  208. * @param is 输入流
  209. * @return bitmap
  210. */
  211. public Bitmap getBitmap(InputStream is) {
  212. if (is == null) return null;
  213. return BitmapFactory.decodeStream(is);
  214. }
  215. /**
  216. * 获取bitmap
  217. *
  218. * @param is 输入流
  219. * @param maxWidth 最大宽度
  220. * @param maxHeight 最大高度
  221. * @return bitmap
  222. */
  223. public static Bitmap getBitmap(InputStream is, int maxWidth, int maxHeight) {
  224. if (is == null) return null;
  225. BitmapFactory.Options options = new BitmapFactory.Options();
  226. options.inJustDecodeBounds = true;
  227. BitmapFactory.decodeStream(is, null, options);
  228. options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
  229. options.inJustDecodeBounds = false;
  230. return BitmapFactory.decodeStream(is, null, options);
  231. }
  232. /**
  233. * 获取bitmap
  234. *
  235. * @param data 数据
  236. * @param offset 偏移量
  237. * @return bitmap
  238. */
  239. public Bitmap getBitmap(byte[] data, int offset) {
  240. if (data.length == 0) return null;
  241. return BitmapFactory.decodeByteArray(data, offset, data.length);
  242. }
  243. /**
  244. * 获取bitmap
  245. *
  246. * @param data 数据
  247. * @param offset 偏移量
  248. * @param maxWidth 最大宽度
  249. * @param maxHeight 最大高度
  250. * @return bitmap
  251. */
  252. public static Bitmap getBitmap(byte[] data, int offset, int maxWidth, int maxHeight) {
  253. if (data.length == 0) return null;
  254. BitmapFactory.Options options = new BitmapFactory.Options();
  255. options.inJustDecodeBounds = true;
  256. BitmapFactory.decodeByteArray(data, offset, data.length, options);
  257. options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
  258. options.inJustDecodeBounds = false;
  259. return BitmapFactory.decodeByteArray(data, offset, data.length, options);
  260. }
  261. /**
  262. * 获取bitmap
  263. *
  264. * @param context 上下文
  265. * @param resId 资源id
  266. * @return bitmap
  267. */
  268. public static Bitmap getBitmap(Context context, int resId) {
  269. if (context == null) return null;
  270. InputStream is = context.getResources().openRawResource(resId);
  271. return BitmapFactory.decodeStream(is);
  272. }
  273. /**
  274. * 获取bitmap
  275. *
  276. * @param context 上下文
  277. * @param resId 资源id
  278. * @param maxWidth 最大宽度
  279. * @param maxHeight 最大高度
  280. * @return bitmap
  281. */
  282. public static Bitmap getBitmap(Context context, int resId, int maxWidth, int maxHeight) {
  283. if (context == null) return null;
  284. BitmapFactory.Options options = new BitmapFactory.Options();
  285. options.inJustDecodeBounds = true;
  286. InputStream is = context.getResources().openRawResource(resId);
  287. BitmapFactory.decodeStream(is, null, options);
  288. options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
  289. options.inJustDecodeBounds = false;
  290. return BitmapFactory.decodeStream(is, null, options);
  291. }
  292. /**
  293. * 获取bitmap
  294. *
  295. * @param res 资源对象
  296. * @param id 资源id
  297. * @return bitmap
  298. */
  299. public static Bitmap getBitmap(Resources res, int id) {
  300. if (res == null) return null;
  301. return BitmapFactory.decodeResource(res, id);
  302. }
  303. /**
  304. * 获取bitmap
  305. *
  306. * @param res 资源对象
  307. * @param id 资源id
  308. * @param maxWidth 最大宽度
  309. * @param maxHeight 最大高度
  310. * @return bitmap
  311. */
  312. public static Bitmap getBitmap(Resources res, int id, int maxWidth, int maxHeight) {
  313. if (res == null) return null;
  314. BitmapFactory.Options options = new BitmapFactory.Options();
  315. options.inJustDecodeBounds = true;
  316. BitmapFactory.decodeResource(res, id, options);
  317. options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
  318. options.inJustDecodeBounds = false;
  319. return BitmapFactory.decodeResource(res, id, options);
  320. }
  321. /**
  322. * 获取bitmap
  323. *
  324. * @param fd 文件描述
  325. * @return bitmap
  326. */
  327. public static Bitmap getBitmap(FileDescriptor fd) {
  328. if (fd == null) return null;
  329. return BitmapFactory.decodeFileDescriptor(fd);
  330. }
  331. /**
  332. * 获取bitmap
  333. *
  334. * @param fd 文件描述
  335. * @param maxWidth 最大宽度
  336. * @param maxHeight 最大高度
  337. * @return bitmap
  338. */
  339. public static Bitmap getBitmap(FileDescriptor fd, int maxWidth, int maxHeight) {
  340. if (fd == null) return null;
  341. BitmapFactory.Options options = new BitmapFactory.Options();
  342. options.inJustDecodeBounds = true;
  343. BitmapFactory.decodeFileDescriptor(fd, null, options);
  344. options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
  345. options.inJustDecodeBounds = false;
  346. return BitmapFactory.decodeFileDescriptor(fd, null, options);
  347. }
  348. /**
  349. * 缩放图片
  350. *
  351. * @param src 源图片
  352. * @param newWidth 新宽度
  353. * @param newHeight 新高度
  354. * @return 缩放后的图片
  355. */
  356. public static Bitmap scale(Bitmap src, int newWidth, int newHeight) {
  357. return scale(src, newWidth, newHeight, false);
  358. }
  359. /**
  360. * 缩放图片
  361. *
  362. * @param src 源图片
  363. * @param newWidth 新宽度
  364. * @param newHeight 新高度
  365. * @param recycle 是否回收
  366. * @return 缩放后的图片
  367. */
  368. public static Bitmap scale(Bitmap src, int newWidth, int newHeight, boolean recycle) {
  369. if (isEmptyBitmap(src)) return null;
  370. Bitmap ret = Bitmap.createScaledBitmap(src, newWidth, newHeight, true);
  371. if (recycle && !src.isRecycled()) src.recycle();
  372. return ret;
  373. }
  374. /**
  375. * 缩放图片
  376. *
  377. * @param src 源图片
  378. * @param scaleWidth 缩放宽度倍数
  379. * @param scaleHeight 缩放高度倍数
  380. * @return 缩放后的图片
  381. */
  382. public static Bitmap scale(Bitmap src, float scaleWidth, float scaleHeight) {
  383. return scale(src, scaleWidth, scaleHeight, false);
  384. }
  385. /**
  386. * 缩放图片
  387. *
  388. * @param src 源图片
  389. * @param scaleWidth 缩放宽度倍数
  390. * @param scaleHeight 缩放高度倍数
  391. * @param recycle 是否回收
  392. * @return 缩放后的图片
  393. */
  394. public static Bitmap scale(Bitmap src, float scaleWidth, float scaleHeight, boolean recycle) {
  395. if (isEmptyBitmap(src)) return null;
  396. Matrix matrix = new Matrix();
  397. matrix.setScale(scaleWidth, scaleHeight);
  398. Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
  399. if (recycle && !src.isRecycled()) src.recycle();
  400. return ret;
  401. }
  402. /**
  403. * 裁剪图片
  404. *
  405. * @param src 源图片
  406. * @param x 开始坐标x
  407. * @param y 开始坐标y
  408. * @param width 裁剪宽度
  409. * @param height 裁剪高度
  410. * @return 裁剪后的图片
  411. */
  412. public static Bitmap clip(Bitmap src, int x, int y, int width, int height) {
  413. return clip(src, x, y, width, height, false);
  414. }
  415. /**
  416. * 裁剪图片
  417. *
  418. * @param src 源图片
  419. * @param x 开始坐标x
  420. * @param y 开始坐标y
  421. * @param width 裁剪宽度
  422. * @param height 裁剪高度
  423. * @param recycle 是否回收
  424. * @return 裁剪后的图片
  425. */
  426. public static Bitmap clip(Bitmap src, int x, int y, int width, int height, boolean recycle) {
  427. if (isEmptyBitmap(src)) return null;
  428. Bitmap ret = Bitmap.createBitmap(src, x, y, width, height);
  429. if (recycle && !src.isRecycled()) src.recycle();
  430. return ret;
  431. }
  432. /**
  433. * 倾斜图片
  434. *
  435. * @param src 源图片
  436. * @param kx 倾斜因子x
  437. * @param ky 倾斜因子y
  438. * @return 倾斜后的图片
  439. */
  440. public static Bitmap skew(Bitmap src, float kx, float ky) {
  441. return skew(src, kx, ky, 0, 0, false);
  442. }
  443. /**
  444. * 倾斜图片
  445. *
  446. * @param src 源图片
  447. * @param kx 倾斜因子x
  448. * @param ky 倾斜因子y
  449. * @param recycle 是否回收
  450. * @return 倾斜后的图片
  451. */
  452. public static Bitmap skew(Bitmap src, float kx, float ky, boolean recycle) {
  453. return skew(src, kx, ky, 0, 0, recycle);
  454. }
  455. /**
  456. * 倾斜图片
  457. *
  458. * @param src 源图片
  459. * @param kx 倾斜因子x
  460. * @param ky 倾斜因子y
  461. * @param px 平移因子x
  462. * @param py 平移因子y
  463. * @return 倾斜后的图片
  464. */
  465. public static Bitmap skew(Bitmap src, float kx, float ky, float px, float py) {
  466. return skew(src, kx, ky, 0, 0, false);
  467. }
  468. /**
  469. * 倾斜图片
  470. *
  471. * @param src 源图片
  472. * @param kx 倾斜因子x
  473. * @param ky 倾斜因子y
  474. * @param px 平移因子x
  475. * @param py 平移因子y
  476. * @param recycle 是否回收
  477. * @return 倾斜后的图片
  478. */
  479. public static Bitmap skew(Bitmap src, float kx, float ky, float px, float py, boolean recycle) {
  480. if (isEmptyBitmap(src)) return null;
  481. Matrix matrix = new Matrix();
  482. matrix.setSkew(kx, ky, px, py);
  483. Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
  484. if (recycle && !src.isRecycled()) src.recycle();
  485. return ret;
  486. }
  487. /**
  488. * 旋转图片
  489. *
  490. * @param src 源图片
  491. * @param degrees 旋转角度
  492. * @param px 旋转点横坐标
  493. * @param py 旋转点纵坐标
  494. * @return 旋转后的图片
  495. */
  496. public static Bitmap rotate(Bitmap src, int degrees, float px, float py) {
  497. return rotate(src, degrees, px, py, false);
  498. }
  499. /**
  500. * 旋转图片
  501. *
  502. * @param src 源图片
  503. * @param degrees 旋转角度
  504. * @param px 旋转点横坐标
  505. * @param py 旋转点纵坐标
  506. * @param recycle 是否回收
  507. * @return 旋转后的图片
  508. */
  509. public static Bitmap rotate(Bitmap src, int degrees, float px, float py, boolean recycle) {
  510. if (isEmptyBitmap(src)) return null;
  511. if (degrees == 0) return src;
  512. Matrix matrix = new Matrix();
  513. matrix.setRotate(degrees, px, py);
  514. Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
  515. if (recycle && !src.isRecycled()) src.recycle();
  516. return ret;
  517. }
  518. /**
  519. * 获取图片旋转角度
  520. *
  521. * @param filePath 文件路径
  522. * @return 旋转角度
  523. */
  524. public static int getRotateDegree(String filePath) {
  525. int degree = 0;
  526. try {
  527. ExifInterface exifInterface = new ExifInterface(filePath);
  528. int orientation = exifInterface.getAttributeInt(
  529. ExifInterface.TAG_ORIENTATION,
  530. ExifInterface.ORIENTATION_NORMAL);
  531. switch (orientation) {
  532. default:
  533. case ExifInterface.ORIENTATION_ROTATE_90:
  534. degree = 90;
  535. break;
  536. case ExifInterface.ORIENTATION_ROTATE_180:
  537. degree = 180;
  538. break;
  539. case ExifInterface.ORIENTATION_ROTATE_270:
  540. degree = 270;
  541. break;
  542. }
  543. } catch (IOException e) {
  544. e.printStackTrace();
  545. }
  546. return degree;
  547. }
  548. /**
  549. * 转为圆形图片
  550. *
  551. * @param src 源图片
  552. * @return 圆形图片
  553. */
  554. public static Bitmap toRound(Bitmap src) {
  555. return toRound(src, false);
  556. }
  557. /**
  558. * 转为圆形图片
  559. *
  560. * @param src 源图片
  561. * @param recycle 是否回收
  562. * @return 圆形图片
  563. */
  564. public static Bitmap toRound(Bitmap src, boolean recycle) {
  565. if (isEmptyBitmap(src)) return null;
  566. int width = src.getWidth();
  567. int height = src.getHeight();
  568. int radius = Math.min(width, height) >> 1;
  569. Bitmap ret = src.copy(src.getConfig(), true);
  570. Paint paint = new Paint();
  571. Canvas canvas = new Canvas(ret);
  572. Rect rect = new Rect(0, 0, width, height);
  573. paint.setAntiAlias(true);
  574. paint.setColor(Color.TRANSPARENT);
  575. paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
  576. canvas.drawARGB(0, 0, 0, 0);
  577. canvas.drawCircle(width >> 1, height >> 1, radius, paint);
  578. canvas.drawBitmap(src, rect, rect, paint);
  579. if (recycle && !src.isRecycled()) src.recycle();
  580. return ret;
  581. }
  582. /**
  583. * 转为圆角图片
  584. *
  585. * @param src 源图片
  586. * @param radius 圆角的度数
  587. * @return 圆角图片
  588. */
  589. public static Bitmap toRoundCorner(Bitmap src, float radius) {
  590. return toRoundCorner(src, radius, false);
  591. }
  592. /**
  593. * 转为圆角图片
  594. *
  595. * @param src 源图片
  596. * @param radius 圆角的度数
  597. * @param recycle 是否回收
  598. * @return 圆角图片
  599. */
  600. public static Bitmap toRoundCorner(Bitmap src, float radius, boolean recycle) {
  601. if (null == src) return null;
  602. int width = src.getWidth();
  603. int height = src.getHeight();
  604. Bitmap ret = src.copy(src.getConfig(), true);
  605. BitmapShader bitmapShader = new BitmapShader(src,
  606. Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
  607. Paint paint = new Paint();
  608. Canvas canvas = new Canvas(ret);
  609. RectF rectf = new RectF(0, 0, width, height);
  610. paint.setAntiAlias(true);
  611. paint.setShader(bitmapShader);
  612. canvas.drawRoundRect(rectf, radius, radius, paint);
  613. if (recycle && !src.isRecycled()) src.recycle();
  614. return ret;
  615. }
  616. /**
  617. * 快速模糊
  618. * <p>先缩小原图,对小图进行模糊,再放大回原先尺寸</p>
  619. *
  620. * @param context 上下文
  621. * @param src 源图片
  622. * @param scale 缩小倍数(0...1)
  623. * @param radius 模糊半径
  624. * @return 模糊后的图片
  625. */
  626. public static Bitmap fastBlur(Context context, Bitmap src, float scale, float radius) {
  627. return fastBlur(context, src, scale, radius, false);
  628. }
  629. /**
  630. * 快速模糊
  631. * <p>先缩小原图,对小图进行模糊,再放大回原先尺寸</p>
  632. *
  633. * @param context 上下文
  634. * @param src 源图片
  635. * @param scale 缩小倍数(0...1)
  636. * @param radius 模糊半径
  637. * @param recycle 是否回收
  638. * @return 模糊后的图片
  639. */
  640. public static Bitmap fastBlur(Context context, Bitmap src, float scale, float radius, boolean recycle) {
  641. if (isEmptyBitmap(src)) return null;
  642. int width = src.getWidth();
  643. int height = src.getHeight();
  644. int scaleWidth = (int) (width * scale + 0.5f);
  645. int scaleHeight = (int) (height * scale + 0.5f);
  646. if (scaleWidth == 0 || scaleHeight == 0) return null;
  647. Bitmap scaleBitmap = Bitmap.createScaledBitmap(src, scaleWidth, scaleHeight, true);
  648. Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
  649. Canvas canvas = new Canvas();
  650. PorterDuffColorFilter filter = new PorterDuffColorFilter(
  651. Color.TRANSPARENT, PorterDuff.Mode.SRC_ATOP);
  652. paint.setColorFilter(filter);
  653. canvas.scale(scale, scale);
  654. canvas.drawBitmap(scaleBitmap, 0, 0, paint);
  655. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
  656. scaleBitmap = renderScriptBlur(context, scaleBitmap, radius);
  657. } else {
  658. scaleBitmap = stackBlur(scaleBitmap, (int) radius, true);
  659. }
  660. if (scale == 1) return scaleBitmap;
  661. Bitmap ret = Bitmap.createScaledBitmap(scaleBitmap, width, height, true);
  662. if (scaleBitmap != null && !scaleBitmap.isRecycled()) scaleBitmap.recycle();
  663. if (recycle && !src.isRecycled()) src.recycle();
  664. return ret;
  665. }
  666. /**
  667. * renderScript模糊图片
  668. * <p>API大于17</p>
  669. *
  670. * @param context 上下文
  671. * @param src 源图片
  672. * @param radius 模糊度(0...25)
  673. * @return 模糊后的图片
  674. */
  675. @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
  676. public static Bitmap renderScriptBlur(Context context, Bitmap src, float radius) {
  677. if (isEmptyBitmap(src)) return null;
  678. RenderScript rs = null;
  679. try {
  680. rs = RenderScript.create(context);
  681. rs.setMessageHandler(new RenderScript.RSMessageHandler());
  682. Allocation input = Allocation.createFromBitmap(rs, src, Allocation.MipmapControl.MIPMAP_NONE, Allocation
  683. .USAGE_SCRIPT);
  684. Allocation output = Allocation.createTyped(rs, input.getType());
  685. ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
  686. if (radius > 25) {
  687. radius = 25.0f;
  688. } else if (radius <= 0) {
  689. radius = 1.0f;
  690. }
  691. blurScript.setInput(input);
  692. blurScript.setRadius(radius);
  693. blurScript.forEach(output);
  694. output.copyTo(src);
  695. } finally {
  696. if (rs != null) {
  697. rs.destroy();
  698. }
  699. }
  700. return src;
  701. }
  702. /**
  703. * stack模糊图片
  704. *
  705. * @param src 源图片
  706. * @param radius 模糊半径
  707. * @param recycle 是否回收
  708. * @return stackBlur模糊图片
  709. */
  710. public static Bitmap stackBlur(Bitmap src, int radius, boolean recycle) {
  711. Bitmap ret;
  712. if (recycle) {
  713. ret = src;
  714. } else {
  715. ret = src.copy(src.getConfig(), true);
  716. }
  717. if (radius < 1) {
  718. return (null);
  719. }
  720. int w = ret.getWidth();
  721. int h = ret.getHeight();
  722. int[] pix = new int[w * h];
  723. ret.getPixels(pix, 0, w, 0, 0, w, h);
  724. int wm = w - 1;
  725. int hm = h - 1;
  726. int wh = w * h;
  727. int div = radius + radius + 1;
  728. int r[] = new int[wh];
  729. int g[] = new int[wh];
  730. int b[] = new int[wh];
  731. int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
  732. int vmin[] = new int[Math.max(w, h)];
  733. int divsum = (div + 1) >> 1;
  734. divsum *= divsum;
  735. int dv[] = new int[256 * divsum];
  736. for (i = 0; i < 256 * divsum; i++) {
  737. dv[i] = (i / divsum);
  738. }
  739. yw = yi = 0;
  740. int[][] stack = new int[div][3];
  741. int stackpointer;
  742. int stackstart;
  743. int[] sir;
  744. int rbs;
  745. int r1 = radius + 1;
  746. int routsum, goutsum, boutsum;
  747. int rinsum, ginsum, binsum;
  748. for (y = 0; y < h; y++) {
  749. rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
  750. for (i = -radius; i <= radius; i++) {
  751. p = pix[yi + Math.min(wm, Math.max(i, 0))];
  752. sir = stack[i + radius];
  753. sir[0] = (p & 0xff0000) >> 16;
  754. sir[1] = (p & 0x00ff00) >> 8;
  755. sir[2] = (p & 0x0000ff);
  756. rbs = r1 - Math.abs(i);
  757. rsum += sir[0] * rbs;
  758. gsum += sir[1] * rbs;
  759. bsum += sir[2] * rbs;
  760. if (i > 0) {
  761. rinsum += sir[0];
  762. ginsum += sir[1];
  763. binsum += sir[2];
  764. } else {
  765. routsum += sir[0];
  766. goutsum += sir[1];
  767. boutsum += sir[2];
  768. }
  769. }
  770. stackpointer = radius;
  771. for (x = 0; x < w; x++) {
  772. r[yi] = dv[rsum];
  773. g[yi] = dv[gsum];
  774. b[yi] = dv[bsum];
  775. rsum -= routsum;
  776. gsum -= goutsum;
  777. bsum -= boutsum;
  778. stackstart = stackpointer - radius + div;
  779. sir = stack[stackstart % div];
  780. routsum -= sir[0];
  781. goutsum -= sir[1];
  782. boutsum -= sir[2];
  783. if (y == 0) {
  784. vmin[x] = Math.min(x + radius + 1, wm);
  785. }
  786. p = pix[yw + vmin[x]];
  787. sir[0] = (p & 0xff0000) >> 16;
  788. sir[1] = (p & 0x00ff00) >> 8;
  789. sir[2] = (p & 0x0000ff);
  790. rinsum += sir[0];
  791. ginsum += sir[1];
  792. binsum += sir[2];
  793. rsum += rinsum;
  794. gsum += ginsum;
  795. bsum += binsum;
  796. stackpointer = (stackpointer + 1) % div;
  797. sir = stack[(stackpointer) % div];
  798. routsum += sir[0];
  799. goutsum += sir[1];
  800. boutsum += sir[2];
  801. rinsum -= sir[0];
  802. ginsum -= sir[1];
  803. binsum -= sir[2];
  804. yi++;
  805. }
  806. yw += w;
  807. }
  808. for (x = 0; x < w; x++) {
  809. rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
  810. yp = -radius * w;
  811. for (i = -radius; i <= radius; i++) {
  812. yi = Math.max(0, yp) + x;
  813. sir = stack[i + radius];
  814. sir[0] = r[yi];
  815. sir[1] = g[yi];
  816. sir[2] = b[yi];
  817. rbs = r1 - Math.abs(i);
  818. rsum += r[yi] * rbs;
  819. gsum += g[yi] * rbs;
  820. bsum += b[yi] * rbs;
  821. if (i > 0) {
  822. rinsum += sir[0];
  823. ginsum += sir[1];
  824. binsum += sir[2];
  825. } else {
  826. routsum += sir[0];
  827. goutsum += sir[1];
  828. boutsum += sir[2];
  829. }
  830. if (i < hm) {
  831. yp += w;
  832. }
  833. }
  834. yi = x;
  835. stackpointer = radius;
  836. for (y = 0; y < h; y++) {
  837. // Preserve alpha channel: ( 0xff000000 & pix[yi] )
  838. pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
  839. rsum -= routsum;
  840. gsum -= goutsum;
  841. bsum -= boutsum;
  842. stackstart = stackpointer - radius + div;
  843. sir = stack[stackstart % div];
  844. routsum -= sir[0];
  845. goutsum -= sir[1];
  846. boutsum -= sir[2];
  847. if (x == 0) {
  848. vmin[y] = Math.min(y + r1, hm) * w;
  849. }
  850. p = x + vmin[y];
  851. sir[0] = r[p];
  852. sir[1] = g[p];
  853. sir[2] = b[p];
  854. rinsum += sir[0];
  855. ginsum += sir[1];
  856. binsum += sir[2];
  857. rsum += rinsum;
  858. gsum += ginsum;
  859. bsum += binsum;
  860. stackpointer = (stackpointer + 1) % div;
  861. sir = stack[stackpointer];
  862. routsum += sir[0];
  863. goutsum += sir[1];
  864. boutsum += sir[2];
  865. rinsum -= sir[0];
  866. ginsum -= sir[1];
  867. binsum -= sir[2];
  868. yi += w;
  869. }
  870. }
  871. ret.setPixels(pix, 0, w, 0, 0, w, h);
  872. return (ret);
  873. }
  874. /**
  875. * 添加颜色边框
  876. *
  877. * @param src 源图片
  878. * @param borderWidth 边框宽度
  879. * @param color 边框的颜色值
  880. * @return 带颜色边框图
  881. */
  882. public static Bitmap addFrame(Bitmap src, int borderWidth, int color) {
  883. return addFrame(src, borderWidth, color);
  884. }
  885. /**
  886. * 添加颜色边框
  887. *
  888. * @param src 源图片
  889. * @param borderWidth 边框宽度
  890. * @param color 边框的颜色值
  891. * @param recycle 是否回收
  892. * @return 带颜色边框图
  893. */
  894. public static Bitmap addFrame(Bitmap src, int borderWidth, int color, boolean recycle) {
  895. if (isEmptyBitmap(src)) return null;
  896. int newWidth = src.getWidth() + borderWidth >> 1;
  897. int newHeight = src.getHeight() + borderWidth >> 1;
  898. Bitmap ret = Bitmap.createBitmap(newWidth, newHeight, src.getConfig());
  899. Canvas canvas = new Canvas(ret);
  900. Rect rec = canvas.getClipBounds();
  901. Paint paint = new Paint();
  902. paint.setColor(color);
  903. paint.setStyle(Paint.Style.STROKE);
  904. paint.setStrokeWidth(borderWidth);
  905. canvas.drawRect(rec, paint);
  906. canvas.drawBitmap(src, borderWidth, borderWidth, null);
  907. if (recycle && !src.isRecycled()) src.recycle();
  908. return ret;
  909. }
  910. /**
  911. * 添加倒影
  912. *
  913. * @param src 源图片的
  914. * @param reflectionHeight 倒影高度
  915. * @return 带倒影图片
  916. */
  917. public static Bitmap addReflection(Bitmap src, int reflectionHeight) {
  918. return addReflection(src, reflectionHeight, false);
  919. }
  920. /**
  921. * 添加倒影
  922. *
  923. * @param src 源图片的
  924. * @param reflectionHeight 倒影高度
  925. * @param recycle 是否回收
  926. * @return 带倒影图片
  927. */
  928. public static Bitmap addReflection(Bitmap src, int reflectionHeight, boolean recycle) {
  929. if (isEmptyBitmap(src)) return null;
  930. final int REFLECTION_GAP = 0;
  931. int srcWidth = src.getWidth();
  932. int srcHeight = src.getHeight();
  933. if (0 == srcWidth || srcHeight == 0) return null;
  934. Matrix matrix = new Matrix();
  935. matrix.preScale(1, -1);
  936. Bitmap reflectionBitmap = Bitmap.createBitmap(src, 0, srcHeight - reflectionHeight,
  937. srcWidth, reflectionHeight, matrix, false);
  938. if (null == reflectionBitmap) return null;
  939. Bitmap ret = Bitmap.createBitmap(srcWidth, srcHeight + reflectionHeight, src.getConfig());
  940. Canvas canvas = new Canvas(ret);
  941. canvas.drawBitmap(src, 0, 0, null);
  942. canvas.drawBitmap(reflectionBitmap, 0, srcHeight + REFLECTION_GAP, null);
  943. Paint paint = new Paint();
  944. paint.setAntiAlias(true);
  945. LinearGradient shader = new LinearGradient(0, srcHeight, 0,
  946. ret.getHeight() + REFLECTION_GAP,
  947. 0x70FFFFFF, 0x00FFFFFF, Shader.TileMode.MIRROR);
  948. paint.setShader(shader);
  949. paint.setXfermode(new PorterDuffXfermode(
  950. android.graphics.PorterDuff.Mode.DST_IN));
  951. canvas.save();
  952. canvas.drawRect(0, srcHeight, srcWidth,
  953. ret.getHeight() + REFLECTION_GAP, paint);
  954. canvas.restore();
  955. if (!reflectionBitmap.isRecycled()) reflectionBitmap.recycle();
  956. if (recycle && !src.isRecycled()) src.recycle();
  957. return ret;
  958. }
  959. /**
  960. * 添加文字水印
  961. *
  962. * @param src 源图片
  963. * @param content 水印文本
  964. * @param textSize 水印字体大小
  965. * @param color 水印字体颜色
  966. * @param alpha 水印字体透明度
  967. * @param x 起始坐标x
  968. * @param y 起始坐标y
  969. * @return 带有文字水印的图片
  970. */
  971. public static Bitmap addTextWatermark(Bitmap src, String content, int textSize, int color, int alpha, float x, float y) {
  972. return addTextWatermark(src, content, textSize, color, alpha, x, y, false);
  973. }
  974. /**
  975. * 添加文字水印
  976. *
  977. * @param src 源图片
  978. * @param content 水印文本
  979. * @param textSize 水印字体大小
  980. * @param color 水印字体颜色
  981. * @param alpha 水印字体透明度
  982. * @param x 起始坐标x
  983. * @param y 起始坐标y
  984. * @param recycle 是否回收
  985. * @return 带有文字水印的图片
  986. */
  987. public static Bitmap addTextWatermark(Bitmap src, String content, int textSize, int color, int alpha, float x, float y, boolean recycle) {
  988. if (isEmptyBitmap(src) || content == null) return null;
  989. Bitmap ret = src.copy(src.getConfig(), true);
  990. Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
  991. Canvas canvas = new Canvas(ret);
  992. paint.setAlpha(alpha);
  993. paint.setColor(color);
  994. paint.setTextSize(textSize);
  995. Rect bounds = new Rect();
  996. paint.getTextBounds(content, 0, content.length(), bounds);
  997. canvas.drawText(content, x, y, paint);
  998. if (recycle && !src.isRecycled()) src.recycle();
  999. return ret;
  1000. }
  1001. /**
  1002. * 添加图片水印
  1003. *
  1004. * @param src 源图片
  1005. * @param watermark 图片水印
  1006. * @param x 起始坐标x
  1007. * @param y 起始坐标y
  1008. * @param alpha 透明度
  1009. * @return 带有图片水印的图片
  1010. */
  1011. public static Bitmap addImageWatermark(Bitmap src, Bitmap watermark, int x, int y, int alpha) {
  1012. return addImageWatermark(src, watermark, x, y, alpha, false);
  1013. }
  1014. /**
  1015. * 添加图片水印
  1016. *
  1017. * @param src 源图片
  1018. * @param watermark 图片水印
  1019. * @param x 起始坐标x
  1020. * @param y 起始坐标y
  1021. * @param alpha 透明度
  1022. * @param recycle 是否回收
  1023. * @return 带有图片水印的图片
  1024. */
  1025. public static Bitmap addImageWatermark(Bitmap src, Bitmap watermark, int x, int y, int alpha, boolean recycle) {
  1026. if (isEmptyBitmap(src)) return null;
  1027. Bitmap ret = src.copy(src.getConfig(), true);
  1028. if (!isEmptyBitmap(watermark)) {
  1029. Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
  1030. Canvas canvas = new Canvas(ret);
  1031. paint.setAlpha(alpha);
  1032. canvas.drawBitmap(watermark, x, y, paint);
  1033. }
  1034. if (recycle && !src.isRecycled()) src.recycle();
  1035. return ret;
  1036. }
  1037. /**
  1038. * 转为alpha位图
  1039. *
  1040. * @param src 源图片
  1041. * @return alpha位图
  1042. */
  1043. public static Bitmap toAlpha(Bitmap src) {
  1044. return toAlpha(src);
  1045. }
  1046. /**
  1047. * 转为alpha位图
  1048. *
  1049. * @param src 源图片
  1050. * @param recycle 是否回收
  1051. * @return alpha位图
  1052. */
  1053. public static Bitmap toAlpha(Bitmap src, Boolean recycle) {
  1054. if (isEmptyBitmap(src)) return null;
  1055. Bitmap ret = src.extractAlpha();
  1056. if (recycle && !src.isRecycled()) src.recycle();
  1057. return ret;
  1058. }
  1059. /**
  1060. * 转为灰度图片
  1061. *
  1062. * @param src 源图片
  1063. * @return 灰度图
  1064. */
  1065. public static Bitmap toGray(Bitmap src) {
  1066. return toGray(src, false);
  1067. }
  1068. /**
  1069. * 转为灰度图片
  1070. *
  1071. * @param src 源图片
  1072. * @param recycle 是否回收
  1073. * @return 灰度图
  1074. */
  1075. public static Bitmap toGray(Bitmap src, boolean recycle) {
  1076. if (isEmptyBitmap(src)) return null;
  1077. Bitmap grayBitmap = Bitmap.createBitmap(src.getWidth(),
  1078. src.getHeight(), Bitmap.Config.RGB_565);
  1079. Canvas canvas = new Canvas(grayBitmap);
  1080. Paint paint = new Paint();
  1081. ColorMatrix colorMatrix = new ColorMatrix();
  1082. colorMatrix.setSaturation(0);
  1083. ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(colorMatrix);
  1084. paint.setColorFilter(colorMatrixColorFilter);
  1085. canvas.drawBitmap(src, 0, 0, paint);
  1086. if (recycle && !src.isRecycled()) src.recycle();
  1087. return grayBitmap;
  1088. }
  1089. /**
  1090. * 保存图片
  1091. *
  1092. * @param src 源图片
  1093. * @param filePath 要保存到的文件路径
  1094. * @param format 格式
  1095. * @return {@code true}: 成功<br>{@code false}: 失败
  1096. */
  1097. public static boolean save(Bitmap src, String filePath, CompressFormat format) {
  1098. return save(src, FileUtils.getFileByPath(filePath), format, false);
  1099. }
  1100. /**
  1101. * 保存图片
  1102. *
  1103. * @param src 源图片
  1104. * @param file 要保存到的文件
  1105. * @param format 格式
  1106. * @return {@code true}: 成功<br>{@code false}: 失败
  1107. */
  1108. public static boolean save(Bitmap src, File file, CompressFormat format) {
  1109. return save(src, file, format, false);
  1110. }
  1111. /**
  1112. * 保存图片
  1113. *
  1114. * @param src 源图片
  1115. * @param filePath 要保存到的文件路径
  1116. * @param format 格式
  1117. * @param recycle 是否回收
  1118. * @return {@code true}: 成功<br>{@code false}: 失败
  1119. */
  1120. public static boolean save(Bitmap src, String filePath, CompressFormat format, boolean recycle) {
  1121. return save(src, FileUtils.getFileByPath(filePath), format, recycle);
  1122. }
  1123. /**
  1124. * 保存图片
  1125. *
  1126. * @param src 源图片
  1127. * @param file 要保存到的文件
  1128. * @param format 格式
  1129. * @param recycle 是否回收
  1130. * @return {@code true}: 成功<br>{@code false}: 失败
  1131. */
  1132. public static boolean save(Bitmap src, File file, CompressFormat format, boolean recycle) {
  1133. if (isEmptyBitmap(src) || !FileUtils.createOrExistsFile(file)) return false;
  1134. System.out.println(src.getWidth() + ", " + src.getHeight());
  1135. OutputStream os = null;
  1136. boolean ret = false;
  1137. try {
  1138. os = new BufferedOutputStream(new FileOutputStream(file));
  1139. ret = src.compress(format, 100, os);
  1140. if (recycle && !src.isRecycled()) src.recycle();
  1141. } catch (IOException e) {
  1142. e.printStackTrace();
  1143. } finally {
  1144. FileUtils.closeIO(os);
  1145. }
  1146. return ret;
  1147. }
  1148. /**
  1149. * 根据文件名判断文件是否为图片
  1150. *
  1151. * @param file  文件
  1152. * @return {@code true}: 是<br>{@code false}: 否
  1153. */
  1154. public static boolean isImage(File file) {
  1155. return file != null && isImage(file.getPath());
  1156. }
  1157. /**
  1158. * 根据文件名判断文件是否为图片
  1159. *
  1160. * @param filePath  文件路径
  1161. * @return {@code true}: 是<br>{@code false}: 否
  1162. */
  1163. public static boolean isImage(String filePath) {
  1164. String path = filePath.toUpperCase();
  1165. return path.endsWith(".PNG") || path.endsWith(".JPG")
  1166. || path.endsWith(".JPEG") || path.endsWith(".BMP")
  1167. || path.endsWith(".GIF");
  1168. }
  1169. /**
  1170. * 获取图片类型
  1171. *
  1172. * @param filePath 文件路径
  1173. * @return 图片类型
  1174. */
  1175. public static String getImageType(String filePath) {
  1176. return getImageType(FileUtils.getFileByPath(filePath));
  1177. }
  1178. /**
  1179. * 获取图片类型
  1180. *
  1181. * @param file 文件
  1182. * @return 图片类型
  1183. */
  1184. public static String getImageType(File file) {
  1185. if (file == null) return null;
  1186. InputStream is = null;
  1187. try {
  1188. is = new FileInputStream(file);
  1189. return getImageType(is);
  1190. } catch (IOException e) {
  1191. e.printStackTrace();
  1192. return null;
  1193. } finally {
  1194. FileUtils.closeIO(is);
  1195. }
  1196. }
  1197. /**
  1198. * 流获取图片类型
  1199. *
  1200. * @param is 图片输入流
  1201. * @return 图片类型
  1202. */
  1203. public static String getImageType(InputStream is) {
  1204. if (is == null) return null;
  1205. try {
  1206. byte[] bytes = new byte[8];
  1207. return is.read(bytes, 0, 8) != -1 ? getImageType(bytes) : null;
  1208. } catch (IOException e) {
  1209. e.printStackTrace();
  1210. return null;
  1211. }
  1212. }
  1213. /**
  1214. * 获取图片类型
  1215. *
  1216. * @param bytes bitmap的前8字节
  1217. * @return 图片类型
  1218. */
  1219. public static String getImageType(byte[] bytes) {
  1220. if (isJPEG(bytes)) return "JPEG";
  1221. if (isGIF(bytes)) return "GIF";
  1222. if (isPNG(bytes)) return "PNG";
  1223. if (isBMP(bytes)) return "BMP";
  1224. return null;
  1225. }
  1226. private static boolean isJPEG(byte[] b) {
  1227. return b.length >= 2
  1228. && (b[0] == (byte) 0xFF) && (b[1] == (byte) 0xD8);
  1229. }
  1230. private static boolean isGIF(byte[] b) {
  1231. return b.length >= 6
  1232. && b[0] == 'G' && b[1] == 'I'
  1233. && b[2] == 'F' && b[3] == '8'
  1234. && (b[4] == '7' || b[4] == '9') && b[5] == 'a';
  1235. }
  1236. private static boolean isPNG(byte[] b) {
  1237. return b.length >= 8
  1238. && (b[0] == (byte) 137 && b[1] == (byte) 80
  1239. && b[2] == (byte) 78 && b[3] == (byte) 71
  1240. && b[4] == (byte) 13 && b[5] == (byte) 10
  1241. && b[6] == (byte) 26 && b[7] == (byte) 10);
  1242. }
  1243. private static boolean isBMP(byte[] b) {
  1244. return b.length >= 2
  1245. && (b[0] == 0x42) && (b[1] == 0x4d);
  1246. }
  1247. /**
  1248. * 判断bitmap对象是否为空
  1249. *
  1250. * @param src 源图片
  1251. * @return {@code true}: 是<br>{@code false}: 否
  1252. */
  1253. private static boolean isEmptyBitmap(Bitmap src) {
  1254. return src == null || src.getWidth() == 0 || src.getHeight() == 0;
  1255. }
  1256. /******************************~~~~~~~~~ 下方和压缩有关 ~~~~~~~~~******************************/
  1257. /**
  1258. * 按缩放压缩
  1259. *
  1260. * @param src 源图片
  1261. * @param newWidth 新宽度
  1262. * @param newHeight 新高度
  1263. * @return 缩放压缩后的图片
  1264. */
  1265. public static Bitmap compressByScale(Bitmap src, int newWidth, int newHeight) {
  1266. return scale(src, newWidth, newHeight, false);
  1267. }
  1268. /**
  1269. * 按缩放压缩
  1270. *
  1271. * @param src 源图片
  1272. * @param newWidth 新宽度
  1273. * @param newHeight 新高度
  1274. * @param recycle 是否回收
  1275. * @return 缩放压缩后的图片
  1276. */
  1277. public static Bitmap compressByScale(Bitmap src, int newWidth, int newHeight, boolean recycle) {
  1278. return scale(src, newWidth, newHeight, recycle);
  1279. }
  1280. /**
  1281. * 按缩放压缩
  1282. *
  1283. * @param src 源图片
  1284. * @param scaleWidth 缩放宽度倍数
  1285. * @param scaleHeight 缩放高度倍数
  1286. * @return 缩放压缩后的图片
  1287. */
  1288. public static Bitmap compressByScale(Bitmap src, float scaleWidth, float scaleHeight) {
  1289. return scale(src, scaleWidth, scaleHeight, false);
  1290. }
  1291. /**
  1292. * 按缩放压缩
  1293. *
  1294. * @param src 源图片
  1295. * @param scaleWidth 缩放宽度倍数
  1296. * @param scaleHeight 缩放高度倍数
  1297. * @param recycle 是否回收
  1298. * @return 缩放压缩后的图片
  1299. */
  1300. public static Bitmap compressByScale(Bitmap src, float scaleWidth, float scaleHeight, boolean recycle) {
  1301. return scale(src, scaleWidth, scaleHeight, recycle);
  1302. }
  1303. /**
  1304. * 按质量压缩
  1305. *
  1306. * @param src 源图片
  1307. * @param quality 质量
  1308. * @return 质量压缩后的图片
  1309. */
  1310. public static Bitmap compressByQuality(Bitmap src, int quality) {
  1311. return compressByQuality(src, quality, false);
  1312. }
  1313. /**
  1314. * 按质量压缩
  1315. *
  1316. * @param src 源图片
  1317. * @param quality 质量
  1318. * @param recycle 是否回收
  1319. * @return 质量压缩后的图片
  1320. */
  1321. public static Bitmap compressByQuality(Bitmap src, int quality, boolean recycle) {
  1322. if (isEmptyBitmap(src) || quality < 0 || quality > 100) return null;
  1323. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  1324. src.compress(Bitmap.CompressFormat.JPEG, quality, baos);
  1325. byte[] bytes = baos.toByteArray();
  1326. if (recycle && !src.isRecycled()) src.recycle();
  1327. return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
  1328. }
  1329. /**
  1330. * 按质量压缩
  1331. *
  1332. * @param src 源图片
  1333. * @param maxByteSize 允许最大值字节数
  1334. * @return 质量压缩压缩过的图片
  1335. */
  1336. public static Bitmap compressByQuality(Bitmap src, long maxByteSize) {
  1337. return compressByQuality(src, maxByteSize, false);
  1338. }
  1339. /**
  1340. * 按质量压缩
  1341. *
  1342. * @param src 源图片
  1343. * @param maxByteSize 允许最大值字节数
  1344. * @param recycle 是否回收
  1345. * @return 质量压缩压缩过的图片
  1346. */
  1347. public static Bitmap compressByQuality(Bitmap src, long maxByteSize, boolean recycle) {
  1348. if (isEmptyBitmap(src) || maxByteSize <= 0) return null;
  1349. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  1350. int quality = 100;
  1351. src.compress(CompressFormat.JPEG, quality, baos);
  1352. while (baos.toByteArray().length > maxByteSize && quality >= 0) {
  1353. baos.reset();
  1354. src.compress(CompressFormat.JPEG, quality -= 5, baos);
  1355. }
  1356. if (quality < 0) return null;
  1357. byte[] bytes = baos.toByteArray();
  1358. if (recycle && !src.isRecycled()) src.recycle();
  1359. return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
  1360. }
  1361. /**
  1362. * 按采样大小压缩
  1363. *
  1364. * @param src 源图片
  1365. * @param sampleSize 采样率大小
  1366. * @return 按采样率压缩后的图片
  1367. */
  1368. public static Bitmap compressBySampleSize(Bitmap src, int sampleSize) {
  1369. return compressBySampleSize(src, sampleSize, false);
  1370. }
  1371. /**
  1372. * 按采样大小压缩
  1373. *
  1374. * @param src 源图片
  1375. * @param sampleSize 采样率大小
  1376. * @param recycle 是否回收
  1377. * @return 按采样率压缩后的图片
  1378. */
  1379. public static Bitmap compressBySampleSize(Bitmap src, int sampleSize, boolean recycle) {
  1380. if (isEmptyBitmap(src)) return null;
  1381. BitmapFactory.Options options = new BitmapFactory.Options();
  1382. options.inSampleSize = sampleSize;
  1383. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  1384. src.compress(Bitmap.CompressFormat.JPEG, 100, baos);
  1385. byte[] bytes = baos.toByteArray();
  1386. if (recycle && !src.isRecycled()) src.recycle();
  1387. return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
  1388. }
  1389. }

IntentUtils

  1. package com.blankj.utilcode.utils;
  2. import android.content.ComponentName;
  3. import android.content.Context;
  4. import android.content.Intent;
  5. import android.net.Uri;
  6. import android.os.Build;
  7. import android.os.Bundle;
  8. import android.webkit.MimeTypeMap;
  9. import java.io.File;
  10. /**
  11. * <pre>
  12. * author: Blankj
  13. * blog : http://blankj.com
  14. * time : 2016/9/23
  15. * desc : Intent相关工具类
  16. * </pre>
  17. */
  18. public class IntentUtils {
  19. private IntentUtils() {
  20. throw new UnsupportedOperationException("u can't fuck me...");
  21. }
  22. /**
  23. * 获取安装App(支持6.0)的意图
  24. *
  25. * @param filePath 文件路径
  26. * @return 意图
  27. */
  28. public static Intent getInstallAppIntent(String filePath) {
  29. return getInstallAppIntent(FileUtils.getFileByPath(filePath));
  30. }
  31. /**
  32. * 获取安装App(支持6.0)的意图
  33. *
  34. * @param file 文件
  35. * @return 意图
  36. */
  37. public static Intent getInstallAppIntent(File file) {
  38. if (file == null) return null;
  39. Intent intent = new Intent(Intent.ACTION_VIEW);
  40. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  41. String type;
  42. if (Build.VERSION.SDK_INT < 23) {
  43. type = "application/vnd.android.package-archive";
  44. } else {
  45. type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(FileUtils.getFileExtension(file));
  46. }
  47. return intent.setDataAndType(Uri.fromFile(file), type);
  48. }
  49. /**
  50. * 获取卸载App的意图
  51. *
  52. * @param packageName 包名
  53. * @return 意图
  54. */
  55. public Intent getUninstallAppIntent(String packageName) {
  56. Intent intent = new Intent(Intent.ACTION_DELETE);
  57. intent.setData(Uri.parse("package:" + packageName));
  58. return intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  59. }
  60. /**
  61. * 获取打开App的意图
  62. *
  63. * @param context 上下文
  64. * @param packageName 包名
  65. * @return 意图
  66. */
  67. public static Intent getLaunchAppItent(Context context, String packageName) {
  68. return getIntentByPackageName(context, packageName);
  69. }
  70. /**
  71. * 获取App信息的意图
  72. *
  73. * @param packageName 包名
  74. * @return 意图
  75. */
  76. public static Intent getAppInfoIntent(String packageName) {
  77. Intent intent = new Intent("android.settings.APPLICATION_DETAILS_SETTINGS");
  78. return intent.setData(Uri.parse("package:" + packageName));
  79. }
  80. /**
  81. * 获取App信息分享的意图
  82. *
  83. * @param info 分享信息
  84. * @return 意图
  85. */
  86. public static Intent getShareInfoIntent(String info) {
  87. Intent intent = new Intent(Intent.ACTION_SEND);
  88. intent.setType("text/plain");
  89. return intent.putExtra(Intent.EXTRA_TEXT, info);
  90. }
  91. /**
  92. * 根据包名获取意图
  93. *
  94. * @param context 上下文
  95. * @param packageName 包名
  96. * @return 意图
  97. */
  98. private static Intent getIntentByPackageName(Context context, String packageName) {
  99. return context.getPackageManager().getLaunchIntentForPackage(packageName);
  100. }
  101. /**
  102. * 获取其他应用的Intent
  103. *
  104. * @param packageName 包名
  105. * @param className 全类名
  106. * @return 意图
  107. */
  108. public static Intent getComponentNameIntent(String packageName, String className) {
  109. return getComponentNameIntent(packageName, className, null);
  110. }
  111. /**
  112. * 获取其他应用的Intent
  113. *
  114. * @param packageName 包名
  115. * @param className 全类名
  116. * @return 意图
  117. */
  118. public static Intent getComponentNameIntent(String packageName, String className, Bundle bundle) {
  119. Intent intent = new Intent(Intent.ACTION_VIEW);
  120. if (bundle != null) intent.putExtras(bundle);
  121. ComponentName cn = new ComponentName(packageName, className);
  122. intent.setComponent(cn);
  123. return intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  124. }
  125. }

KeyboardUtils

  1. package com.blankj.utilcode.utils;
  2. import android.app.Activity;
  3. import android.content.Context;
  4. import android.util.Log;
  5. import android.view.View;
  6. import android.view.inputmethod.InputMethodManager;
  7. import android.widget.EditText;
  8. /**
  9. * <pre>
  10. * author: Blankj
  11. * blog : http://blankj.com
  12. * time : 2016/8/2
  13. * desc : 键盘相关工具类
  14. * </pre>
  15. */
  16. public class KeyboardUtils {
  17. private KeyboardUtils() {
  18. throw new UnsupportedOperationException("u can't fuck me...");
  19. }
  20. /**
  21. * 避免输入法面板遮挡
  22. * <p>在manifest.xml中activity中设置</p>
  23. * <p>android:windowSoftInputMode="stateVisible|adjustResize"</p>
  24. */
  25. /**
  26. * 动态隐藏软键盘
  27. *
  28. * @param activity activity
  29. */
  30. public static void hideSoftInput(Activity activity) {
  31. View view = activity.getWindow().peekDecorView();
  32. if (view != null) {
  33. InputMethodManager inputmanger = (InputMethodManager) activity
  34. .getSystemService(Context.INPUT_METHOD_SERVICE);
  35. inputmanger.hideSoftInputFromWindow(view.getWindowToken(), 0);
  36. }
  37. }
  38. /**
  39. * 动态隐藏软键盘
  40. *
  41. * @param context 上下文
  42. * @param edit 输入框
  43. */
  44. public static void hideSoftInput(Context context, EditText edit) {
  45. edit.clearFocus();
  46. InputMethodManager inputmanger = (InputMethodManager) context
  47. .getSystemService(Context.INPUT_METHOD_SERVICE);
  48. inputmanger.hideSoftInputFromWindow(edit.getWindowToken(), 0);
  49. }
  50. /**
  51. * 点击屏幕空白区域隐藏软键盘(方法1)
  52. * <p>在onTouch中处理,未获焦点则隐藏</p>
  53. * <p>参照以下注释代码</p>
  54. */
  55. public static void clickBlankArea2HideSoftInput0() {
  56. Log.i("tips", "U should copy the following code.");
  57. /*
  58. @Override
  59. public boolean onTouchEvent (MotionEvent event){
  60. if (null != this.getCurrentFocus()) {
  61. InputMethodManager mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
  62. return mInputMethodManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0);
  63. }
  64. return super.onTouchEvent(event);
  65. }
  66. */
  67. }
  68. /**
  69. * 点击屏幕空白区域隐藏软键盘(方法2)
  70. * <p>根据EditText所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘</p>
  71. * <p>需重写dispatchTouchEvent</p>
  72. * <p>参照以下注释代码</p>
  73. */
  74. public static void clickBlankArea2HideSoftInput1() {
  75. Log.i("tips", "U should copy the following code.");
  76. /*
  77. @Override
  78. public boolean dispatchTouchEvent(MotionEvent ev) {
  79. if (ev.getAction() == MotionEvent.ACTION_DOWN) {
  80. View v = getCurrentFocus();
  81. if (isShouldHideKeyboard(v, ev)) {
  82. hideKeyboard(v.getWindowToken());
  83. }
  84. }
  85. return super.dispatchTouchEvent(ev);
  86. }
  87. // 根据EditText所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘
  88. private boolean isShouldHideKeyboard(View v, MotionEvent event) {
  89. if (v != null && (v instanceof EditText)) {
  90. int[] l = {0, 0};
  91. v.getLocationInWindow(l);
  92. int left = l[0],
  93. top = l[1],
  94. bottom = top + v.getHeight(),
  95. right = left + v.getWidth();
  96. return !(event.getX() > left && event.getX() < right
  97. && event.getY() > top && event.getY() < bottom);
  98. }
  99. return false;
  100. }
  101. // 获取InputMethodManager,隐藏软键盘
  102. private void hideKeyboard(IBinder token) {
  103. if (token != null) {
  104. InputMethodManager im = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
  105. im.hideSoftInputFromWindow(token, InputMethodManager.HIDE_NOT_ALWAYS);
  106. }
  107. }
  108. */
  109. }
  110. /**
  111. * 动态显示软键盘
  112. *
  113. * @param context 上下文
  114. * @param edit 输入框
  115. */
  116. public static void showSoftInput(Context context, EditText edit) {
  117. edit.setFocusable(true);
  118. edit.setFocusableInTouchMode(true);
  119. edit.requestFocus();
  120. InputMethodManager inputManager = (InputMethodManager) context
  121. .getSystemService(Context.INPUT_METHOD_SERVICE);
  122. inputManager.showSoftInput(edit, 0);
  123. }
  124. /**
  125. * 切换键盘显示与否状态
  126. *
  127. * @param context 上下文
  128. * @param edit 输入框
  129. */
  130. public static void toggleSoftInput(Context context, EditText edit) {
  131. edit.setFocusable(true);
  132. edit.setFocusableInTouchMode(true);
  133. edit.requestFocus();
  134. InputMethodManager inputManager = (InputMethodManager) context
  135. .getSystemService(Context.INPUT_METHOD_SERVICE);
  136. inputManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
  137. }
  138. }

LogUtils

  1. package com.blankj.utilcode.utils;
  2. import android.content.Context;
  3. import android.os.Environment;
  4. import android.util.Log;
  5. import java.io.BufferedWriter;
  6. import java.io.File;
  7. import java.io.FileWriter;
  8. import java.io.IOException;
  9. import java.text.SimpleDateFormat;
  10. import java.util.Calendar;
  11. import java.util.Date;
  12. /**
  13. * <pre>
  14. * author: Blankj
  15. * blog : http://blankj.com
  16. * time : 2016/9/21
  17. * desc :
  18. * </pre>
  19. */
  20. public class LogUtils {
  21. private static Boolean LOG_SWITCH = true; // 日志文件总开关
  22. private static Boolean LOG_TO_FILE = false; // 日志写入文件开关
  23. private static String LOG_TAG = "TAG"; // 默认的tag
  24. private static char LOG_TYPE = 'v';// 输入日志类型,v代表输出所有信息,w则只输出警告...
  25. private static int LOG_SAVE_DAYS = 7;// sd卡中日志文件的最多保存天数
  26. private final static SimpleDateFormat LOG_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 日志的输出格式
  27. private final static SimpleDateFormat FILE_SUFFIX = new SimpleDateFormat("yyyy-MM-dd");// 日志文件格式
  28. private static String LOG_FILE_PATH; // 日志文件保存路径
  29. private static String LOG_FILE_NAME;// 日志文件保存名称
  30. public static void init(Context context) { // 在Application中初始化
  31. LOG_FILE_PATH = Environment.getExternalStorageDirectory().getPath() + File.separator + context.getPackageName();
  32. LOG_FILE_NAME = "Log";
  33. }
  34. /****************************
  35. * Warn
  36. *********************************/
  37. public static void w(Object msg) {
  38. w(LOG_TAG, msg);
  39. }
  40. public static void w(String tag, Object msg) {
  41. w(tag, msg, null);
  42. }
  43. public static void w(String tag, Object msg, Throwable tr) {
  44. log(tag, msg.toString(), tr, 'w');
  45. }
  46. /***************************
  47. * Error
  48. ********************************/
  49. public static void e(Object msg) {
  50. e(LOG_TAG, msg);
  51. }
  52. public static void e(String tag, Object msg) {
  53. e(tag, msg, null);
  54. }
  55. public static void e(String tag, Object msg, Throwable tr) {
  56. log(tag, msg.toString(), tr, 'e');
  57. }
  58. /***************************
  59. * Debug
  60. ********************************/
  61. public static void d(Object msg) {
  62. d(LOG_TAG, msg);
  63. }
  64. public static void d(String tag, Object msg) {// 调试信息
  65. d(tag, msg, null);
  66. }
  67. public static void d(String tag, Object msg, Throwable tr) {
  68. log(tag, msg.toString(), tr, 'd');
  69. }
  70. /****************************
  71. * Info
  72. *********************************/
  73. public static void i(Object msg) {
  74. i(LOG_TAG, msg);
  75. }
  76. public static void i(String tag, Object msg) {
  77. i(tag, msg, null);
  78. }
  79. public static void i(String tag, Object msg, Throwable tr) {
  80. log(tag, msg.toString(), tr, 'i');
  81. }
  82. /**************************
  83. * Verbose
  84. ********************************/
  85. public static void v(Object msg) {
  86. v(LOG_TAG, msg);
  87. }
  88. public static void v(String tag, Object msg) {
  89. v(tag, msg, null);
  90. }
  91. public static void v(String tag, Object msg, Throwable tr) {
  92. log(tag, msg.toString(), tr, 'v');
  93. }
  94. /**
  95. * 根据tag, msg和等级,输出日志
  96. *
  97. * @param tag
  98. * @param msg
  99. * @param level
  100. */
  101. private static void log(String tag, String msg, Throwable tr, char level) {
  102. if (LOG_SWITCH) {
  103. if ('e' == level && ('e' == LOG_TYPE || 'v' == LOG_TYPE)) { // 输出错误信息
  104. Log.e(tag, msg, tr);
  105. } else if ('w' == level && ('w' == LOG_TYPE || 'v' == LOG_TYPE)) {
  106. Log.w(tag, msg, tr);
  107. } else if ('d' == level && ('d' == LOG_TYPE || 'v' == LOG_TYPE)) {
  108. Log.d(tag, msg, tr);
  109. } else if ('i' == level && ('d' == LOG_TYPE || 'v' == LOG_TYPE)) {
  110. Log.i(tag, msg, tr);
  111. } else {
  112. Log.v(tag, msg, tr);
  113. }
  114. if (LOG_TO_FILE)
  115. log2File(String.valueOf(level), tag, msg + tr == null ? "" : "\n" + Log.getStackTraceString(tr));
  116. }
  117. }
  118. /**
  119. * 打开日志文件并写入日志
  120. *
  121. * @return
  122. **/
  123. private synchronized static void log2File(String mylogtype, String tag, String text) {
  124. Date nowtime = new Date();
  125. String date = FILE_SUFFIX.format(nowtime);
  126. String dateLogContent = LOG_FORMAT.format(nowtime) + ":" + mylogtype + ":" + tag + ":" + text; // 日志输出格式
  127. File destDir = new File(LOG_FILE_PATH);
  128. if (!destDir.exists()) {
  129. destDir.mkdirs();
  130. }
  131. File file = new File(LOG_FILE_PATH, LOG_FILE_NAME + date);
  132. try {
  133. FileWriter filerWriter = new FileWriter(file, true);
  134. BufferedWriter bufWriter = new BufferedWriter(filerWriter);
  135. bufWriter.write(dateLogContent);
  136. bufWriter.newLine();
  137. bufWriter.close();
  138. filerWriter.close();
  139. } catch (IOException e) {
  140. e.printStackTrace();
  141. }
  142. }
  143. /**
  144. * 删除指定的日志文件
  145. */
  146. public static void delFile() {// 删除日志文件
  147. String needDelFiel = FILE_SUFFIX.format(getDateBefore());
  148. File file = new File(LOG_FILE_PATH, needDelFiel + LOG_FILE_NAME);
  149. if (file.exists()) {
  150. file.delete();
  151. }
  152. }
  153. /**
  154. * 得到LOG_SAVE_DAYS天前的日期
  155. *
  156. * @return
  157. */
  158. private static Date getDateBefore() {
  159. Date nowtime = new Date();
  160. Calendar now = Calendar.getInstance();
  161. now.setTime(nowtime);
  162. now.set(Calendar.DATE, now.get(Calendar.DATE) - LOG_SAVE_DAYS);
  163. return now.getTime();
  164. }
  165. }

NetworkUtils

  1. package com.blankj.utilcode.utils;
  2. import android.content.Context;
  3. import android.content.Intent;
  4. import android.net.ConnectivityManager;
  5. import android.net.NetworkInfo;
  6. import android.telephony.TelephonyManager;
  7. /**
  8. * <pre>
  9. * author: Blankj
  10. * blog : http://blankj.com
  11. * time : 2016/8/2
  12. * desc : 网络相关工具类
  13. * </pre>
  14. */
  15. public class NetworkUtils {
  16. private NetworkUtils() {
  17. throw new UnsupportedOperationException("u can't fuck me...");
  18. }
  19. public static final int NETWORK_WIFI = 1; // wifi network
  20. public static final int NETWORK_4G = 4; // "4G" networks
  21. public static final int NETWORK_3G = 3; // "3G" networks
  22. public static final int NETWORK_2G = 2; // "2G" networks
  23. public static final int NETWORK_UNKNOWN = 5; // unknown network
  24. public static final int NETWORK_NO = -1; // no network
  25. private static final int NETWORK_TYPE_GSM = 16;
  26. private static final int NETWORK_TYPE_TD_SCDMA = 17;
  27. private static final int NETWORK_TYPE_IWLAN = 18;
  28. /**
  29. * 打开网络设置界面
  30. * <p>3.0以下打开设置界面</p>
  31. *
  32. * @param context 上下文
  33. */
  34. public static void openWirelessSettings(Context context) {
  35. if (android.os.Build.VERSION.SDK_INT > 10) {
  36. context.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS));
  37. } else {
  38. context.startActivity(new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS));
  39. }
  40. }
  41. /**
  42. * 获取活动网络信息
  43. *
  44. * @param context 上下文
  45. * @return NetworkInfo
  46. */
  47. private static NetworkInfo getActiveNetworkInfo(Context context) {
  48. ConnectivityManager cm = (ConnectivityManager) context
  49. .getSystemService(Context.CONNECTIVITY_SERVICE);
  50. return cm.getActiveNetworkInfo();
  51. }
  52. /**
  53. * 判断网络是否可用
  54. * <p>需添加权限 {@code <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>}</p>
  55. *
  56. * @param context 上下文
  57. * @return {@code true}: 可用<br>{@code false}: 不可用
  58. */
  59. public static boolean isAvailable(Context context) {
  60. NetworkInfo info = getActiveNetworkInfo(context);
  61. return info != null && info.isAvailable();
  62. }
  63. /**
  64. * 判断网络是否连接
  65. * <p>需添加权限 {@code <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>}</p>
  66. *
  67. * @param context 上下文
  68. * @return {@code true}: 是<br>{@code false}: 否
  69. */
  70. public static boolean isConnected(Context context) {
  71. NetworkInfo info = getActiveNetworkInfo(context);
  72. return info != null && info.isConnected();
  73. }
  74. /**
  75. * 判断网络是否是4G
  76. * <p>需添加权限 {@code <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>}</p>
  77. *
  78. * @param context 上下文
  79. * @return {@code true}: 是<br>{@code false}: 不是
  80. */
  81. public static boolean is4G(Context context) {
  82. NetworkInfo info = getActiveNetworkInfo(context);
  83. return info != null && info.isAvailable() && info.getSubtype() == TelephonyManager.NETWORK_TYPE_LTE;
  84. }
  85. /**
  86. * 判断wifi是否连接状态
  87. * <p>需添加权限 {@code <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>}</p>
  88. *
  89. * @param context 上下文
  90. * @return {@code true}: 连接<br>{@code false}: 未连接
  91. */
  92. public static boolean isWifiConnected(Context context) {
  93. ConnectivityManager cm = (ConnectivityManager) context
  94. .getSystemService(Context.CONNECTIVITY_SERVICE);
  95. return cm != null && cm.getActiveNetworkInfo() != null
  96. && cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI;
  97. }
  98. /**
  99. * 获取移动网络运营商名称
  100. * <p>如中国联通、中国移动、中国电信</p>
  101. *
  102. * @param context 上下文
  103. * @return 移动网络运营商名称
  104. */
  105. public static String getNetworkOperatorName(Context context) {
  106. TelephonyManager tm = (TelephonyManager) context
  107. .getSystemService(Context.TELEPHONY_SERVICE);
  108. return tm != null ? tm.getNetworkOperatorName() : null;
  109. }
  110. /**
  111. * 获取移动终端类型
  112. *
  113. * @param context 上下文
  114. * @return 手机制式
  115. * <ul>
  116. * <li>{@link TelephonyManager#PHONE_TYPE_NONE } : 0 手机制式未知</li>
  117. * <li>{@link TelephonyManager#PHONE_TYPE_GSM } : 1 手机制式为GSM,移动和联通</li>
  118. * <li>{@link TelephonyManager#PHONE_TYPE_CDMA } : 2 手机制式为CDMA,电信</li>
  119. * <li>{@link TelephonyManager#PHONE_TYPE_SIP } : 3</li>
  120. * </ul>
  121. */
  122. public static int getPhoneType(Context context) {
  123. TelephonyManager tm = (TelephonyManager) context
  124. .getSystemService(Context.TELEPHONY_SERVICE);
  125. return tm != null ? tm.getPhoneType() : -1;
  126. }
  127. /**
  128. * 获取当前的网络类型(WIFI,2G,3G,4G)
  129. * <p>需添加权限 {@code <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>}</p>
  130. *
  131. * @param context 上下文
  132. * @return 网络类型
  133. * <ul>
  134. * <li>{@link #NETWORK_WIFI } = 1;</li>
  135. * <li>{@link #NETWORK_4G } = 4;</li>
  136. * <li>{@link #NETWORK_3G } = 3;</li>
  137. * <li>{@link #NETWORK_2G } = 2;</li>
  138. * <li>{@link #NETWORK_UNKNOWN} = 5;</li>
  139. * <li>{@link #NETWORK_NO } = -1;</li>
  140. * </ul>
  141. */
  142. public static int getNetWorkType(Context context) {
  143. int netType = NETWORK_NO;
  144. NetworkInfo info = getActiveNetworkInfo(context);
  145. if (info != null && info.isAvailable()) {
  146. if (info.getType() == ConnectivityManager.TYPE_WIFI) {
  147. netType = NETWORK_WIFI;
  148. } else if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
  149. switch (info.getSubtype()) {
  150. case NETWORK_TYPE_GSM:
  151. case TelephonyManager.NETWORK_TYPE_GPRS:
  152. case TelephonyManager.NETWORK_TYPE_CDMA:
  153. case TelephonyManager.NETWORK_TYPE_EDGE:
  154. case TelephonyManager.NETWORK_TYPE_1xRTT:
  155. case TelephonyManager.NETWORK_TYPE_IDEN:
  156. netType = NETWORK_2G;
  157. break;
  158. case NETWORK_TYPE_TD_SCDMA:
  159. case TelephonyManager.NETWORK_TYPE_EVDO_A:
  160. case TelephonyManager.NETWORK_TYPE_UMTS:
  161. case TelephonyManager.NETWORK_TYPE_EVDO_0:
  162. case TelephonyManager.NETWORK_TYPE_HSDPA:
  163. case TelephonyManager.NETWORK_TYPE_HSUPA:
  164. case TelephonyManager.NETWORK_TYPE_HSPA:
  165. case TelephonyManager.NETWORK_TYPE_EVDO_B:
  166. case TelephonyManager.NETWORK_TYPE_EHRPD:
  167. case TelephonyManager.NETWORK_TYPE_HSPAP:
  168. netType = NETWORK_3G;
  169. break;
  170. case NETWORK_TYPE_IWLAN:
  171. case TelephonyManager.NETWORK_TYPE_LTE:
  172. netType = NETWORK_4G;
  173. break;
  174. default:
  175. String subtypeName = info.getSubtypeName();
  176. if (subtypeName.equalsIgnoreCase("TD-SCDMA")
  177. || subtypeName.equalsIgnoreCase("WCDMA")
  178. || subtypeName.equalsIgnoreCase("CDMA2000")) {
  179. netType = NETWORK_3G;
  180. } else {
  181. netType = NETWORK_UNKNOWN;
  182. }
  183. break;
  184. }
  185. } else {
  186. netType = NETWORK_UNKNOWN;
  187. }
  188. }
  189. return netType;
  190. }
  191. /**
  192. * 获取当前的网络类型(WIFI,2G,3G,4G)
  193. * <p>依赖上面的方法</p>
  194. *
  195. * @param context 上下文
  196. * @return 网络类型名称
  197. * <ul>
  198. * <li>NETWORK_WIFI </li>
  199. * <li>NETWORK_4G </li>
  200. * <li>NETWORK_3G </li>
  201. * <li>NETWORK_2G </li>
  202. * <li>NETWORK_UNKNOWN</li>
  203. * <li>NETWORK_NO </li>
  204. * </ul>
  205. */
  206. public static String getNetWorkTypeName(Context context) {
  207. switch (getNetWorkType(context)) {
  208. case NETWORK_WIFI:
  209. return "NETWORK_WIFI";
  210. case NETWORK_4G:
  211. return "NETWORK_4G";
  212. case NETWORK_3G:
  213. return "NETWORK_3G";
  214. case NETWORK_2G:
  215. return "NETWORK_2G";
  216. case NETWORK_NO:
  217. return "NETWORK_NO";
  218. default:
  219. return "NETWORK_UNKNOWN";
  220. }
  221. }
  222. }

PhoneUtils

  1. package com.blankj.utilcode.utils;
  2. import android.content.ContentResolver;
  3. import android.content.Context;
  4. import android.content.Intent;
  5. import android.database.Cursor;
  6. import android.net.Uri;
  7. import android.os.SystemClock;
  8. import android.provider.Settings;
  9. import android.telephony.TelephonyManager;
  10. import android.util.Log;
  11. import android.util.Xml;
  12. import org.xmlpull.v1.XmlSerializer;
  13. import java.io.File;
  14. import java.io.FileOutputStream;
  15. import java.util.ArrayList;
  16. import java.util.HashMap;
  17. import java.util.List;
  18. /**
  19. * <pre>
  20. * author: Blankj
  21. * blog : http://blankj.com
  22. * time : 2016/8/2
  23. * desc : 手机相关工具类
  24. * </pre>
  25. */
  26. public class PhoneUtils {
  27. private PhoneUtils() {
  28. throw new UnsupportedOperationException("u can't fuck me...");
  29. }
  30. /**
  31. * 判断设备是否是手机
  32. *
  33. * @param context 上下文
  34. * @return {@code true}: 是<br>{@code false}: 否
  35. */
  36. public static boolean isPhone(Context context) {
  37. TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
  38. return tm.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
  39. }
  40. /**
  41. * 获取手机的IMIE
  42. * <p>需与{@link #isPhone(Context)}一起使用</p>
  43. * <p>需添加权限 {@code <uses-permission android:name="android.permission.READ_PHONE_STATE"/>}</p>
  44. *
  45. * @param context 上下文
  46. * @return IMIE码
  47. */
  48. public static String getPhoneIMEI(Context context) {
  49. String deviceId;
  50. if (isPhone(context)) {
  51. TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
  52. deviceId = tm.getDeviceId();
  53. } else {
  54. deviceId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
  55. }
  56. return deviceId;
  57. }
  58. /**
  59. * 获取手机状态信息
  60. * <p>需添加权限 {@code <uses-permission android:name="android.permission.READ_PHONE_STATE"/>}</p>
  61. *
  62. * @param context 上下文
  63. * @return DeviceId(IMEI) = 99000311726612<br>
  64. * DeviceSoftwareVersion = 00<br>
  65. * Line1Number =<br>
  66. * NetworkCountryIso = cn<br>
  67. * NetworkOperator = 46003<br>
  68. * NetworkOperatorName = 中国电信<br>
  69. * NetworkType = 6<br>
  70. * honeType = 2<br>
  71. * SimCountryIso = cn<br>
  72. * SimOperator = 46003<br>
  73. * SimOperatorName = 中国电信<br>
  74. * SimSerialNumber = 89860315045710604022<br>
  75. * SimState = 5<br>
  76. * SubscriberId(IMSI) = 460030419724900<br>
  77. * VoiceMailNumber = *86<br>
  78. */
  79. public static String getPhoneStatus(Context context) {
  80. TelephonyManager tm = (TelephonyManager) context
  81. .getSystemService(Context.TELEPHONY_SERVICE);
  82. String str = "";
  83. str += "DeviceId(IMEI) = " + tm.getDeviceId() + "\n";
  84. str += "DeviceSoftwareVersion = " + tm.getDeviceSoftwareVersion() + "\n";
  85. str += "Line1Number = " + tm.getLine1Number() + "\n";
  86. str += "NetworkCountryIso = " + tm.getNetworkCountryIso() + "\n";
  87. str += "NetworkOperator = " + tm.getNetworkOperator() + "\n";
  88. str += "NetworkOperatorName = " + tm.getNetworkOperatorName() + "\n";
  89. str += "NetworkType = " + tm.getNetworkType() + "\n";
  90. str += "honeType = " + tm.getPhoneType() + "\n";
  91. str += "SimCountryIso = " + tm.getSimCountryIso() + "\n";
  92. str += "SimOperator = " + tm.getSimOperator() + "\n";
  93. str += "SimOperatorName = " + tm.getSimOperatorName() + "\n";
  94. str += "SimSerialNumber = " + tm.getSimSerialNumber() + "\n";
  95. str += "SimState = " + tm.getSimState() + "\n";
  96. str += "SubscriberId(IMSI) = " + tm.getSubscriberId() + "\n";
  97. str += "VoiceMailNumber = " + tm.getVoiceMailNumber() + "\n";
  98. return str;
  99. }
  100. /**
  101. * 跳至填充好phoneNumber的拨号界面
  102. *
  103. * @param context 上下文
  104. * @param phoneNumber 电话号码
  105. */
  106. public static void dial(Context context, String phoneNumber) {
  107. context.startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phoneNumber)));
  108. }
  109. /**
  110. * 拨打phoneNumber
  111. * <p>需添加权限 {@code <uses-permission android:name="android.permission.CALL_PHONE"/>}</p>
  112. *
  113. * @param context 上下文
  114. * @param phoneNumber 电话号码
  115. */
  116. public static void call(Context context, String phoneNumber) {
  117. context.startActivity(new Intent("android.intent.action.CALL", Uri.parse("tel:" + phoneNumber)));
  118. }
  119. /**
  120. * 发送短信
  121. *
  122. * @param context 上下文
  123. * @param phoneNumber 电话号码
  124. * @param content 内容
  125. */
  126. public static void sendSms(Context context, String phoneNumber, String content) {
  127. Uri uri = Uri.parse("smsto:" + (StringUtils.isEmpty(phoneNumber) ? "" : phoneNumber));
  128. Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
  129. intent.putExtra("sms_body", StringUtils.isEmpty(content) ? "" : content);
  130. context.startActivity(intent);
  131. }
  132. /**
  133. * 获取手机联系人
  134. * <p>需添加权限 {@code <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>}</p>
  135. * <p>需添加权限 {@code <uses-permission android:name="android.permission.READ_CONTACTS"/>}</p>
  136. *
  137. * @param context 上下文;
  138. * @return 联系人链表
  139. */
  140. public static List<HashMap<String, String>> getAllContactInfo(Context context) {
  141. SystemClock.sleep(3000);
  142. ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
  143. // 1.获取内容解析者
  144. ContentResolver resolver = context.getContentResolver();
  145. // 2.获取内容提供者的地址:com.android.contacts
  146. // raw_contacts表的地址 :raw_contacts
  147. // view_data表的地址 : data
  148. // 3.生成查询地址
  149. Uri raw_uri = Uri.parse("content://com.android.contacts/raw_contacts");
  150. Uri date_uri = Uri.parse("content://com.android.contacts/data");
  151. // 4.查询操作,先查询raw_contacts,查询contact_id
  152. // projection : 查询的字段
  153. Cursor cursor = resolver.query(raw_uri, new String[]{"contact_id"},
  154. null, null, null);
  155. // 5.解析cursor
  156. while (cursor.moveToNext()) {
  157. // 6.获取查询的数据
  158. String contact_id = cursor.getString(0);
  159. // cursor.getString(cursor.getColumnIndex("contact_id"));//getColumnIndex
  160. // : 查询字段在cursor中索引值,一般都是用在查询字段比较多的时候
  161. // 判断contact_id是否为空
  162. if (!StringUtils.isEmpty(contact_id)) {//null ""
  163. // 7.根据contact_id查询view_data表中的数据
  164. // selection : 查询条件
  165. // selectionArgs :查询条件的参数
  166. // sortOrder : 排序
  167. // 空指针: 1.null.方法 2.参数为null
  168. Cursor c = resolver.query(date_uri, new String[]{"data1",
  169. "mimetype"}, "raw_contact_id=?",
  170. new String[]{contact_id}, null);
  171. HashMap<String, String> map = new HashMap<String, String>();
  172. // 8.解析c
  173. while (c.moveToNext()) {
  174. // 9.获取数据
  175. String data1 = c.getString(0);
  176. String mimetype = c.getString(1);
  177. // 10.根据类型去判断获取的data1数据并保存
  178. if (mimetype.equals("vnd.android.cursor.item/phone_v2")) {
  179. // 电话
  180. map.put("phone", data1);
  181. } else if (mimetype.equals("vnd.android.cursor.item/name")) {
  182. // 姓名
  183. map.put("name", data1);
  184. }
  185. }
  186. // 11.添加到集合中数据
  187. list.add(map);
  188. // 12.关闭cursor
  189. c.close();
  190. }
  191. }
  192. // 12.关闭cursor
  193. cursor.close();
  194. return list;
  195. }
  196. /**
  197. * 打开手机联系人界面点击联系人后便获取该号码
  198. * <p>参照以下注释代码</p>
  199. */
  200. public static void getContantNum() {
  201. Log.i("tips", "U should copy the following code.");
  202. /*
  203. Intent intent = new Intent();
  204. intent.setAction("android.intent.action.PICK");
  205. intent.setType("vnd.android.cursor.dir/phone_v2");
  206. startActivityForResult(intent, 0);
  207. @Override
  208. protected void onActivityResult ( int requestCode, int resultCode, Intent data){
  209. super.onActivityResult(requestCode, resultCode, data);
  210. if (data != null) {
  211. Uri uri = data.getData();
  212. String num = null;
  213. // 创建内容解析者
  214. ContentResolver contentResolver = getContentResolver();
  215. Cursor cursor = contentResolver.query(uri,
  216. null, null, null, null);
  217. while (cursor.moveToNext()) {
  218. num = cursor.getString(cursor.getColumnIndex("data1"));
  219. }
  220. cursor.close();
  221. num = num.replaceAll("-", "");//替换的操作,555-6 -> 5556
  222. }
  223. }
  224. */
  225. }
  226. /**
  227. * 获取手机短信并保存到xml中
  228. * <p>需添加权限 {@code <uses-permission android:name="android.permission.READ_SMS"/>}</p>
  229. * <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p>
  230. *
  231. * @param context 上下文
  232. */
  233. public static void getAllSMS(Context context) {
  234. // 1.获取短信
  235. // 1.1获取内容解析者
  236. ContentResolver resolver = context.getContentResolver();
  237. // 1.2获取内容提供者地址 sms,sms表的地址:null 不写
  238. // 1.3获取查询路径
  239. Uri uri = Uri.parse("content://sms");
  240. // 1.4.查询操作
  241. // projection : 查询的字段
  242. // selection : 查询的条件
  243. // selectionArgs : 查询条件的参数
  244. // sortOrder : 排序
  245. Cursor cursor = resolver.query(uri, new String[]{"address", "date", "type", "body"}, null, null, null);
  246. // 设置最大进度
  247. int count = cursor.getCount();//获取短信的个数
  248. // 2.备份短信
  249. // 2.1获取xml序列器
  250. XmlSerializer xmlSerializer = Xml.newSerializer();
  251. try {
  252. // 2.2设置xml文件保存的路径
  253. // os : 保存的位置
  254. // encoding : 编码格式
  255. xmlSerializer.setOutput(new FileOutputStream(new File("/mnt/sdcard/backupsms.xml")), "utf-8");
  256. // 2.3设置头信息
  257. // standalone : 是否独立保存
  258. xmlSerializer.startDocument("utf-8", true);
  259. // 2.4设置根标签
  260. xmlSerializer.startTag(null, "smss");
  261. // 1.5.解析cursor
  262. while (cursor.moveToNext()) {
  263. SystemClock.sleep(1000);
  264. // 2.5设置短信的标签
  265. xmlSerializer.startTag(null, "sms");
  266. // 2.6设置文本内容的标签
  267. xmlSerializer.startTag(null, "address");
  268. String address = cursor.getString(0);
  269. // 2.7设置文本内容
  270. xmlSerializer.text(address);
  271. xmlSerializer.endTag(null, "address");
  272. xmlSerializer.startTag(null, "date");
  273. String date = cursor.getString(1);
  274. xmlSerializer.text(date);
  275. xmlSerializer.endTag(null, "date");
  276. xmlSerializer.startTag(null, "type");
  277. String type = cursor.getString(2);
  278. xmlSerializer.text(type);
  279. xmlSerializer.endTag(null, "type");
  280. xmlSerializer.startTag(null, "body");
  281. String body = cursor.getString(3);
  282. xmlSerializer.text(body);
  283. xmlSerializer.endTag(null, "body");
  284. xmlSerializer.endTag(null, "sms");
  285. System.out.println("address:" + address + " date:" + date + " type:" + type + " body:" + body);
  286. }
  287. xmlSerializer.endTag(null, "smss");
  288. xmlSerializer.endDocument();
  289. // 2.8将数据刷新到文件中
  290. xmlSerializer.flush();
  291. } catch (Exception e) {
  292. e.printStackTrace();
  293. }
  294. }
  295. }

RegexUtils

  1. package com.blankj.utilcode.utils;
  2. import java.util.regex.Pattern;
  3. import static com.blankj.utilcode.utils.ConstUtils.*;
  4. /**
  5. * <pre>
  6. * author: Blankj
  7. * blog : http://blankj.com
  8. * time : 2016/8/2
  9. * desc : 正则相关工具类
  10. * </pre>
  11. */
  12. public class RegexUtils {
  13. private RegexUtils() {
  14. throw new UnsupportedOperationException("u can't fuck me...");
  15. }
  16. /**
  17. * If u want more please visit http://toutiao.com/i6231678548520731137/
  18. */
  19. /**
  20. * 验证手机号(简单)
  21. *
  22. * @param string 待验证文本
  23. * @return {@code true}: 匹配<br>{@code false}: 不匹配
  24. */
  25. public static boolean isMobileSimple(String string) {
  26. return isMatch(REGEX_MOBILE_SIMPLE, string);
  27. }
  28. /**
  29. * 验证手机号(精确)
  30. *
  31. * @param string 待验证文本
  32. * @return {@code true}: 匹配<br>{@code false}: 不匹配
  33. */
  34. public static boolean isMobileExact(String string) {
  35. return isMatch(REGEX_MOBILE_EXACT, string);
  36. }
  37. /**
  38. * 验证电话号码
  39. *
  40. * @param string 待验证文本
  41. * @return {@code true}: 匹配<br>{@code false}: 不匹配
  42. */
  43. public static boolean isTel(String string) {
  44. return isMatch(REGEX_TEL, string);
  45. }
  46. /**
  47. * 验证身份证号码15位
  48. *
  49. * @param string 待验证文本
  50. * @return {@code true}: 匹配<br>{@code false}: 不匹配
  51. */
  52. public static boolean isIDCard15(String string) {
  53. return isMatch(REGEX_IDCARD15, string);
  54. }
  55. /**
  56. * 验证身份证号码18位
  57. *
  58. * @param string 待验证文本
  59. * @return {@code true}: 匹配<br>{@code false}: 不匹配
  60. */
  61. public static boolean isIDCard18(String string) {
  62. return isMatch(REGEX_IDCARD18, string);
  63. }
  64. /**
  65. * 验证邮箱
  66. *
  67. * @param string 待验证文本
  68. * @return {@code true}: 匹配<br>{@code false}: 不匹配
  69. */
  70. public static boolean isEmail(String string) {
  71. return isMatch(REGEX_EMAIL, string);
  72. }
  73. /**
  74. * 验证URL
  75. *
  76. * @param string 待验证文本
  77. * @return {@code true}: 匹配<br>{@code false}: 不匹配
  78. */
  79. public static boolean isURL(String string) {
  80. return isMatch(REGEX_URL, string);
  81. }
  82. /**
  83. * 验证汉字
  84. *
  85. * @param string 待验证文本
  86. * @return {@code true}: 匹配<br>{@code false}: 不匹配
  87. */
  88. public static boolean isChz(String string) {
  89. return isMatch(REGEX_CHZ, string);
  90. }
  91. /**
  92. * 验证用户名
  93. * <p>取值范围为a-z,A-Z,0-9,"_",汉字,不能以"_"结尾,用户名必须是6-20位</p>
  94. *
  95. * @param string 待验证文本
  96. * @return {@code true}: 匹配<br>{@code false}: 不匹配
  97. */
  98. public static boolean isUsername(String string) {
  99. return isMatch(REGEX_USERNAME, string);
  100. }
  101. /**
  102. * 验证yyyy-MM-dd格式的日期校验,已考虑平闰年
  103. *
  104. * @param string 待验证文本
  105. * @return {@code true}: 匹配<br>{@code false}: 不匹配
  106. */
  107. public static boolean isDate(String string) {
  108. return isMatch(REGEX_DATE, string);
  109. }
  110. /**
  111. * 验证IP地址
  112. *
  113. * @param string 待验证文本
  114. * @return {@code true}: 匹配<br>{@code false}: 不匹配
  115. */
  116. public static boolean isIP(String string) {
  117. return isMatch(REGEX_IP, string);
  118. }
  119. /**
  120. * string是否匹配regex
  121. *
  122. * @param regex 正则表达式字符串
  123. * @param string 要匹配的字符串
  124. * @return {@code true}: 匹配<br>{@code false}: 不匹配
  125. */
  126. public static boolean isMatch(String regex, String string) {
  127. return !StringUtils.isEmpty(string) && Pattern.matches(regex, string);
  128. }
  129. }

ScreenUtils

  1. package com.blankj.utilcode.utils;
  2. import android.app.Activity;
  3. import android.app.KeyguardManager;
  4. import android.content.Context;
  5. import android.content.pm.ActivityInfo;
  6. import android.content.res.Configuration;
  7. import android.graphics.Bitmap;
  8. import android.util.DisplayMetrics;
  9. import android.view.Surface;
  10. import android.view.View;
  11. import android.view.WindowManager;
  12. /**
  13. * <pre>
  14. * author: Blankj
  15. * blog : http://blankj.com
  16. * time : 2016/8/2
  17. * desc : 屏幕相关工具类
  18. * </pre>
  19. */
  20. public class ScreenUtils {
  21. private ScreenUtils() {
  22. throw new UnsupportedOperationException("u can't fuck me...");
  23. }
  24. /**
  25. * 获取屏幕的宽度px
  26. *
  27. * @param context 上下文
  28. * @return 屏幕宽px
  29. */
  30. public static int getScreenWidth(Context context) {
  31. WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
  32. DisplayMetrics outMetrics = new DisplayMetrics();// 创建了一张白纸
  33. windowManager.getDefaultDisplay().getMetrics(outMetrics);// 给白纸设置宽高
  34. return outMetrics.widthPixels;
  35. }
  36. /**
  37. * 获取屏幕的高度px
  38. *
  39. * @param context 上下文
  40. * @return 屏幕高px
  41. */
  42. public static int getScreenHeight(Context context) {
  43. WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
  44. DisplayMetrics outMetrics = new DisplayMetrics();// 创建了一张白纸
  45. windowManager.getDefaultDisplay().getMetrics(outMetrics);// 给白纸设置宽高
  46. return outMetrics.heightPixels;
  47. }
  48. /**
  49. * 设置屏幕为横屏
  50. * <p>还有一种就是在Activity中加属性android:screenOrientation="landscape"</p>
  51. * <p>不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次</p>
  52. * <p>设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次</p>
  53. * <p>设置Activity的android:configChanges="orientation|keyboardHidden|screenSize"(4.0以上必须带最后一个参数)时
  54. * 切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法</p>
  55. *
  56. * @param activity activity
  57. */
  58. public static void setLandscape(Activity activity) {
  59. activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
  60. }
  61. /**
  62. * 设置屏幕为竖屏
  63. *
  64. * @param activity activity
  65. */
  66. public static void setPortrait(Activity activity) {
  67. activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
  68. }
  69. /**
  70. * 判断是否横屏
  71. *
  72. * @param context 上下文
  73. * @return {@code true}: 是<br>{@code false}: 否
  74. */
  75. public static boolean isLandscape(Context context) {
  76. return context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
  77. }
  78. /**
  79. * 判断是否竖屏
  80. *
  81. * @param context 上下文
  82. * @return {@code true}: 是<br>{@code false}: 否
  83. */
  84. public static boolean isPortrait(Context context) {
  85. return context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
  86. }
  87. /**
  88. * 获取屏幕旋转角度
  89. *
  90. * @param activity activity
  91. * @return 屏幕旋转角度
  92. */
  93. public static int getScreenRotation(Activity activity) {
  94. switch (activity.getWindowManager().getDefaultDisplay().getRotation()) {
  95. default:
  96. case Surface.ROTATION_0:
  97. return 0;
  98. case Surface.ROTATION_90:
  99. return 90;
  100. case Surface.ROTATION_180:
  101. return 180;
  102. case Surface.ROTATION_270:
  103. return 270;
  104. }
  105. }
  106. /**
  107. * 获取当前屏幕截图,包含状态栏
  108. *
  109. * @param activity activity
  110. * @return Bitmap
  111. */
  112. public static Bitmap captureWithStatusBar(Activity activity) {
  113. View view = activity.getWindow().getDecorView();
  114. view.setDrawingCacheEnabled(true);
  115. view.buildDrawingCache();
  116. Bitmap bmp = view.getDrawingCache();
  117. int width = getScreenWidth(activity);
  118. int height = getScreenHeight(activity);
  119. Bitmap ret = Bitmap.createBitmap(bmp, 0, 0, width, height);
  120. view.destroyDrawingCache();
  121. return ret;
  122. }
  123. /**
  124. * 获取当前屏幕截图,不包含状态栏
  125. * <p>需要用到上面获取状态栏高度getStatusBarHeight的方法</p>
  126. *
  127. * @param activity activity
  128. * @return Bitmap
  129. */
  130. public static Bitmap captureWithoutStatusBar(Activity activity) {
  131. View view = activity.getWindow().getDecorView();
  132. view.setDrawingCacheEnabled(true);
  133. view.buildDrawingCache();
  134. Bitmap bmp = view.getDrawingCache();
  135. int statusBarHeight = BarUtils.getStatusBarHeight(activity);
  136. int width = getScreenWidth(activity);
  137. int height = getScreenHeight(activity);
  138. Bitmap ret = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height - statusBarHeight);
  139. view.destroyDrawingCache();
  140. return ret;
  141. }
  142. /**
  143. * 判断是否锁屏
  144. *
  145. * @param context 上下文
  146. * @return {@code true}: 是<br>{@code false}: 否
  147. */
  148. public static boolean isScreenLock(Context context) {
  149. KeyguardManager km = (KeyguardManager) context
  150. .getSystemService(Context.KEYGUARD_SERVICE);
  151. return km.inKeyguardRestrictedInputMode();
  152. }
  153. }

SDCardUtils

  1. package com.blankj.utilcode.utils;
  2. import android.annotation.TargetApi;
  3. import android.os.Build;
  4. import android.os.Environment;
  5. import android.os.StatFs;
  6. import java.io.File;
  7. import static com.blankj.utilcode.utils.ConstUtils.*;
  8. /**
  9. * <pre>
  10. * author: Blankj
  11. * blog : http://blankj.com
  12. * time : 2016/8/11
  13. * desc : SD卡相关工具类
  14. * </pre>
  15. */
  16. public class SDCardUtils {
  17. private SDCardUtils() {
  18. throw new UnsupportedOperationException("u can't fuck me...");
  19. }
  20. /**
  21. * 判断SD卡是否可用
  22. *
  23. * @return true : 可用<br>false : 不可用
  24. */
  25. public static boolean isSDCardEnable() {
  26. return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
  27. }
  28. /**
  29. * 获取SD卡路径
  30. * <p>一般是/storage/emulated/0/</p>
  31. *
  32. * @return SD卡路径
  33. */
  34. public static String getSDCardPath() {
  35. if (!isSDCardEnable()) return "sdcard unable!";
  36. return Environment.getExternalStorageDirectory().getPath() + File.separator;
  37. }
  38. /**
  39. * 获取SD卡Data路径
  40. *
  41. * @return SD卡Data路径
  42. */
  43. public static String getDataPath() {
  44. if (!isSDCardEnable()) return "sdcard unable!";
  45. return Environment.getDataDirectory().getPath();
  46. }
  47. /**
  48. * 获取SD卡剩余空间
  49. *
  50. * @return SD卡剩余空间
  51. */
  52. @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
  53. public static String getFreeSpace() {
  54. if (!isSDCardEnable()) return "sdcard unable!";
  55. StatFs stat = new StatFs(getSDCardPath());
  56. long blockSize, availableBlocks;
  57. availableBlocks = stat.getAvailableBlocksLong();
  58. blockSize = stat.getBlockSizeLong();
  59. return ConvertUtils.byte2FitSize(availableBlocks * blockSize);
  60. }
  61. }

ServiceUtils

  1. package com.blankj.utilcode.utils;
  2. import android.app.ActivityManager;
  3. import android.app.ActivityManager.RunningServiceInfo;
  4. import android.content.ComponentName;
  5. import android.content.Context;
  6. import android.content.Intent;
  7. import android.content.pm.ResolveInfo;
  8. import android.os.Bundle;
  9. import java.util.List;
  10. /**
  11. * <pre>
  12. * author: Blankj
  13. * blog : http://blankj.com
  14. * time : 2016/8/2
  15. * desc : 服务工具类
  16. * </pre>
  17. */
  18. public class ServiceUtils {
  19. private ServiceUtils() {
  20. throw new UnsupportedOperationException("u can't fuck me...");
  21. }
  22. /**
  23. * 获取服务是否开启
  24. *
  25. * @param context 上下文
  26. * @param className 完整包名的服务类名
  27. * @return {@code true}: 是<br>{@code false}: 否
  28. */
  29. public static boolean isRunningService(Context context, String className) {
  30. // 进程的管理者,活动的管理者
  31. ActivityManager activityManager = (ActivityManager)
  32. context.getSystemService(Context.ACTIVITY_SERVICE);
  33. // 获取正在运行的服务,最多获取1000个
  34. List<RunningServiceInfo> runningServices = activityManager.getRunningServices(1000);
  35. // 遍历集合
  36. for (RunningServiceInfo runningServiceInfo : runningServices) {
  37. ComponentName service = runningServiceInfo.service;
  38. if (className.equals(service.getClassName())) {
  39. return true;
  40. }
  41. }
  42. return false;
  43. }
  44. }

ShellUtils

  1. package com.blankj.utilcode.utils;
  2. import java.io.BufferedReader;
  3. import java.io.DataOutputStream;
  4. import java.io.IOException;
  5. import java.io.InputStreamReader;
  6. import java.util.List;
  7. /**
  8. * <pre>
  9. * author: Blankj
  10. * blog : http://blankj.com
  11. * time : 2016/8/7
  12. * desc : Shell相关工具类
  13. * </pre>
  14. */
  15. public class ShellUtils {
  16. private ShellUtils() {
  17. throw new UnsupportedOperationException("u can't fuck me...");
  18. }
  19. public static final String COMMAND_SU = "su";
  20. public static final String COMMAND_SH = "sh";
  21. public static final String COMMAND_EXIT = "exit\n";
  22. public static final String COMMAND_LINE_END = "\n";
  23. /**
  24. * 判断设备是否root
  25. * @return {@code true}: root<br>{@code false}: 没root
  26. */
  27. public static boolean isRoot() {
  28. return execCmd("echo root", true, false).result == 0;
  29. }
  30. /**
  31. * 是否是在root下执行命令
  32. *
  33. * @param command 命令
  34. * @param isRoot 是否root
  35. * @return CommandResult
  36. */
  37. public static CommandResult execCmd(String command, boolean isRoot) {
  38. return execCmd(new String[]{command}, isRoot, true);
  39. }
  40. /**
  41. * 是否是在root下执行命令
  42. *
  43. * @param commands 多条命令链表
  44. * @param isRoot 是否root
  45. * @return CommandResult
  46. */
  47. public static CommandResult execCmd(List<String> commands, boolean isRoot) {
  48. return execCmd(commands == null ? null : commands.toArray(new String[]{}), isRoot, true);
  49. }
  50. /**
  51. * 是否是在root下执行命令
  52. *
  53. * @param commands 多条命令数组
  54. * @param isRoot 是否root
  55. * @return CommandResult
  56. */
  57. public static CommandResult execCmd(String[] commands, boolean isRoot) {
  58. return execCmd(commands, isRoot, true);
  59. }
  60. /**
  61. * 是否是在root下执行命令
  62. *
  63. * @param command 命令
  64. * @param isRoot 是否root
  65. * @param isNeedResultMsg 是否需要结果消息
  66. * @return CommandResult
  67. */
  68. public static CommandResult execCmd(String command, boolean isRoot, boolean isNeedResultMsg) {
  69. return execCmd(new String[]{command}, isRoot, isNeedResultMsg);
  70. }
  71. /**
  72. * 是否是在root下执行命令
  73. *
  74. * @param commands 命令链表
  75. * @param isRoot 是否root
  76. * @param isNeedResultMsg 是否需要结果消息
  77. * @return CommandResult
  78. */
  79. public static CommandResult execCmd(List<String> commands, boolean isRoot, boolean isNeedResultMsg) {
  80. return execCmd(commands == null ? null : commands.toArray(new String[]{}), isRoot, isNeedResultMsg);
  81. }
  82. /**
  83. * 是否是在root下执行命令
  84. *
  85. * @param commands 命令数组
  86. * @param isRoot 是否root
  87. * @param isNeedResultMsg 是否需要结果消息
  88. * @return CommandResult
  89. */
  90. public static CommandResult execCmd(String[] commands, boolean isRoot, boolean isNeedResultMsg) {
  91. int result = -1;
  92. if (commands == null || commands.length == 0) {
  93. return new CommandResult(result, null, null);
  94. }
  95. Process process = null;
  96. BufferedReader successResult = null;
  97. BufferedReader errorResult = null;
  98. StringBuilder successMsg = null;
  99. StringBuilder errorMsg = null;
  100. DataOutputStream os = null;
  101. try {
  102. process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);
  103. os = new DataOutputStream(process.getOutputStream());
  104. for (String command : commands) {
  105. if (command == null) {
  106. continue;
  107. }
  108. os.write(command.getBytes());
  109. os.writeBytes(COMMAND_LINE_END);
  110. os.flush();
  111. }
  112. os.writeBytes(COMMAND_EXIT);
  113. os.flush();
  114. result = process.waitFor();
  115. if (isNeedResultMsg) {
  116. successMsg = new StringBuilder();
  117. errorMsg = new StringBuilder();
  118. successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
  119. errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
  120. String s;
  121. while ((s = successResult.readLine()) != null) {
  122. successMsg.append(s);
  123. }
  124. while ((s = errorResult.readLine()) != null) {
  125. errorMsg.append(s);
  126. }
  127. }
  128. } catch (Exception e) {
  129. e.printStackTrace();
  130. } finally {
  131. try {
  132. if (os != null) {
  133. os.close();
  134. }
  135. if (successResult != null) {
  136. successResult.close();
  137. }
  138. if (errorResult != null) {
  139. errorResult.close();
  140. }
  141. } catch (IOException e) {
  142. e.printStackTrace();
  143. }
  144. if (process != null) {
  145. process.destroy();
  146. }
  147. }
  148. return new CommandResult(result, successMsg == null ? null : successMsg.toString(), errorMsg == null ? null
  149. : errorMsg.toString());
  150. }
  151. /**
  152. * 返回的命令结果
  153. */
  154. public static class CommandResult {
  155. /**
  156. * 结果码
  157. **/
  158. public int result;
  159. /**
  160. * 成功的信息
  161. **/
  162. public String successMsg;
  163. /**
  164. * 错误信息
  165. **/
  166. public String errorMsg;
  167. public CommandResult(int result) {
  168. this.result = result;
  169. }
  170. public CommandResult(int result, String successMsg, String errorMsg) {
  171. this.result = result;
  172. this.successMsg = successMsg;
  173. this.errorMsg = errorMsg;
  174. }
  175. }
  176. }

SizeUtils

  1. package com.blankj.utilcode.utils;
  2. import android.content.Context;
  3. import android.util.DisplayMetrics;
  4. import android.util.Log;
  5. import android.util.TypedValue;
  6. import android.view.View;
  7. /**
  8. * <pre>
  9. * author: Blankj
  10. * blog : http://blankj.com
  11. * time : 2016/8/2
  12. * desc : 尺寸相关工具类
  13. * </pre>
  14. */
  15. public class SizeUtils {
  16. private SizeUtils() {
  17. throw new UnsupportedOperationException("u can't fuck me...");
  18. }
  19. /**
  20. * dp转px
  21. *
  22. * @param context 上下文
  23. * @param dpValue dp值
  24. * @return px值
  25. */
  26. public static int dp2px(Context context, float dpValue) {
  27. final float scale = context.getResources().getDisplayMetrics().density;
  28. return (int) (dpValue * scale + 0.5f);
  29. }
  30. /**
  31. * px转dp
  32. *
  33. * @param context 上下文
  34. * @param pxValue px值
  35. * @return dp值
  36. */
  37. public static int px2dp(Context context, float pxValue) {
  38. final float scale = context.getResources().getDisplayMetrics().density;
  39. return (int) (pxValue / scale + 0.5f);
  40. }
  41. /**
  42. * sp转px
  43. *
  44. * @param context 上下文
  45. * @param spValue sp值
  46. * @return px值
  47. */
  48. public static int sp2px(Context context, float spValue) {
  49. final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
  50. return (int) (spValue * fontScale + 0.5f);
  51. }
  52. /**
  53. * px转sp
  54. *
  55. * @param context 上下文
  56. * @param pxValue px值
  57. * @return sp值
  58. */
  59. public static int px2sp(Context context, float pxValue) {
  60. final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
  61. return (int) (pxValue / fontScale + 0.5f);
  62. }
  63. /**
  64. * 各种单位转换
  65. * <p>该方法存在于TypedValue</p>
  66. *
  67. * @param unit 单位
  68. * @param value 值
  69. * @param metrics DisplayMetrics
  70. * @return 转换结果
  71. */
  72. public static float applyDimension(int unit, float value, DisplayMetrics metrics) {
  73. switch (unit) {
  74. case TypedValue.COMPLEX_UNIT_PX:
  75. return value;
  76. case TypedValue.COMPLEX_UNIT_DIP:
  77. return value * metrics.density;
  78. case TypedValue.COMPLEX_UNIT_SP:
  79. return value * metrics.scaledDensity;
  80. case TypedValue.COMPLEX_UNIT_PT:
  81. return value * metrics.xdpi * (1.0f / 72);
  82. case TypedValue.COMPLEX_UNIT_IN:
  83. return value * metrics.xdpi;
  84. case TypedValue.COMPLEX_UNIT_MM:
  85. return value * metrics.xdpi * (1.0f / 25.4f);
  86. }
  87. return 0;
  88. }
  89. /**
  90. * 在onCreate()即可强行获取View的尺寸
  91. * <p>需回调onGetSizeListener接口,在onGetSize中获取view宽高</p>
  92. * <p>用法示例如下所示</p>
  93. * <pre>{@code
  94. * SizeUtils.forceGetViewSize(view);
  95. * SizeUtils.setListener(new SizeUtils.onGetSizeListener() {
  96. * public void onGetSize(View view) {
  97. * Log.d("tag", view.getWidth() + " " + view.getHeight());
  98. * }
  99. * });}
  100. * </pre>
  101. *
  102. * @param view 视图
  103. */
  104. public static void forceGetViewSize(final View view) {
  105. view.post(new Runnable() {
  106. @Override
  107. public void run() {
  108. if (mListener != null) {
  109. mListener.onGetSize(view);
  110. }
  111. }
  112. });
  113. }
  114. /**
  115. * 获取到View尺寸的监听
  116. */
  117. public interface onGetSizeListener {
  118. void onGetSize(View view);
  119. }
  120. public static void setListener(onGetSizeListener listener) {
  121. mListener = listener;
  122. }
  123. private static onGetSizeListener mListener;
  124. /**
  125. * ListView中提前测量View尺寸,如headerView
  126. * <p>用的时候去掉注释拷贝到ListView中即可</p>
  127. * <p>参照以下注释代码</p>
  128. *
  129. * @param view 视图
  130. */
  131. public static void measureViewInLV(View view) {
  132. Log.i("tips", "U should copy the following code.");
  133. /*
  134. ViewGroup.LayoutParams p = view.getLayoutParams();
  135. if (p == null) {
  136. p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
  137. ViewGroup.LayoutParams.WRAP_CONTENT);
  138. }
  139. int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);
  140. int height;
  141. int tempHeight = p.height;
  142. if (tempHeight > 0) {
  143. height = MeasureSpec.makeMeasureSpec(tempHeight,
  144. MeasureSpec.EXACTLY);
  145. } else {
  146. height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
  147. }
  148. view.measure(width, height);
  149. */
  150. }
  151. }

SPUtils

  1. package com.blankj.utilcode.utils;
  2. import android.content.Context;
  3. import android.content.SharedPreferences;
  4. import java.util.Map;
  5. /**
  6. * <pre>
  7. * author: Blankj
  8. * blog : http://blankj.com
  9. * time : 2016/8/2
  10. * desc : SP相关工具类
  11. * </pre>
  12. */
  13. public class SPUtils {
  14. private SharedPreferences sp;
  15. private SharedPreferences.Editor editor;
  16. /**
  17. * SPUtils构造函数
  18. *
  19. * @param context 上下文
  20. * @param spName spName
  21. */
  22. public SPUtils(Context context, String spName) {
  23. sp = context.getSharedPreferences(spName, Context.MODE_PRIVATE);
  24. editor = sp.edit();
  25. editor.apply();
  26. }
  27. /**
  28. * SP中写入String类型value
  29. *
  30. * @param key 键
  31. * @param value 值
  32. */
  33. public void putString(String key, String value) {
  34. editor.putString(key, value).apply();
  35. }
  36. /**
  37. * SP中读取String
  38. *
  39. * @param key 键
  40. * @return 存在返回对应值,不存在返回默认值{@code null}
  41. */
  42. public String getString(String key) {
  43. return getString(key, null);
  44. }
  45. /**
  46. * SP中读取String
  47. *
  48. * @param key 键
  49. * @param defaultValue 默认值
  50. * @return 存在返回对应值,不存在返回默认值{@code defaultValue}
  51. */
  52. public String getString(String key, String defaultValue) {
  53. return sp.getString(key, defaultValue);
  54. }
  55. /**
  56. * SP中写入int类型value
  57. *
  58. * @param key 键
  59. * @param value 值
  60. */
  61. public void putInt(String key, int value) {
  62. editor.putInt(key, value).apply();
  63. }
  64. /**
  65. * SP中读取int
  66. *
  67. * @param key 键
  68. * @return 存在返回对应值,不存在返回默认值-1
  69. */
  70. public int getInt(String key) {
  71. return getInt(key, -1);
  72. }
  73. /**
  74. * SP中读取int
  75. *
  76. * @param key 键
  77. * @param defaultValue 默认值
  78. * @return 存在返回对应值,不存在返回默认值{@code defaultValue}
  79. */
  80. public int getInt(String key, int defaultValue) {
  81. return sp.getInt(key, defaultValue);
  82. }
  83. /**
  84. * SP中写入long类型value
  85. *
  86. * @param key 键
  87. * @param value 值
  88. */
  89. public void putLong(String key, long value) {
  90. editor.putLong(key, value).apply();
  91. }
  92. /**
  93. * SP中读取long
  94. *
  95. * @param key 键
  96. * @return 存在返回对应值,不存在返回默认值-1
  97. */
  98. public long getLong(String key) {
  99. return getLong(key, -1L);
  100. }
  101. /**
  102. * SP中读取long
  103. *
  104. * @param key 键
  105. * @param defaultValue 默认值
  106. * @return 存在返回对应值,不存在返回默认值{@code defaultValue}
  107. */
  108. public long getLong(String key, long defaultValue) {
  109. return sp.getLong(key, defaultValue);
  110. }
  111. /**
  112. * SP中写入float类型value
  113. *
  114. * @param key 键
  115. * @param value 值
  116. */
  117. public void putFloat(String key, float value) {
  118. editor.putFloat(key, value).apply();
  119. }
  120. /**
  121. * SP中读取float
  122. *
  123. * @param key 键
  124. * @return 存在返回对应值,不存在返回默认值-1
  125. */
  126. public float getFloat(String key) {
  127. return getFloat(key, -1f);
  128. }
  129. /**
  130. * SP中读取float
  131. *
  132. * @param key 键
  133. * @param defaultValue 默认值
  134. * @return 存在返回对应值,不存在返回默认值{@code defaultValue}
  135. */
  136. public float getFloat(String key, float defaultValue) {
  137. return sp.getFloat(key, defaultValue);
  138. }
  139. /**
  140. * SP中写入boolean类型value
  141. *
  142. * @param key 键
  143. * @param value 值
  144. */
  145. public void putBoolean(String key, boolean value) {
  146. editor.putBoolean(key, value).apply();
  147. }
  148. /**
  149. * SP中读取boolean
  150. *
  151. * @param key 键
  152. * @return 存在返回对应值,不存在返回默认值{@code false}
  153. */
  154. public boolean getBoolean(String key) {
  155. return getBoolean(key, false);
  156. }
  157. /**
  158. * SP中读取boolean
  159. *
  160. * @param key 键
  161. * @param defaultValue 默认值
  162. * @return 存在返回对应值,不存在返回默认值{@code defaultValue}
  163. */
  164. public boolean getBoolean(String key, boolean defaultValue) {
  165. return sp.getBoolean(key, defaultValue);
  166. }
  167. /**
  168. * SP中获取所有键值对
  169. *
  170. * @return Map对象
  171. */
  172. public Map<String, ?> getAll() {
  173. return sp.getAll();
  174. }
  175. /**
  176. * SP中移除该key
  177. *
  178. * @param key 键
  179. */
  180. public void remove(String key) {
  181. editor.remove(key).apply();
  182. }
  183. /**
  184. * SP中是否存在该key
  185. *
  186. * @param key 键
  187. * @return {@code true}: 存在<br>{@code false}: 不存在
  188. */
  189. public boolean contains(String key) {
  190. return sp.contains(key);
  191. }
  192. /**
  193. * SP中清除所有数据
  194. */
  195. public void clear() {
  196. editor.clear().apply();
  197. }
  198. }

StringUtils

  1. package com.blankj.utilcode.utils;
  2. import java.io.UnsupportedEncodingException;
  3. /**
  4. * <pre>
  5. * author: Blankj
  6. * blog : http://blankj.com
  7. * time : 2016/8/16
  8. * desc : 字符串相关工具类
  9. * </pre>
  10. */
  11. public class StringUtils {
  12. private StringUtils() {
  13. throw new UnsupportedOperationException("u can't fuck me...");
  14. }
  15. /**
  16. * 判断字符串是否为null或长度为0
  17. *
  18. * @param s 待校验字符串
  19. * @return {@code true}: 空<br> {@code false}: 不为空
  20. */
  21. public static boolean isEmpty(CharSequence s) {
  22. return s == null || s.length() == 0;
  23. }
  24. /**
  25. * 判断字符串是否为null或全为空格
  26. *
  27. * @param s 待校验字符串
  28. * @return {@code true}: null或全空格<br> {@code false}: 不为null且不全空格
  29. */
  30. public static boolean isSpace(String s) {
  31. return (s == null || s.trim().length() == 0);
  32. }
  33. /**
  34. * null转为长度为0的字符串
  35. *
  36. * @param s 待转字符串
  37. * @return s为null转为长度为0字符串,否则不改变
  38. */
  39. public static String null2Length0(String s) {
  40. return s == null ? "" : s;
  41. }
  42. /**
  43. * 返回字符串长度
  44. *
  45. * @param s 字符串
  46. * @return null返回0,其他返回自身长度
  47. */
  48. public static int length(CharSequence s) {
  49. return s == null ? 0 : s.length();
  50. }
  51. /**
  52. * 首字母大写
  53. *
  54. * @param s 待转字符串
  55. * @return 首字母大写字符串
  56. */
  57. public static String upperFirstLetter(String s) {
  58. if (isEmpty(s) || !Character.isLowerCase(s.charAt(0))) {
  59. return s;
  60. }
  61. return String.valueOf((char) (s.charAt(0) - 32)) + s.substring(1);
  62. }
  63. /**
  64. * 首字母小写
  65. *
  66. * @param s 待转字符串
  67. * @return 首字母小写字符串
  68. */
  69. public static String lowerFirstLetter(String s) {
  70. if (isEmpty(s) || !Character.isUpperCase(s.charAt(0))) {
  71. return s;
  72. }
  73. return String.valueOf((char) (s.charAt(0) + 32)) + s.substring(1);
  74. }
  75. /**
  76. * 反转字符串
  77. *
  78. * @param s 待反转字符串
  79. * @return 反转字符串
  80. */
  81. public static String reverse(String s) {
  82. int len = length(s);
  83. if (len <= 1) return s;
  84. int mid = len >> 1;
  85. char[] chars = s.toCharArray();
  86. char c;
  87. for (int i = 0; i < mid; ++i) {
  88. c = chars[i];
  89. chars[i] = chars[len - i - 1];
  90. chars[len - i - 1] = c;
  91. }
  92. return new String(chars);
  93. }
  94. /**
  95. * 转化为半角字符
  96. *
  97. * @param s 待转字符串
  98. * @return 半角字符串
  99. */
  100. public static String toDBC(String s) {
  101. if (isEmpty(s)) {
  102. return s;
  103. }
  104. char[] chars = s.toCharArray();
  105. for (int i = 0, len = chars.length; i < len; i++) {
  106. if (chars[i] == 12288) {
  107. chars[i] = ' ';
  108. } else if (65281 <= chars[i] && chars[i] <= 65374) {
  109. chars[i] = (char) (chars[i] - 65248);
  110. } else {
  111. chars[i] = chars[i];
  112. }
  113. }
  114. return new String(chars);
  115. }
  116. /**
  117. * 转化为全角字符
  118. *
  119. * @param s 待转字符串
  120. * @return 全角字符串
  121. */
  122. public static String toSBC(String s) {
  123. if (isEmpty(s)) {
  124. return s;
  125. }
  126. char[] chars = s.toCharArray();
  127. for (int i = 0, len = chars.length; i < len; i++) {
  128. if (chars[i] == ' ') {
  129. chars[i] = (char) 12288;
  130. } else if (33 <= chars[i] && chars[i] <= 126) {
  131. chars[i] = (char) (chars[i] + 65248);
  132. } else {
  133. chars[i] = chars[i];
  134. }
  135. }
  136. return new String(chars);
  137. }
  138. private static int[] pyValue = new int[]{-20319, -20317, -20304, -20295, -20292, -20283, -20265, -20257, -20242,
  139. -20230, -20051, -20036, -20032,
  140. -20026, -20002, -19990, -19986, -19982, -19976, -19805, -19784, -19775, -19774, -19763, -19756, -19751,
  141. -19746, -19741, -19739, -19728,
  142. -19725, -19715, -19540, -19531, -19525, -19515, -19500, -19484, -19479, -19467, -19289, -19288, -19281,
  143. -19275, -19270, -19263, -19261,
  144. -19249, -19243, -19242, -19238, -19235, -19227, -19224, -19218, -19212, -19038, -19023, -19018, -19006,
  145. -19003, -18996, -18977, -18961,
  146. -18952, -18783, -18774, -18773, -18763, -18756, -18741, -18735, -18731, -18722, -18710, -18697, -18696,
  147. -18526, -18518, -18501, -18490,
  148. -18478, -18463, -18448, -18447, -18446, -18239, -18237, -18231, -18220, -18211, -18201, -18184, -18183,
  149. -18181, -18012, -17997, -17988,
  150. -17970, -17964, -17961, -17950, -17947, -17931, -17928, -17922, -17759, -17752, -17733, -17730, -17721,
  151. -17703, -17701, -17697, -17692,
  152. -17683, -17676, -17496, -17487, -17482, -17468, -17454, -17433, -17427, -17417, -17202, -17185, -16983,
  153. -16970, -16942, -16915, -16733,
  154. -16708, -16706, -16689, -16664, -16657, -16647, -16474, -16470, -16465, -16459, -16452, -16448, -16433,
  155. -16429, -16427, -16423, -16419,
  156. -16412, -16407, -16403, -16401, -16393, -16220, -16216, -16212, -16205, -16202, -16187, -16180, -16171,
  157. -16169, -16158, -16155, -15959,
  158. -15958, -15944, -15933, -15920, -15915, -15903, -15889, -15878, -15707, -15701, -15681, -15667, -15661,
  159. -15659, -15652, -15640, -15631,
  160. -15625, -15454, -15448, -15436, -15435, -15419, -15416, -15408, -15394, -15385, -15377, -15375, -15369,
  161. -15363, -15362, -15183, -15180,
  162. -15165, -15158, -15153, -15150, -15149, -15144, -15143, -15141, -15140, -15139, -15128, -15121, -15119,
  163. -15117, -15110, -15109, -14941,
  164. -14937, -14933, -14930, -14929, -14928, -14926, -14922, -14921, -14914, -14908, -14902, -14894, -14889,
  165. -14882, -14873, -14871, -14857,
  166. -14678, -14674, -14670, -14668, -14663, -14654, -14645, -14630, -14594, -14429, -14407, -14399, -14384,
  167. -14379, -14368, -14355, -14353,
  168. -14345, -14170, -14159, -14151, -14149, -14145, -14140, -14137, -14135, -14125, -14123, -14122, -14112,
  169. -14109, -14099, -14097, -14094,
  170. -14092, -14090, -14087, -14083, -13917, -13914, -13910, -13907, -13906, -13905, -13896, -13894, -13878,
  171. -13870, -13859, -13847, -13831,
  172. -13658, -13611, -13601, -13406, -13404, -13400, -13398, -13395, -13391, -13387, -13383, -13367, -13359,
  173. -13356, -13343, -13340, -13329,
  174. -13326, -13318, -13147, -13138, -13120, -13107, -13096, -13095, -13091, -13076, -13068, -13063, -13060,
  175. -12888, -12875, -12871, -12860,
  176. -12858, -12852, -12849, -12838, -12831, -12829, -12812, -12802, -12607, -12597, -12594, -12585, -12556,
  177. -12359, -12346, -12320, -12300,
  178. -12120, -12099, -12089, -12074, -12067, -12058, -12039, -11867, -11861, -11847, -11831, -11798, -11781,
  179. -11604, -11589, -11536, -11358,
  180. -11340, -11339, -11324, -11303, -11097, -11077, -11067, -11055, -11052, -11045, -11041, -11038, -11024,
  181. -11020, -11019, -11018, -11014,
  182. -10838, -10832, -10815, -10800, -10790, -10780, -10764, -10587, -10544, -10533, -10519, -10331, -10329,
  183. -10328, -10322, -10315, -10309,
  184. -10307, -10296, -10281, -10274, -10270, -10262, -10260, -10256, -10254};
  185. private static String[] pyStr = new String[]{"a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao",
  186. "bei", "ben", "beng", "bi", "bian",
  187. "biao", "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "ceng", "cha", "chai",
  188. "chan", "chang", "chao", "che",
  189. "chen", "cheng", "chi", "chong", "chou", "chu", "chuai", "chuan", "chuang", "chui", "chun", "chuo", "ci",
  190. "cong", "cou", "cu", "cuan",
  191. "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "deng", "di", "dian", "diao", "die",
  192. "ding", "diu", "dong", "dou", "du",
  193. "duan", "dui", "dun", "duo", "e", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou",
  194. "fu", "ga", "gai", "gan", "gang",
  195. "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun",
  196. "guo", "ha", "hai", "han", "hang",
  197. "hao", "he", "hei", "hen", "heng", "hong", "hou", "hu", "hua", "huai", "huan", "huang", "hui", "hun",
  198. "huo", "ji", "jia", "jian",
  199. "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", "jue", "jun", "ka", "kai", "kan",
  200. "kang", "kao", "ke", "ken",
  201. "keng", "kong", "kou", "ku", "kua", "kuai", "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan",
  202. "lang", "lao", "le", "lei", "leng",
  203. "li", "lia", "lian", "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "lv", "luan",
  204. "lue", "lun", "luo", "ma", "mai",
  205. "man", "mang", "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu",
  206. "mo", "mou", "mu", "na", "nai",
  207. "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ni", "nian", "niang", "niao", "nie", "nin", "ning",
  208. "niu", "nong", "nu", "nv", "nuan",
  209. "nue", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", "pi", "pian", "piao",
  210. "pie", "pin", "ping", "po", "pu",
  211. "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", "qing", "qiong", "qiu", "qu", "quan", "que", "qun",
  212. "ran", "rang", "rao", "re",
  213. "ren", "reng", "ri", "rong", "rou", "ru", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao",
  214. "se", "sen", "seng", "sha",
  215. "shai", "shan", "shang", "shao", "she", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan",
  216. "shuang", "shui", "shun",
  217. "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te",
  218. "teng", "ti", "tian", "tiao",
  219. "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", "wang", "wei",
  220. "wen", "weng", "wo", "wu", "xi",
  221. "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", "xu", "xuan", "xue", "xun", "ya",
  222. "yan", "yang", "yao", "ye", "yi",
  223. "yin", "ying", "yo", "yong", "you", "yu", "yuan", "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze",
  224. "zei", "zen", "zeng", "zha",
  225. "zhai", "zhan", "zhang", "zhao", "zhe", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai",
  226. "zhuan", "zhuang", "zhui",
  227. "zhun", "zhuo", "zi", "zong", "zou", "zu", "zuan", "zui", "zun", "zuo"};
  228. /**
  229. * 单个汉字转成ASCII码
  230. *
  231. * @param s 单个汉字字符串
  232. * @return 如果字符串长度是1返回的是对应的ascii码,否则返回-1
  233. */
  234. private static int oneCn2ASCII(String s) {
  235. if (s.length() != 1) return -1;
  236. int ascii = 0;
  237. try {
  238. byte[] bytes = s.getBytes("GB2312");
  239. if (bytes.length == 1) {
  240. ascii = bytes[0];
  241. } else if (bytes.length == 2) {
  242. int highByte = 256 + bytes[0];
  243. int lowByte = 256 + bytes[1];
  244. ascii = (256 * highByte + lowByte) - 256 * 256;
  245. } else {
  246. throw new IllegalArgumentException("Illegal resource string");
  247. }
  248. } catch (UnsupportedEncodingException e) {
  249. e.printStackTrace();
  250. }
  251. return ascii;
  252. }
  253. /**
  254. * 单个汉字转成拼音
  255. *
  256. * @param s 单个汉字字符串
  257. * @return 如果字符串长度是1返回的是对应的拼音,否则返回{@code null}
  258. */
  259. private static String oneCn2PY(String s) {
  260. int ascii = oneCn2ASCII(s);
  261. if (ascii == -1) return null;
  262. String ret = null;
  263. if (0 <= ascii && ascii <= 127) {
  264. ret = String.valueOf((char) ascii);
  265. } else {
  266. for (int i = pyValue.length - 1; i >= 0; i--) {
  267. if (pyValue[i] <= ascii) {
  268. ret = pyStr[i];
  269. break;
  270. }
  271. }
  272. }
  273. return ret;
  274. }
  275. /**
  276. * 获得第一个汉字首字母
  277. *
  278. * @param s 单个汉字字符串
  279. * @return 拼音
  280. */
  281. public static String getPYFirstLetter(String s) {
  282. if (isSpace(s)) return "";
  283. String first, py;
  284. first = s.substring(0, 1);
  285. py = oneCn2PY(first);
  286. if (py == null) return null;
  287. return py.substring(0, 1);
  288. }
  289. /**
  290. * 中文转拼音
  291. *
  292. * @param s 汉字字符串
  293. * @return 拼音
  294. */
  295. public static String cn2PY(String s) {
  296. String hz, py;
  297. StringBuilder sb = new StringBuilder();
  298. for (int i = 0; i < s.length(); i++) {
  299. hz = s.substring(i, i + 1);
  300. py = oneCn2PY(hz);
  301. if (py == null) {
  302. py = "?";
  303. }
  304. sb.append(py);
  305. }
  306. return sb.toString();
  307. }
  308. }

ThreadPoolUtils

  1. package com.blankj.utilcode.utils;
  2. import java.util.Collection;
  3. import java.util.List;
  4. import java.util.concurrent.Callable;
  5. import java.util.concurrent.ExecutionException;
  6. import java.util.concurrent.ExecutorService;
  7. import java.util.concurrent.Executors;
  8. import java.util.concurrent.Future;
  9. import java.util.concurrent.ScheduledExecutorService;
  10. import java.util.concurrent.ScheduledFuture;
  11. import java.util.concurrent.TimeUnit;
  12. import java.util.concurrent.TimeoutException;
  13. /**
  14. * <pre>
  15. * author: Blankj
  16. * blog : http://blankj.com
  17. * time : 2016/8/25
  18. * desc : 线程池相关工具类
  19. * </pre>
  20. */
  21. public class ThreadPoolUtils {
  22. public enum Type {
  23. FixedThread,
  24. CachedThread,
  25. SingleThread,
  26. }
  27. private ExecutorService exec;
  28. private ScheduledExecutorService scheduleExec;
  29. /**
  30. * ThreadPoolUtils构造函数
  31. *
  32. * @param type 线程池类型
  33. * @param corePoolSize 只对Fixed和Scheduled线程池起效
  34. */
  35. public ThreadPoolUtils(Type type, int corePoolSize) {
  36. // 构造有定时功能的线程池
  37. // ThreadPoolExecutor(corePoolSize, Integer.MAX_VALUE, 10L, TimeUnit.MILLISECONDS, new BlockingQueue<Runnable>)
  38. scheduleExec = Executors.newScheduledThreadPool(corePoolSize);
  39. switch (type) {
  40. case FixedThread:
  41. // 构造一个固定线程数目的线程池
  42. // ThreadPoolExecutor(corePoolSize, corePoolSize, 0L, TimeUnit.MILLISECONDS, new
  43. // LinkedBlockingQueue<Runnable>());
  44. exec = Executors.newFixedThreadPool(corePoolSize);
  45. break;
  46. case SingleThread:
  47. // 构造一个只支持一个线程的线程池,相当于newFixedThreadPool(1)
  48. // ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())
  49. exec = Executors.newSingleThreadExecutor();
  50. break;
  51. case CachedThread:
  52. // 构造一个缓冲功能的线程池
  53. // ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
  54. exec = Executors.newCachedThreadPool();
  55. break;
  56. default:
  57. exec = scheduleExec;
  58. break;
  59. }
  60. }
  61. /**
  62. * 在未来某个时间执行给定的命令
  63. * <p>该命令可能在新的线程、已入池的线程或者正调用的线程中执行,这由 Executor 实现决定。</p>
  64. *
  65. * @param command 命令
  66. */
  67. public void execute(Runnable command) {
  68. exec.execute(command);
  69. }
  70. /**
  71. * 在未来某个时间执行给定的命令链表
  72. * <p>该命令可能在新的线程、已入池的线程或者正调用的线程中执行,这由 Executor 实现决定。</p>
  73. *
  74. * @param commands 命令链表
  75. */
  76. public void execute(List<Runnable> commands) {
  77. for (Runnable command : commands) {
  78. exec.execute(command);
  79. }
  80. }
  81. /**
  82. * 待以前提交的任务执行完毕后关闭线程池
  83. * <p>启动一次顺序关闭,执行以前提交的任务,但不接受新任务。
  84. * 如果已经关闭,则调用没有作用。</p>
  85. */
  86. public void shutDown() {
  87. exec.shutdown();
  88. }
  89. /**
  90. * 试图停止所有正在执行的活动任务
  91. * <p>试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。</p>
  92. * <p>无法保证能够停止正在处理的活动执行任务,但是会尽力尝试。</p>
  93. *
  94. * @return 等待执行的任务的列表
  95. */
  96. public List<Runnable> shutDownNow() {
  97. return exec.shutdownNow();
  98. }
  99. /**
  100. * 判断线程池是否已关闭
  101. *
  102. * @return {@code true}: 是<br>{@code false}: 否
  103. */
  104. public boolean isShutDown() {
  105. return exec.isShutdown();
  106. }
  107. /**
  108. * 关闭线程池后判断所有任务是否都已完成
  109. * <p>注意,除非首先调用 shutdown 或 shutdownNow,否则 isTerminated 永不为 true。</p>
  110. *
  111. * @return {@code true}: 是<br>{@code false}: 否
  112. */
  113. public boolean isTerminated() {
  114. return exec.isTerminated();
  115. }
  116. /**
  117. * 请求关闭、发生超时或者当前线程中断
  118. * <p>无论哪一个首先发生之后,都将导致阻塞,直到所有任务完成执行。</p>
  119. *
  120. * @param timeout 最长等待时间
  121. * @param unit 时间单位
  122. * @return {@code true}: 请求成功<br>{@code false}: 请求超时
  123. * @throws InterruptedException 终端异常
  124. */
  125. public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
  126. return exec.awaitTermination(timeout, unit);
  127. }
  128. /**
  129. * 提交一个Callable任务用于执行
  130. * <p>如果想立即阻塞任务的等待,则可以使用{@code result = exec.submit(aCallable).get();}形式的构造。</p>
  131. *
  132. * @param task 任务
  133. * @param <T> 泛型
  134. * @return 表示任务等待完成的Future, 该Future的{@code get}方法在成功完成时将会返回该任务的结果。
  135. */
  136. public <T> Future<T> submit(Callable<T> task) {
  137. return exec.submit(task);
  138. }
  139. /**
  140. * 提交一个Runnable任务用于执行
  141. *
  142. * @param task 任务
  143. * @param result 返回的结果
  144. * @param <T> 泛型
  145. * @return 表示任务等待完成的Future, 该Future的{@code get}方法在成功完成时将会返回该任务的结果。
  146. */
  147. public <T> Future<T> submit(Runnable task, T result) {
  148. return exec.submit(task, result);
  149. }
  150. /**
  151. * 提交一个Runnable任务用于执行
  152. *
  153. * @param task 任务
  154. * @return 表示任务等待完成的Future, 该Future的{@code get}方法在成功完成时将会返回null结果。
  155. */
  156. public Future<?> submit(Runnable task) {
  157. return exec.submit(task);
  158. }
  159. /**
  160. * 执行给定的任务
  161. * <p>当所有任务完成时,返回保持任务状态和结果的Future列表。
  162. * 返回列表的所有元素的{@link Future#isDone}为{@code true}。
  163. * 注意,可以正常地或通过抛出异常来终止已完成任务。
  164. * 如果正在进行此操作时修改了给定的 collection,则此方法的结果是不确定的。</p>
  165. *
  166. * @param tasks 任务集合
  167. * @param <T> 泛型
  168. * @return 表示任务的 Future 列表,列表顺序与给定任务列表的迭代器所生成的顺序相同,每个任务都已完成。
  169. * @throws InterruptedException 如果等待时发生中断,在这种情况下取消尚未完成的任务。
  170. */
  171. public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
  172. return exec.invokeAll(tasks);
  173. }
  174. /**
  175. * 执行给定的任务
  176. * <p>当所有任务完成或超时期满时(无论哪个首先发生),返回保持任务状态和结果的Future列表。
  177. * 返回列表的所有元素的{@link Future#isDone}为{@code true}。
  178. * 一旦返回后,即取消尚未完成的任务。
  179. * 注意,可以正常地或通过抛出异常来终止已完成任务。
  180. * 如果此操作正在进行时修改了给定的 collection,则此方法的结果是不确定的。</p>
  181. *
  182. * @param tasks 任务集合
  183. * @param timeout 最长等待时间
  184. * @param unit 时间单位
  185. * @param <T> 泛型
  186. * @return 表示任务的 Future 列表,列表顺序与给定任务列表的迭代器所生成的顺序相同。如果操作未超时,则已完成所有任务。如果确实超时了,则某些任务尚未完成。
  187. * @throws InterruptedException 如果等待时发生中断,在这种情况下取消尚未完成的任务
  188. */
  189. public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws
  190. InterruptedException {
  191. return exec.invokeAll(tasks, timeout, unit);
  192. }
  193. /**
  194. * 执行给定的任务
  195. * <p>如果某个任务已成功完成(也就是未抛出异常),则返回其结果。
  196. * 一旦正常或异常返回后,则取消尚未完成的任务。
  197. * 如果此操作正在进行时修改了给定的collection,则此方法的结果是不确定的。</p>
  198. *
  199. * @param tasks 任务集合
  200. * @param <T> 泛型
  201. * @return 某个任务返回的结果
  202. * @throws InterruptedException 如果等待时发生中断
  203. * @throws ExecutionException 如果没有任务成功完成
  204. */
  205. public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
  206. return exec.invokeAny(tasks);
  207. }
  208. /**
  209. * 执行给定的任务
  210. * <p>如果在给定的超时期满前某个任务已成功完成(也就是未抛出异常),则返回其结果。
  211. * 一旦正常或异常返回后,则取消尚未完成的任务。
  212. * 如果此操作正在进行时修改了给定的collection,则此方法的结果是不确定的。</p>
  213. *
  214. * @param tasks 任务集合
  215. * @param timeout 最长等待时间
  216. * @param unit 时间单位
  217. * @param <T> 泛型
  218. * @return 某个任务返回的结果
  219. * @throws InterruptedException 如果等待时发生中断
  220. * @throws ExecutionException 如果没有任务成功完成
  221. * @throws TimeoutException 如果在所有任务成功完成之前给定的超时期满
  222. */
  223. public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws
  224. InterruptedException, ExecutionException, TimeoutException {
  225. return exec.invokeAny(tasks, timeout, unit);
  226. }
  227. /**
  228. * 延迟执行Runnable命令
  229. *
  230. * @param command 命令
  231. * @param delay 延迟时间
  232. * @param unit 单位
  233. * @return 表示挂起任务完成的ScheduledFuture,并且其{@code get()}方法在完成后将返回{@code null}
  234. */
  235. public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
  236. return scheduleExec.schedule(command, delay, unit);
  237. }
  238. /**
  239. * 延迟执行Callable命令
  240. *
  241. * @param callable 命令
  242. * @param delay 延迟时间
  243. * @param unit 时间单位
  244. * @param <V> 泛型
  245. * @return 可用于提取结果或取消的ScheduledFuture
  246. */
  247. public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
  248. return scheduleExec.schedule(callable, delay, unit);
  249. }
  250. /**
  251. * 延迟并循环执行命令
  252. *
  253. * @param command 命令
  254. * @param initialDelay 首次执行的延迟时间
  255. * @param period 连续执行之间的周期
  256. * @param unit 时间单位
  257. * @return 表示挂起任务完成的ScheduledFuture,并且其{@code get()}方法在取消后将抛出异常
  258. */
  259. public ScheduledFuture<?> scheduleWithFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
  260. return scheduleExec.scheduleAtFixedRate(command, initialDelay, period, unit);
  261. }
  262. /**
  263. * 延迟并以固定休息时间循环执行命令
  264. *
  265. * @param command 命令
  266. * @param initialDelay 首次执行的延迟时间
  267. * @param delay 每一次执行终止和下一次执行开始之间的延迟
  268. * @param unit 时间单位
  269. * @return 表示挂起任务完成的ScheduledFuture,并且其{@code get()}方法在取消后将抛出异常
  270. */
  271. public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
  272. return scheduleExec.scheduleWithFixedDelay(command, initialDelay, delay, unit);
  273. }
  274. }

TimeUtils

  1. package com.blankj.utilcode.utils;
  2. import java.text.ParseException;
  3. import java.text.SimpleDateFormat;
  4. import java.util.Date;
  5. import java.util.Locale;
  6. import static com.blankj.utilcode.utils.ConstUtils.*;
  7. /**
  8. * <pre>
  9. * author: Blankj
  10. * blog : http://blankj.com
  11. * time : 2016/8/2
  12. * desc : 时间相关工具类
  13. * </pre>
  14. */
  15. public class TimeUtils {
  16. private TimeUtils() {
  17. throw new UnsupportedOperationException("u can't fuck me...");
  18. }
  19. /**
  20. * <p>在工具类中经常使用到工具类的格式化描述,这个主要是一个日期的操作类,所以日志格式主要使用 SimpleDateFormat的定义格式.</p>
  21. * 格式的意义如下: 日期和时间模式 <br>
  22. * <p>日期和时间格式由日期和时间模式字符串指定。在日期和时间模式字符串中,未加引号的字母 'A' 到 'Z' 和 'a' 到 'z'
  23. * 被解释为模式字母,用来表示日期或时间字符串元素。文本可以使用单引号 (') 引起来,以免进行解释。"''"
  24. * 表示单引号。所有其他字符均不解释;只是在格式化时将它们简单复制到输出字符串,或者在分析时与输入字符串进行匹配。
  25. * </p>
  26. * 定义了以下模式字母(所有其他字符 'A' 到 'Z' 和 'a' 到 'z' 都被保留): <br>
  27. * <table border="1" cellspacing="1" cellpadding="1" summary="Chart shows pattern letters, date/time component,
  28. * presentation, and examples.">
  29. * <tr>
  30. * <th align="left">字母</th>
  31. * <th align="left">日期或时间元素</th>
  32. * <th align="left">表示</th>
  33. * <th align="left">示例</th>
  34. * </tr>
  35. * <tr>
  36. * <td><code>G</code></td>
  37. * <td>Era 标志符</td>
  38. * <td>Text</td>
  39. * <td><code>AD</code></td>
  40. * </tr>
  41. * <tr>
  42. * <td><code>y</code> </td>
  43. * <td>年 </td>
  44. * <td>Year </td>
  45. * <td><code>1996</code>; <code>96</code> </td>
  46. * </tr>
  47. * <tr>
  48. * <td><code>M</code> </td>
  49. * <td>年中的月份 </td>
  50. * <td>Month </td>
  51. * <td><code>July</code>; <code>Jul</code>; <code>07</code> </td>
  52. * </tr>
  53. * <tr>
  54. * <td><code>w</code> </td>
  55. * <td>年中的周数 </td>
  56. * <td>Number </td>
  57. * <td><code>27</code> </td>
  58. * </tr>
  59. * <tr>
  60. * <td><code>W</code> </td>
  61. * <td>月份中的周数 </td>
  62. * <td>Number </td>
  63. * <td><code>2</code> </td>
  64. * </tr>
  65. * <tr>
  66. * <td><code>D</code> </td>
  67. * <td>年中的天数 </td>
  68. * <td>Number </td>
  69. * <td><code>189</code> </td>
  70. * </tr>
  71. * <tr>
  72. * <td><code>d</code> </td>
  73. * <td>月份中的天数 </td>
  74. * <td>Number </td>
  75. * <td><code>10</code> </td>
  76. * </tr>
  77. * <tr>
  78. * <td><code>F</code> </td>
  79. * <td>月份中的星期 </td>
  80. * <td>Number </td>
  81. * <td><code>2</code> </td>
  82. * </tr>
  83. * <tr>
  84. * <td><code>E</code> </td>
  85. * <td>星期中的天数 </td>
  86. * <td>Text </td>
  87. * <td><code>Tuesday</code>; <code>Tue</code> </td>
  88. * </tr>
  89. * <tr>
  90. * <td><code>a</code> </td>
  91. * <td>Am/pm 标记 </td>
  92. * <td>Text </td>
  93. * <td><code>PM</code> </td>
  94. * </tr>
  95. * <tr>
  96. * <td><code>H</code> </td>
  97. * <td>一天中的小时数(0-23) </td>
  98. * <td>Number </td>
  99. * <td><code>0</code> </td>
  100. * </tr>
  101. * <tr>
  102. * <td><code>k</code> </td>
  103. * <td>一天中的小时数(1-24) </td>
  104. * <td>Number </td>
  105. * <td><code>24</code> </td>
  106. * </tr>
  107. * <tr>
  108. * <td><code>K</code> </td>
  109. * <td>am/pm 中的小时数(0-11) </td>
  110. * <td>Number </td>
  111. * <td><code>0</code> </td>
  112. * </tr>
  113. * <tr>
  114. * <td><code>h</code> </td>
  115. * <td>am/pm 中的小时数(1-12) </td>
  116. * <td>Number </td>
  117. * <td><code>12</code> </td>
  118. * </tr>
  119. * <tr>
  120. * <td><code>m</code> </td>
  121. * <td>小时中的分钟数 </td>
  122. * <td>Number </td>
  123. * <td><code>30</code> </td>
  124. * </tr>
  125. * <tr>
  126. * <td><code>s</code> </td>
  127. * <td>分钟中的秒数 </td>
  128. * <td>Number </td>
  129. * <td><code>55</code> </td>
  130. * </tr>
  131. * <tr>
  132. * <td><code>S</code> </td>
  133. * <td>毫秒数 </td>
  134. * <td>Number </td>
  135. * <td><code>978</code> </td>
  136. * </tr>
  137. * <tr>
  138. * <td><code>z</code> </td>
  139. * <td>时区 </td>
  140. * <td>General time zone </td>
  141. * <td><code>Pacific Standard Time</code>; <code>PST</code>; <code>GMT-08:00</code> </td>
  142. * </tr>
  143. * <tr>
  144. * <td><code>Z</code> </td>
  145. * <td>时区 </td>
  146. * <td>RFC 822 time zone </td>
  147. * <td><code>-0800</code> </td>
  148. * </tr>
  149. * </table>
  150. * <pre>
  151. * HH:mm 15:44
  152. * h:mm a 3:44 下午
  153. * HH:mm z 15:44 CST
  154. * HH:mm Z 15:44 +0800
  155. * HH:mm zzzz 15:44 中国标准时间
  156. * HH:mm:ss 15:44:40
  157. * yyyy-MM-dd 2016-08-12
  158. * yyyy-MM-dd HH:mm 2016-08-12 15:44
  159. * yyyy-MM-dd HH:mm:ss 2016-08-12 15:44:40
  160. * yyyy-MM-dd HH:mm:ss zzzz 2016-08-12 15:44:40 中国标准时间
  161. * EEEE yyyy-MM-dd HH:mm:ss zzzz 星期五 2016-08-12 15:44:40 中国标准时间
  162. * yyyy-MM-dd HH:mm:ss.SSSZ 2016-08-12 15:44:40.461+0800
  163. * yyyy-MM-dd'T'HH:mm:ss.SSSZ 2016-08-12T15:44:40.461+0800
  164. * yyyy.MM.dd G 'at' HH:mm:ss z 2016.08.12 公元 at 15:44:40 CST
  165. * K:mm a 3:44 下午
  166. * EEE, MMM d, ''yy 星期五, 八月 12, '16
  167. * hh 'o''clock' a, zzzz 03 o'clock 下午, 中国标准时间
  168. * yyyyy.MMMMM.dd GGG hh:mm aaa 02016.八月.12 公元 03:44 下午
  169. * EEE, d MMM yyyy HH:mm:ss Z 星期五, 12 八月 2016 15:44:40 +0800
  170. * yyMMddHHmmssZ 160812154440+0800
  171. * yyyy-MM-dd'T'HH:mm:ss.SSSZ 2016-08-12T15:44:40.461+0800
  172. * EEEE 'DATE('yyyy-MM-dd')' 'TIME('HH:mm:ss')' zzzz 星期五 DATE(2016-08-12) TIME(15:44:40) 中国标准时间
  173. * </pre>
  174. */
  175. public static final SimpleDateFormat DEFAULT_SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
  176. /**
  177. * 将时间戳转为时间字符串
  178. * <p>格式为yyyy-MM-dd HH:mm:ss</p>
  179. *
  180. * @param milliseconds 毫秒时间戳
  181. * @return 时间字符串
  182. */
  183. public static String milliseconds2String(long milliseconds) {
  184. return milliseconds2String(milliseconds, DEFAULT_SDF);
  185. }
  186. /**
  187. * 将时间戳转为时间字符串
  188. * <p>格式为用户自定义</p>
  189. *
  190. * @param milliseconds 毫秒时间戳
  191. * @param format 时间格式
  192. * @return 时间字符串
  193. */
  194. public static String milliseconds2String(long milliseconds, SimpleDateFormat format) {
  195. return format.format(new Date(milliseconds));
  196. }
  197. /**
  198. * 将时间字符串转为时间戳
  199. * <p>格式为yyyy-MM-dd HH:mm:ss</p>
  200. *
  201. * @param time 时间字符串
  202. * @return 毫秒时间戳
  203. */
  204. public static long string2Milliseconds(String time) {
  205. return string2Milliseconds(time, DEFAULT_SDF);
  206. }
  207. /**
  208. * 将时间字符串转为时间戳
  209. * <p>格式为用户自定义</p>
  210. *
  211. * @param time 时间字符串
  212. * @param format 时间格式
  213. * @return 毫秒时间戳
  214. */
  215. public static long string2Milliseconds(String time, SimpleDateFormat format) {
  216. try {
  217. return format.parse(time).getTime();
  218. } catch (ParseException e) {
  219. e.printStackTrace();
  220. }
  221. return -1;
  222. }
  223. /**
  224. * 将时间字符串转为Date类型
  225. * <p>格式为yyyy-MM-dd HH:mm:ss</p>
  226. *
  227. * @param time 时间字符串
  228. * @return Date类型
  229. */
  230. public static Date string2Date(String time) {
  231. return string2Date(time, DEFAULT_SDF);
  232. }
  233. /**
  234. * 将时间字符串转为Date类型
  235. * <p>格式为用户自定义</p>
  236. *
  237. * @param time 时间字符串
  238. * @param format 时间格式
  239. * @return Date类型
  240. */
  241. public static Date string2Date(String time, SimpleDateFormat format) {
  242. return new Date(string2Milliseconds(time, format));
  243. }
  244. /**
  245. * 将Date类型转为时间字符串
  246. * <p>格式为yyyy-MM-dd HH:mm:ss</p>
  247. *
  248. * @param time Date类型时间
  249. * @return 时间字符串
  250. */
  251. public static String date2String(Date time) {
  252. return date2String(time, DEFAULT_SDF);
  253. }
  254. /**
  255. * 将Date类型转为时间字符串
  256. * <p>格式为用户自定义</p>
  257. *
  258. * @param time Date类型时间
  259. * @param format 时间格式
  260. * @return 时间字符串
  261. */
  262. public static String date2String(Date time, SimpleDateFormat format) {
  263. return format.format(time);
  264. }
  265. /**
  266. * 将Date类型转为时间戳
  267. *
  268. * @param time Date类型时间
  269. * @return 毫秒时间戳
  270. */
  271. public static long date2Milliseconds(Date time) {
  272. return time.getTime();
  273. }
  274. /**
  275. * 将时间戳转为Date类型
  276. *
  277. * @param milliseconds 毫秒时间戳
  278. * @return Date类型时间
  279. */
  280. public static Date milliseconds2Date(long milliseconds) {
  281. return new Date(milliseconds);
  282. }
  283. /**
  284. * 毫秒时间戳单位转换(单位:unit)
  285. *
  286. * @param milliseconds 毫秒时间戳
  287. * @param unit <ul>
  288. * <li>{@link TimeUnit#MSEC}: 毫秒</li>
  289. * <li>{@link TimeUnit#SEC }: 秒</li>
  290. * <li>{@link TimeUnit#MIN }: 分</li>
  291. * <li>{@link TimeUnit#HOUR}: 小时</li>
  292. * <li>{@link TimeUnit#DAY }: 天</li>
  293. * </ul>
  294. * @return unit时间戳
  295. */
  296. private static long milliseconds2Unit(long milliseconds, TimeUnit unit) {
  297. switch (unit) {
  298. case MSEC:
  299. return milliseconds / MSEC;
  300. case SEC:
  301. return milliseconds / SEC;
  302. case MIN:
  303. return milliseconds / MIN;
  304. case HOUR:
  305. return milliseconds / HOUR;
  306. case DAY:
  307. return milliseconds / DAY;
  308. }
  309. return -1;
  310. }
  311. /**
  312. * 获取两个时间差(单位:unit)
  313. * <p>time1和time2格式都为yyyy-MM-dd HH:mm:ss</p>
  314. *
  315. * @param time0 时间字符串1
  316. * @param time1 时间字符串2
  317. * @param unit <ul>
  318. * <li>{@link TimeUnit#MSEC}: 毫秒</li>
  319. * <li>{@link TimeUnit#SEC }: 秒</li>
  320. * <li>{@link TimeUnit#MIN }: 分</li>
  321. * <li>{@link TimeUnit#HOUR}: 小时</li>
  322. * <li>{@link TimeUnit#DAY }: 天</li>
  323. * </ul>
  324. * @return unit时间戳
  325. */
  326. public static long getIntervalTime(String time0, String time1, TimeUnit unit) {
  327. return getIntervalTime(time0, time1, unit, DEFAULT_SDF);
  328. }
  329. /**
  330. * 获取两个时间差(单位:unit)
  331. * <p>time1和time2格式都为format</p>
  332. *
  333. * @param time0 时间字符串1
  334. * @param time1 时间字符串2
  335. * @param unit <ul>
  336. * <li>{@link TimeUnit#MSEC}: 毫秒</li>
  337. * <li>{@link TimeUnit#SEC }: 秒</li>
  338. * <li>{@link TimeUnit#MIN }: 分</li>
  339. * <li>{@link TimeUnit#HOUR}: 小时</li>
  340. * <li>{@link TimeUnit#DAY }: 天</li>
  341. * </ul>
  342. * @param format 时间格式
  343. * @return unit时间戳
  344. */
  345. public static long getIntervalTime(String time0, String time1, TimeUnit unit, SimpleDateFormat format) {
  346. return Math.abs(milliseconds2Unit(string2Milliseconds(time0, format)
  347. - string2Milliseconds(time1, format), unit));
  348. }
  349. /**
  350. * 获取两个时间差(单位:unit)
  351. * <p>time1和time2都为Date类型</p>
  352. *
  353. * @param time0 Date类型时间1
  354. * @param time1 Date类型时间2
  355. * @param unit <ul>
  356. * <li>{@link TimeUnit#MSEC}: 毫秒</li>
  357. * <li>{@link TimeUnit#SEC }: 秒</li>
  358. * <li>{@link TimeUnit#MIN }: 分</li>
  359. * <li>{@link TimeUnit#HOUR}: 小时</li>
  360. * <li>{@link TimeUnit#DAY }: 天</li>
  361. * </ul>
  362. * @return unit时间戳
  363. */
  364. public static long getIntervalTime(Date time0, Date time1, TimeUnit unit) {
  365. return Math.abs(milliseconds2Unit(date2Milliseconds(time1)
  366. - date2Milliseconds(time0), unit));
  367. }
  368. /**
  369. * 获取当前时间
  370. *
  371. * @return 毫秒时间戳
  372. */
  373. public static long getCurTimeMills() {
  374. return System.currentTimeMillis();
  375. }
  376. /**
  377. * 获取当前时间
  378. * <p>格式为yyyy-MM-dd HH:mm:ss</p>
  379. *
  380. * @return 时间字符串
  381. */
  382. public static String getCurTimeString() {
  383. return date2String(new Date());
  384. }
  385. /**
  386. * 获取当前时间
  387. * <p>格式为用户自定义</p>
  388. *
  389. * @param format 时间格式
  390. * @return 时间字符串
  391. */
  392. public static String getCurTimeString(SimpleDateFormat format) {
  393. return date2String(new Date(), format);
  394. }
  395. /**
  396. * 获取当前时间
  397. * <p>Date类型</p>
  398. *
  399. * @return Date类型时间
  400. */
  401. public static Date getCurTimeDate() {
  402. return new Date();
  403. }
  404. /**
  405. * 获取与当前时间的差(单位:unit)
  406. * <p>time格式为yyyy-MM-dd HH:mm:ss</p>
  407. *
  408. * @param time 时间字符串
  409. * @param unit <ul>
  410. * <li>{@link TimeUnit#MSEC}:毫秒</li>
  411. * <li>{@link TimeUnit#SEC }:秒</li>
  412. * <li>{@link TimeUnit#MIN }:分</li>
  413. * <li>{@link TimeUnit#HOUR}:小时</li>
  414. * <li>{@link TimeUnit#DAY }:天</li>
  415. * </ul>
  416. * @return unit时间戳
  417. */
  418. public static long getIntervalByNow(String time, TimeUnit unit) {
  419. return getIntervalByNow(time, unit, DEFAULT_SDF);
  420. }
  421. /**
  422. * 获取与当前时间的差(单位:unit)
  423. * <p>time格式为format</p>
  424. *
  425. * @param time 时间字符串
  426. * @param unit <ul>
  427. * <li>{@link TimeUnit#MSEC}: 毫秒</li>
  428. * <li>{@link TimeUnit#SEC }: 秒</li>
  429. * <li>{@link TimeUnit#MIN }: 分</li>
  430. * <li>{@link TimeUnit#HOUR}: 小时</li>
  431. * <li>{@link TimeUnit#DAY }: 天</li>
  432. * </ul>
  433. * @param format 时间格式
  434. * @return unit时间戳
  435. */
  436. public static long getIntervalByNow(String time, TimeUnit unit, SimpleDateFormat format) {
  437. return getIntervalTime(getCurTimeString(), time, unit, format);
  438. }
  439. /**
  440. * 获取与当前时间的差(单位:unit)
  441. * <p>time为Date类型</p>
  442. *
  443. * @param time Date类型时间
  444. * @param unit <ul>
  445. * <li>{@link TimeUnit#MSEC}: 毫秒</li>
  446. * <li>{@link TimeUnit#SEC }: 秒</li>
  447. * <li>{@link TimeUnit#MIN }: 分</li>
  448. * <li>{@link TimeUnit#HOUR}: 小时</li>
  449. * <li>{@link TimeUnit#DAY }: 天</li>
  450. * </ul>
  451. * @return unit时间戳
  452. */
  453. public static long getIntervalByNow(Date time, TimeUnit unit) {
  454. return getIntervalTime(getCurTimeDate(), time, unit);
  455. }
  456. /**
  457. * 判断闰年
  458. *
  459. * @param year 年份
  460. * @return {@code true}: 闰年<br>{@code false}: 平年
  461. */
  462. public static boolean isLeapYear(int year) {
  463. return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
  464. }
  465. }

ZipUtils

  1. package com.blankj.utilcode.utils;
  2. import java.io.BufferedInputStream;
  3. import java.io.BufferedOutputStream;
  4. import java.io.File;
  5. import java.io.FileInputStream;
  6. import java.io.FileOutputStream;
  7. import java.io.IOException;
  8. import java.io.InputStream;
  9. import java.io.OutputStream;
  10. import java.util.ArrayList;
  11. import java.util.Collection;
  12. import java.util.Enumeration;
  13. import java.util.List;
  14. import java.util.zip.ZipEntry;
  15. import java.util.zip.ZipFile;
  16. import java.util.zip.ZipOutputStream;
  17. import static com.blankj.utilcode.utils.ConstUtils.KB;
  18. /**
  19. * <pre>
  20. * author: Blankj
  21. * blog : http://blankj.com
  22. * time : 2016/8/27
  23. * desc : 压缩相关工具类
  24. * </pre>
  25. */
  26. public class ZipUtils {
  27. private ZipUtils() {
  28. throw new UnsupportedOperationException("u can't fuck me...");
  29. }
  30. /**
  31. * 批量压缩文件
  32. *
  33. * @param resFiles 待压缩文件集合
  34. * @param zipFilePath 压缩文件路径
  35. * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败
  36. * @throws IOException IO错误时抛出
  37. */
  38. public static boolean zipFiles(Collection<File> resFiles, String zipFilePath)
  39. throws IOException {
  40. return zipFiles(resFiles, zipFilePath, null);
  41. }
  42. /**
  43. * 批量压缩文件
  44. *
  45. * @param resFiles 待压缩文件集合
  46. * @param zipFilePath 压缩文件路径
  47. * @param comment 压缩文件的注释
  48. * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败
  49. * @throws IOException IO错误时抛出
  50. */
  51. public static boolean zipFiles(Collection<File> resFiles, String zipFilePath, String comment)
  52. throws IOException {
  53. return zipFiles(resFiles, FileUtils.getFileByPath(zipFilePath), comment);
  54. }
  55. /**
  56. * 批量压缩文件
  57. *
  58. * @param resFiles 待压缩文件集合
  59. * @param zipFile 压缩文件
  60. * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败
  61. * @throws IOException IO错误时抛出
  62. */
  63. public static boolean zipFiles(Collection<File> resFiles, File zipFile)
  64. throws IOException {
  65. return zipFiles(resFiles, zipFile, null);
  66. }
  67. /**
  68. * 批量压缩文件
  69. *
  70. * @param resFiles 待压缩文件集合
  71. * @param zipFile 压缩文件
  72. * @param comment 压缩文件的注释
  73. * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败
  74. * @throws IOException IO错误时抛出
  75. */
  76. public static boolean zipFiles(Collection<File> resFiles, File zipFile, String comment)
  77. throws IOException {
  78. if (resFiles == null || zipFile == null) return false;
  79. ZipOutputStream zos = null;
  80. try {
  81. zos = new ZipOutputStream(new FileOutputStream(zipFile));
  82. for (File resFile : resFiles) {
  83. if (!zipFile(resFile, "", zos, comment)) return false;
  84. }
  85. return true;
  86. } finally {
  87. if (zos != null) {
  88. zos.finish();
  89. FileUtils.closeIO(zos);
  90. }
  91. }
  92. }
  93. /**
  94. * 压缩文件
  95. *
  96. * @param resFilePath 待压缩文件路径
  97. * @param zipFilePath 压缩文件路径
  98. * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败
  99. * @throws IOException IO错误时抛出
  100. */
  101. public static boolean zipFile(String resFilePath, String zipFilePath)
  102. throws IOException {
  103. return zipFile(resFilePath, zipFilePath, null);
  104. }
  105. /**
  106. * 压缩文件
  107. *
  108. * @param resFilePath 待压缩文件路径
  109. * @param zipFilePath 压缩文件路径
  110. * @param comment 压缩文件的注释
  111. * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败
  112. * @throws IOException IO错误时抛出
  113. */
  114. public static boolean zipFile(String resFilePath, String zipFilePath, String comment)
  115. throws IOException {
  116. return zipFile(FileUtils.getFileByPath(resFilePath), FileUtils.getFileByPath(zipFilePath), comment);
  117. }
  118. /**
  119. * 压缩文件
  120. *
  121. * @param resFile 待压缩文件
  122. * @param zipFile 压缩文件
  123. * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败
  124. * @throws IOException IO错误时抛出
  125. */
  126. public static boolean zipFile(File resFile, File zipFile)
  127. throws IOException {
  128. return zipFile(resFile, zipFile, null);
  129. }
  130. /**
  131. * 压缩文件
  132. *
  133. * @param resFile 待压缩文件
  134. * @param zipFile 压缩文件
  135. * @param comment 压缩文件的注释
  136. * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败
  137. * @throws IOException IO错误时抛出
  138. */
  139. public static boolean zipFile(File resFile, File zipFile, String comment)
  140. throws IOException {
  141. if (resFile == null || zipFile == null) return false;
  142. ZipOutputStream zos = null;
  143. try {
  144. zos = new ZipOutputStream(new FileOutputStream(zipFile));
  145. return zipFile(resFile, "", zos, comment);
  146. } finally {
  147. if (zos != null) {
  148. zos.finish();
  149. FileUtils.closeIO(zos);
  150. }
  151. }
  152. }
  153. /**
  154. * 压缩文件
  155. *
  156. * @param resFile 待压缩文件
  157. * @param rootPath 相对于压缩文件的路径
  158. * @param zos 压缩文件输出流
  159. * @param comment 压缩文件的注释
  160. * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败
  161. * @throws IOException IO错误时抛出
  162. */
  163. private static boolean zipFile(File resFile, String rootPath, ZipOutputStream zos, String comment)
  164. throws IOException {
  165. rootPath = rootPath + (StringUtils.isSpace(rootPath) ? "" : File.separator) + resFile.getName();
  166. if (resFile.isDirectory()) {
  167. File[] fileList = resFile.listFiles();
  168. // 如果是空文件夹那么创建它,我把'/'换为File.separator测试就不成功,eggPain
  169. if (fileList.length <= 0) {
  170. ZipEntry entry = new ZipEntry(rootPath + '/');
  171. if (!StringUtils.isEmpty(comment)) entry.setComment(comment);
  172. zos.putNextEntry(entry);
  173. zos.closeEntry();
  174. } else {
  175. for (File file : fileList) {
  176. // 如果递归返回false则返回false
  177. if (!zipFile(file, rootPath, zos, comment)) return false;
  178. }
  179. }
  180. } else {
  181. InputStream is = null;
  182. try {
  183. is = new BufferedInputStream(new FileInputStream(resFile));
  184. ZipEntry entry = new ZipEntry(rootPath);
  185. if (!StringUtils.isEmpty(comment)) entry.setComment(comment);
  186. zos.putNextEntry(entry);
  187. byte buffer[] = new byte[KB];
  188. int len;
  189. while ((len = is.read(buffer, 0, KB)) != -1) {
  190. zos.write(buffer, 0, len);
  191. }
  192. zos.closeEntry();
  193. } finally {
  194. FileUtils.closeIO(is);
  195. }
  196. }
  197. return true;
  198. }
  199. /**
  200. * 批量解压文件
  201. *
  202. * @param zipFiles 压缩文件集合
  203. * @param destDirPath 目标目录路径
  204. * @return {@code true}: 解压成功<br>{@code false}: 解压失败
  205. * @throws IOException IO错误时抛出
  206. */
  207. public static boolean unzipFiles(Collection<File> zipFiles, String destDirPath)
  208. throws IOException {
  209. return unzipFiles(zipFiles, FileUtils.getFileByPath(destDirPath));
  210. }
  211. /**
  212. * 批量解压文件
  213. *
  214. * @param zipFiles 压缩文件集合
  215. * @param destDir 目标目录
  216. * @return {@code true}: 解压成功<br>{@code false}: 解压失败
  217. * @throws IOException IO错误时抛出
  218. */
  219. public static boolean unzipFiles(Collection<File> zipFiles, File destDir)
  220. throws IOException {
  221. if (zipFiles == null || destDir == null) return false;
  222. for (File zipFile : zipFiles) {
  223. if (!unzipFile(zipFile, destDir)) return false;
  224. }
  225. return true;
  226. }
  227. /**
  228. * 解压文件
  229. *
  230. * @param zipFilePath 待解压文件路径
  231. * @param destDirPath 目标目录路径
  232. * @return {@code true}: 解压成功<br>{@code false}: 解压失败
  233. * @throws IOException IO错误时抛出
  234. */
  235. public static boolean unzipFile(String zipFilePath, String destDirPath)
  236. throws IOException {
  237. return unzipFile(FileUtils.getFileByPath(zipFilePath), FileUtils.getFileByPath(destDirPath));
  238. }
  239. /**
  240. * 解压文件
  241. *
  242. * @param zipFile 待解压文件
  243. * @param destDir 目标目录
  244. * @return {@code true}: 解压成功<br>{@code false}: 解压失败
  245. * @throws IOException IO错误时抛出
  246. */
  247. public static boolean unzipFile(File zipFile, File destDir)
  248. throws IOException {
  249. return unzipFileByKeyword(zipFile, destDir, null) != null;
  250. }
  251. /**
  252. * 解压带有关键字的文件
  253. *
  254. * @param zipFilePath 待解压文件路径
  255. * @param destDirPath 目标目录路径
  256. * @param keyword 关键字
  257. * @return 返回带有关键字的文件链表
  258. * @throws IOException IO错误时抛出
  259. */
  260. public static List<File> unzipFileByKeyword(String zipFilePath, String destDirPath, String keyword)
  261. throws IOException {
  262. return unzipFileByKeyword(FileUtils.getFileByPath(zipFilePath),
  263. FileUtils.getFileByPath(destDirPath), keyword);
  264. }
  265. /**
  266. * 解压带有关键字的文件
  267. *
  268. * @param zipFile 待解压文件
  269. * @param destDir 目标目录
  270. * @param keyword 关键字
  271. * @return 返回带有关键字的文件链表
  272. * @throws IOException IO错误时抛出
  273. */
  274. public static List<File> unzipFileByKeyword(File zipFile, File destDir, String keyword)
  275. throws IOException {
  276. if (zipFile == null || destDir == null) return null;
  277. List<File> files = new ArrayList<>();
  278. ZipFile zf = new ZipFile(zipFile);
  279. Enumeration<?> entries = zf.entries();
  280. while (entries.hasMoreElements()) {
  281. ZipEntry entry = ((ZipEntry) entries.nextElement());
  282. String entryName = entry.getName();
  283. if (StringUtils.isEmpty(keyword) || FileUtils.getFileName(entryName).toLowerCase().contains(keyword.toLowerCase())) {
  284. String filePath = destDir + File.separator + entryName;
  285. File file = new File(filePath);
  286. files.add(file);
  287. if (entry.isDirectory()) {
  288. if (!FileUtils.createOrExistsDir(file)) return null;
  289. } else {
  290. if (!FileUtils.createOrExistsFile(file)) return null;
  291. InputStream in = null;
  292. OutputStream out = null;
  293. try {
  294. in = new BufferedInputStream(zf.getInputStream(entry));
  295. out = new BufferedOutputStream(new FileOutputStream(file));
  296. byte buffer[] = new byte[KB];
  297. int len;
  298. while ((len = in.read(buffer)) != -1) {
  299. out.write(buffer, 0, len);
  300. }
  301. } finally {
  302. FileUtils.closeIO(in, out);
  303. }
  304. }
  305. }
  306. }
  307. return files;
  308. }
  309. /**
  310. * 获取压缩文件中的文件路径链表
  311. *
  312. * @param zipFilePath 压缩文件路径
  313. * @return 压缩文件中的文件路径链表
  314. * @throws IOException IO错误时抛出
  315. */
  316. public static List<String> getFilesPath(String zipFilePath)
  317. throws IOException {
  318. return getFilesPath(FileUtils.getFileByPath(zipFilePath));
  319. }
  320. /**
  321. * 获取压缩文件中的文件路径链表
  322. *
  323. * @param zipFile 压缩文件
  324. * @return 压缩文件中的文件路径链表
  325. * @throws IOException IO错误时抛出
  326. */
  327. public static List<String> getFilesPath(File zipFile)
  328. throws IOException {
  329. if (zipFile == null) return null;
  330. List<String> paths = new ArrayList<>();
  331. Enumeration<?> entries = getEntries(zipFile);
  332. while (entries.hasMoreElements()) {
  333. paths.add(((ZipEntry) entries.nextElement()).getName());
  334. }
  335. return paths;
  336. }
  337. /**
  338. * 获取压缩文件中的注释链表
  339. *
  340. * @param zipFilePath 压缩文件路径
  341. * @return 压缩文件中的注释链表
  342. * @throws IOException IO错误时抛出
  343. */
  344. public static List<String> getComments(String zipFilePath)
  345. throws IOException {
  346. return getComments(FileUtils.getFileByPath(zipFilePath));
  347. }
  348. /**
  349. * 获取压缩文件中的注释链表
  350. *
  351. * @param zipFile 压缩文件
  352. * @return 压缩文件中的注释链表
  353. * @throws IOException IO错误时抛出
  354. */
  355. public static List<String> getComments(File zipFile)
  356. throws IOException {
  357. if (zipFile == null) return null;
  358. List<String> comments = new ArrayList<>();
  359. Enumeration<?> entries = getEntries(zipFile);
  360. while (entries.hasMoreElements()) {
  361. ZipEntry entry = ((ZipEntry) entries.nextElement());
  362. comments.add(entry.getComment());
  363. }
  364. return comments;
  365. }
  366. /**
  367. * 获取压缩文件中的文件对象
  368. *
  369. * @param zipFilePath 压缩文件路径
  370. * @return 压缩文件中的文件对象
  371. * @throws IOException IO错误时抛出
  372. */
  373. public static Enumeration<?> getEntries(String zipFilePath)
  374. throws IOException {
  375. return getEntries(FileUtils.getFileByPath(zipFilePath));
  376. }
  377. /**
  378. * 获取压缩文件中的文件对象
  379. *
  380. * @param zipFile 压缩文件
  381. * @return 压缩文件中的文件对象
  382. * @throws IOException IO错误时抛出
  383. */
  384. public static Enumeration<?> getEntries(File zipFile)
  385. throws IOException {
  386. if (zipFile == null) return null;
  387. return new ZipFile(zipFile).entries();
  388. }
  389. }

Android Studio 相关


keymap

常用:    Ctrl+Shift+A    搜索菜单命令    Alt+F12     切换TerminalF1 帮助     Alt(Option)+F1 查找文件所在目录位置     Alt(Option)+1 快速打开或隐藏工程面板     Ctrl(Command)+Alt(Option)+ 打开设置对话框     Alt(Option)+Home 跳转到导航栏     Esc 光标返回编辑框     Shift+Esc 光标返回编辑框,关闭无用的窗口     Shift+Click 关闭标签页     F12 把焦点从编辑器移到最近使用的工具窗口     Ctrl(Command)+Alt(Option)+Y 同步     Ctrl(Command)+Alt(Option)+S 打开设置对话框     Alt(Option)+Shift+Inert 开启/关闭列选择模式     Ctrl(Command)+Alt(Option)+Shift+S 打开当前项目/模块属性     Alt(Option)+Shift+C 查看文件的变更历史     Ctrl(Command)+Shift+F10 运行     Ctrl(Command)+Shift+F9 debug运行     Ctrl(Command)+Alt(Option)+F12 资源管理器打开文件夹 编辑     Ctrl(Command)+C 复制当前行或选中的内容     Ctrl(Command)+D 粘贴当前行或选中的内容     Ctrl(Command)+X 剪切当前行或选中的内容     Ctrl(Command)+Y 删除行     Ctrl(Command)+Z 倒退     Ctrl(Command)+Shift+Z 向前     Alt(Option)+Enter 自动修正     Ctrl(Command)+Alt(Option)+L 格式化代码     Ctrl(Command)+Alt(Option)+I 将选中的代码进行自动缩进编排     Ctrl(Command)+Alt(Option)+O 优化导入的类和包     Alt(Option)+Insert 得到一些Intention Action,可以生成构造器、Getter、Setter、将 == 改为equals() 等 Ctrl(Command)+Shift+V 选最近使用的剪贴板内容并插入     Ctrl(Command)+Alt(Option)+Shift+V 简单粘贴     Ctrl(Command)+Shift+Insert 选最近使用的剪贴板内容并插入(同Ctrl(Command)+Shift+V)     Ctrl(Command)+Enter 在当前行的上面插入新行,并移动光标到新行(此功能光标在行首时有效)     Shift+Enter 在当前行的下面插入新行,并移动光标到新行     Ctrl(Command)+J 自动代码     Ctrl(Command)+Alt(Option)+T     把选中的代码放在 try{} 、if{} 、 else{} 里     Shift+Alt(Option)+Insert 竖编辑模式     Ctrl(Command)+ / 注释 //     Ctrl(Command)+Shift+ / 注释 /…/     Ctrl(Command)+Shift+J 合并成一行     F2/Shift+F2 跳转到下/上一个错误语句处     Ctrl(Command)+Shift+Back 跳转到上次编辑的地方     Ctrl(Command)+Alt(Option)+Space 类名自动完成     Shift+Alt(Option)+Up/Down 内容向上/下移动     Ctrl(Command)+Shift+Up/Down 语句向上/下移动     Ctrl(Command)+Shift+U 大小写切换     Tab 代码标签输入完成后,按 Tab,生成代码     Ctrl(Command)+Backspace 按单词删除     Ctrl(Command)+Shift+Enter 语句完成     Ctrl(Command)+Alt(Option)+J 用动态模板环绕 文件     Ctrl(Command)+F12 显示当前文件的结构     Ctrl(Command)+H 显示类继承结构图     Ctrl(Command)+Q 显示注释文档     Ctrl(Command)+P 方法参数提示     Ctrl(Command)+U 打开当前类的父类或者实现的接口     Alt(Option)+Left/Right 切换代码视图     Ctrl(Command)+Alt(Option)+Left/Right 返回上次编辑的位置     Alt(Option)+Up/Down 在方法间快速移动定位     Ctrl(Command)+B 快速打开光标处的类或方法     Ctrl(Command)+W 选中代码,连续按会有其他效果     Ctrl(Command)+Shift+W 取消选择光标所在词     Ctrl(Command)+ - / + 折叠/展开代码     Ctrl(Command)+Shift+ - / + 折叠/展开全部代码     Ctrl(Command)+Shift+. 折叠/展开当前花括号中的代码     Ctrl(Command)+ ] / [ 跳转到代码块结束/开始处     F2 或 Shift+F2 高亮错误或警告快速定位     Ctrl(Command)+Shift+C 复制路径     Ctrl(Command)+Alt(Option)+Shift+C 复制引用,必须选择类名     Alt(Option)+Up/Down 在方法间快速移动定位     Shift+F1 要打开编辑器光标字符处使用的类或者方法 Java 文档的浏览器     Ctrl(Command)+G 定位行 查找     Ctrl(Command)+F 在当前窗口查找文本     Ctrl(Command)+Shift+F 在指定环境下查找文本     F3 向下查找关键字出现位置     Shift+F3 向上一个关键字出现位置     Ctrl(Command)+R 在当前窗口替换文本     Ctrl(Command)+Shift+R 在指定窗口替换文本     Ctrl(Command)+N 查找类     Ctrl(Command)+Shift+N 查找文件     Ctrl(Command)+Shift+Alt(Option)+N 查找项目中的方法或变量     Ctrl(Command)+B 查找变量的来源     Ctrl(Command)+Alt(Option)+B 快速打开光标处的类或方法     Ctrl(Command)+Shift+B 跳转到类或方法实现处     Ctrl(Command)+E 最近打开的文件     Alt(Option)+F3 快速查找,效果和Ctrl(Command)+F相同     F4 跳转至定义变量的位置     Alt(Option)+F7 查询当前元素在工程中的引用     Ctrl(Command)+F7 查询当前元素在当前文件中的引用,然后按 F3 可以选择     Ctrl(Command)+Alt(Option)+F7 选中查询当前元素在工程中的引用     Ctrl(Command)+Shift+F7 高亮显示匹配的字符,按 Esc 高亮消失     Ctrl(Command)+Alt(Option)+F7 查找某个方法的所有调用地方     Ctrl(Command)+Shift+Alt(Option)+N 查找类中的方法或变量     Ctrl(Command)+Shift+O 弹出显示查找内容     Ctrl(Command)+Alt(Option)+Up/Down 快速跳转搜索结果     Ctrl(Command)+Shift+S 高级搜索、搜索结构 重构     F5 复制     F6 移动     Alt(Option)+Delete 安全删除     Ctrl(Command)+U 转到父类     Ctrl(Command)+O 重写父类的方法     Ctrl(Command)+I 实现方法     Ctrl(Command)+Alt(Option)+N 内联     Ctrl(Command)+Alt(Option)+Shift+T 弹出重构菜单     Shift+F6 重构-重命名     Ctrl(Command)+Alt(Option)+M 提取代码组成方法     Ctrl(Command)+Alt(Option)+C 将变量更改为常量     Ctrl(Command)+Alt(Option)+V 定义变量引用当前对象或者方法的返回值     Ctrl(Command)+Alt(Option)+F 将局部变量更改为类的成员变量     Ctrl(Command)+Alt(Option)+P 将变量更改为方法的参数 调试     F8 跳到下一步     Shift+F8 跳出函数、跳到下一个断点     Alt(Option)+Shift+F8 强制跳出函数     F7 进入代码     Shift+F7 智能进入代码     Alt(Option)+Shift+F7 强制进入代码     Alt(Option)+F9 运行至光标处     Ctrl(Command)+Alt(Option)+F9 强制运行至光标处     Ctrl(Command)+F2 停止运行     Alt(Option)+F8 计算变量值 VCS     Ctrl(Command)+K 提交更改     Ctrl(Command)+T 更新项目     Ctrl(Command)+Alt(Option)+Shift+D   显示变化 

gradle问题总结:

  • App第一次安装启动的时候很慢,不要升级gradle版本,虽然提示升级了之后可以使用强大的Install Run功能!

    1. dependencies {
    2. classpath 'com.android.tools.build:gradle:2.1.0+'
    3. }


Android系统架构图


Android相关


常用第三方jar、aar包
名称下载地址fastjsonhttp://7j1w9c.com1.z0.glb.clouddn.com/fastjson-1.2.9.jarxpp3-minhttp://7j1w9c.com1.z0.glb.clouddn.com/xpp3_min-1.1.4c.jarxstreamhttp://7j1w9c.com1.z0.glb.clouddn.com/xstream-1.4.6.jaruniversal-image-loaderhttp://7j1w9c.com1.z0.glb.clouddn.com/universal-image-loader-1.9.4.jarcorehttp://7j1w9c.com1.z0.glb.clouddn.com/core-3.0.0.jarcommons-httpclienthttp://7j1w9c.com1.z0.glb.clouddn.com/commons-httpclient-3.1.jarxUtils3http://7j1w9c.com1.z0.glb.clouddn.com/xutils-3.3.36.aar

|org.apache.http.legacy|http://7j1w9c.com1.z0.glb.clouddn.com/org.apache.http.legacy.jar|

aar包引入方式


java相关



VIM Keymap

sublime 支持 VIM 80% 左右的快捷键,以实际为准。

一. 移动:    h,j,k,l: 左,下,上,右。    w: 下一个词的词首。W:下一个单词(不含标点)。    e:下一个词的词尾。E:不含标点。    b:上一个词的词首。B:不含标点。    <>: v 模式选中后进行缩进。    >><<:向前向后缩进。 二. 跳转:    %: 可以匹配{},"",(),[]之间跳转。    H、M、L:直接跳转到当前屏幕的顶部、中部、底部。    #H:跳转到当前屏的第#行。    #L:跳转到当前屏的倒数第#行。    zt: 当前编辑行置为屏顶。    zz: 当前编辑行置为屏中。    zb: 当前编辑行置为屏底。    G:直接跳转到文件的底部。    gg: 跳转到文件首。    gd: 跳转到光标所在函数和变量的定义。    ():跳转到当前的行首、行尾。    {}:向上、向下跳转到最近的空行。    [{:跳转到目前区块开头。    ]}:跳转到目前区块结尾。    0: 跳转到行首。    $: 跳转到行尾。        2$: 跳转到下一行的行尾。    #:跳转到该行的第#个位置。    #G: 15G,跳转到15行。    :#:跳转到#行。    f'n':跳转到下一个"n"字母后。    ctrl+b: 向后翻一页。    ctrl+f:向前翻一页。    ctrl+u: 向后翻半页。    ctrl+d: 向前翻半页。    ctry+e: 下滚一行。三. 选择:    1.v: 开启可视模式。 V: 开启逐行可视模式。    2.^V: 矩形选择。    3.v3w: 选择三个字符。      4.ab:包括括号和()内的区域。    5.aB:包括括号和{}内的区域。    6.ib:括号()内的区域。    7.iB:括号{}内的区域。    8.aw:标记一个单词。四. 编辑:    1. 新增:        i: 光标前插入。        I: 在当前行首插入。        a: 光标后插入。        A: 当前行尾插入。        O: 在当前行之前插入新行。        o: 在当前行之后插入新行。    2. 修改 c(change) 为主:        r: 替换光标所在处的字符。        R:替换光标所到之处的字符。        cw: 更改光标所在处的字到字尾处。        c#w: c3w 修改3个字符。        C:修改到行尾。        ci':修改配对标点符号中的文本内容。        di':删除配对标点符号中的文本内容。        yi':复制配对标点符号中的文本内容。        vi':选中配对标点符号中的文本内容。        s:替换当前一个光标所处字符。        #S:删除 # 行,并以新文本代替。    3. 删除 d(delete) 为主:        D:删除到行尾。        X: 每按一次,删除光标所在位置的前面一个字符。        x: 每按一次,删除光标所在位置的后面一个字符。        #x: 删除光标所在位置后面6个字符。        d^: 删至行首。        d$: 删至行尾。        dd:(剪切)删除光标所在行。                dw: 删除一个单词/光标之后的单词剩余部分。        d4w: 删除4个word。        #dd: 从光标所在行开始删除#行。        daB: 删除{}及其内的内容。        diB: 删除{}中的内容。        n1,n2 d:将n1,n2行之间的内容删除。    4. 查找:        /: 输入关键字,发现不是要找的,直接在按n,向后查找直到找到为止。        ?: 输入关键字,发现不是要找的,直接在按n,向前查找直到找到为止。        *: 在当前页向后查找同一字。        #: 在当前页向前查找同一字。    5. 复制 y(yank)为主:        yw: 将光标所在之处到字尾的字符复制到缓冲区中。        #yw: 复制#个字到缓冲区。        Y:相当于yy, 复制整行。        #yy:表示复制从光标所在的该行往下数#行文字。        p: 粘贴。所有与y相关的操作必用p来结合粘贴。        ]p:粘贴到合适的缩进处。        n1,n2 co n3:复制第n1行到第n2行之间的内容到第n3行后面。    6. 大小写转换:        gUU: 将当前行的字母改为大写。        guu: 将当前行的字母改为小写。        gUw: 将当前光标下的单词改为大写。        guw: 将当前光标下的单词改为小写。        a. 整篇大写:        ggguG        gg: 光标到文件第一个字符。        gu: 把选择范围全部小写。        G: 到文件结束。        b. 整篇小写:gggUG    7.  其它:        J:当前行和下一行合并成一行。    8.  移动:        n1,n2 m n3:将n1行到n2行之间的内容移至n3行下。五.退出:     1. w filename: 保存正在编辑的文件filename     2. wq filename: 保存后退出正在编辑的文件filename     3. q:退出不保存。六.窗口操作:     1. ctrl+w p: 在两个分割窗口之间来回切换。     2. ctrl+w j: 跳到下面的分割窗     3. ctrl+w h: 跳到左边的分割窗。     4. ctrl+w k: 跳到上面的分割窗。     5. ctrl+w l: 跳到右边的分割窗。七.折叠:    zo 將游標所在處的折疊打開。open。    zc 將游標所在處已打開的內容再度折疊起來。close。    zr 將全文的所有折疊依層次通通打開。reduce。    zm 將全文已打開的折疊依層次通通再折疊起來。more。    zR 作用和 zr 同,但會打開含巢狀折疊(折疊中又還有折疊)的所有折疊。    zM 作用和 zm 同,但對於巢狀折疊亦有作用。    zi 這是個切換,是折疊與不折疊指令間的切換。    zn 打開全文的所有折疊。fold none。    zN 這是 zn 的相對指令,回復所有的折疊。







  • 0 0
    原创粉丝点击