第三次修改-2017.11.1>>> 这次修改了ActivityManager中的cleanActivity() 和cleanActivityWithOutThis() 两个方法,在循环删除的时候会出错,简单的说就是“集合没有反应过来已经有数据被移除,还是按照已有的执行顺序执行,导致越界啊等等毛病”。
- 第二次修改-2017.10.18>>>>确实有一些错误,对此进行了改正,在此谢谢<<无心下棋>>的提醒。错误在ActivityManager的严谨问题上和一些逻辑上,现已经修改,有问题再提,我接着修改。最后更新了一个需求“app国际化”,我也写了一个工具类LanguageUtils,还有一个baseActivity和MyAPP,因为项目还没完全启动起来,没有完全补充齐全,见谅!!(附带一个大家都知道的双击返回键退出的实现)
- 第一次修改- 2017.10.17>>>>这次更新了一个方法,很厉害,不是我写的,是我抄袭的,所以附带了出处,可以看看;方法在4.ScreenUtils中的controlKeyboardLayout方法,作用就是在你需要弹出软键盘的时候,部分控件跟着上移。用处之一就是登录界面,背景不变,登录按钮整体上移。(注意的一点是:整个控件组的大小尽力控制在“手机屏幕高度-软键盘高度”之间,要不然,还是会被顶上去)
- 最近需要做一个新项目,前期准备中想起需要一些工具类,就写了一下,都是简单但却很使用的工具类
- 注释很清楚,做一个认真的好人,不要让别人看你的代码时是一头雾水,将心比心,你会做的更好
- 不要想着去重复造轮子,自己写的过瘾了,但实际上你的能力并不会提升多少
- 有出错的可以直接留言,共同进步嘛!
1.ActivityManager
import android.app.Activity;
import android.content.Intent;
import java.util.ArrayList;
import java.util.List;
/**
* Activity 管理器<p>
* <li>addActivity 添加活动</li>
* <li>removeActivity 移除指定活动</li>
* <li>cleanActivity 移除所有的活动</li>
* <li>exitAPP 退出应用</li>
* <li>cleanActivityWithOutThis 清除集合中除指定外的所有活动</li>
* Author:蔡小树 <p>
* Date:2017/10/13<p>
* Time:10:03<p>
* No bug!No bug!No bug!<p>
*/
public class ActivityManager {
// 应用中出现的Activity的集合
private static List<Activity> activityList;
/**
* 添加Activity到集合中去
*
* @param activity 要添加的Activity
*/
public static void addActivity(Activity activity) {
if (activityList == null) {
activityList = new ArrayList<>();
}
if (activity != null) {
activityList.add(activity);
}
}
/**
* 删除集合中指定的Activity
*
* @param activitys 可变参数,要删除的Activity
*/
public static void removeActivity(Activity... activitys) {
for (Activity activity :
activitys) {
if (activityList.contains(activity)) {
activityList.remove(activity);
}
activity.finish();
}
}
/**
* 移除所有的活动
*/
public static void cleanActivity() {
//移除的时候,索引会发生改变
for (int i = 0; i < activityList.size(); i++) {
Activity activity = activityList.get(i);
activity.finish();
activityList.remove(activity);
i--;
}
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
/**
* 退出应用
*/
public static void exitAPP(Activity context) {
//清空sp
SPUtils.cleanAll(context);
//关闭移除除当前界面的所有活动
for (Activity activity :
activityList) {
if (!context.equals(activity)) {
activity.finish();
activityList.remove(activity);
}
}
//跳转到登录界面
Intent loginIntent = new Intent(context, LoginActivity.class);
context.startActivity(loginIntent);
ActivityManager.removeActivity(context);
}
/**
* 清除集合中除指定外的所有活动
*
* @param activity
*/
public static void cleanActivityWithOutThis(Activity activity) throws ConcurrentModificationException {
if (activityList != null) {
for (int i = 0; i < activityList.size(); i++) {
Activity a = activityList.get(i);
if (!a.equals(activity)) {
activityList.remove(a);
activity.finish();
}
i--;
}
}
}
}
2.EncoderUtils
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
/**
* 编码格式转换工具类<p>
* <li>String2UTF8 将字符串转换为UTF-8编码格式</li>
* <li>String2GBK 将字符串转换为GBK编码格式</li>
* Author:蔡小树 <p>
* Date:2017/10/16<p>
* Time:14:48<p>
* No bug!No bug!No bug!<p>
*/
public class EncoderUtils {
public static String String2UTF8(String string) {
String encode = "";
try {
encode = URLEncoder.encode(string, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return "UTF-8格式转换不支持";
}
if ("".equals(encode)) {
return "UTF-8转换失败";
}
return encode;
}
public static String String2GBK(String string) {
String encode = "";
try {
encode = URLEncoder.encode(string, "GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return "GBK格式转换不支持";
}
if ("".equals(encode)) {
return "GBK转换失败";
}
return encode;
}
}
3.LogUtils
import android.util.Log;
/**
* Log日志控制工具类<p>
* <li>d 打印debug日志</li>
* <li>i 打印info日志</li>
* <li>w 打印warn日志</li>
* <li>e 打印error日志</li>
* Author:蔡小树 <p>
* Date:2017/10/16<p>
* Time:11:15<p>
* No bug!No bug!No bug!<p>
*/
public class LogUtils {
//Log日志是否打印
private static boolean isSwitch = true;
/**
* 答应debug日志
*
* @param tag 标签
* @param msg 信息
*/
public static void d(String tag, String msg) {
if (isSwitch && msg != null) {
Log.d(tag, msg);
} else {
Log.d(tag, "null");
}
}
/**
* 打印info日志
*
* @param tag 标签
* @param msg 消息
*/
public static void i(String tag, String msg) {
if (isSwitch && msg != null) {
Log.i(tag, msg);
} else {
Log.i(tag, "null");
}
}
/**
* 打印warn日志
*
* @param tag 标签
* @param msg 消息
*/
public static void w(String tag, String msg) {
if (isSwitch && msg != null) {
Log.w(tag, msg);
} else {
Log.w(tag, "null");
}
}
/**
* 打印error日志
*
* @param tag 标签
* @param msg 消息
*/
public static void e(String tag, String msg) {
if (isSwitch && msg != null) {
Log.e(tag, msg);
} else {
Log.e(tag, "null");
}
}
}
4.ScreenUtils
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
/**
* 屏幕控制工具类<p>
* <li>getScreenWidth 获取屏幕宽度</li>
* <li>getScreenHeight 获取屏幕高度</li>
* <li>getStatusHeight 获取状态栏高度</li>
* <li>getTitleheight 获取标题栏高度</li>
* <li>snapShot 获取当前屏幕截图</li>
* <li>snapShotWithoutStatusBar 获取当前屏幕截图,不包含状态栏</li>
* <li>snapShotWithoutTitle 获取当前屏幕截图,不包含状态栏和标题栏</li>
* Author:蔡小树 <p>
* Date:2017/10/16<p>
* Time:14:53<p>
* No bug!No bug!No bug!<p>
*/
public class ScreenUtils {
/**
* 获取屏幕宽度
*
* @param context
* @return
*/
public static int getScreenWidth(Context context) {
//获取屏幕管理器
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(metrics);
return metrics.widthPixels;
}
/**
* 获取屏幕高度
*
* @param context
* @return
*/
public static int getScreenHeight(Context context) {
//获取屏幕管理器
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(metrics);
return metrics.heightPixels;
}
/**
* 获得状态栏的高度
*
* @param context
* @return
*/
public static int getStatusHeight(Context context) {
int statusHeight = -1;
try {
Class<?> clazz = Class.forName("com.android.internal.R$dimen");
Object object = clazz.newInstance();
int height = Integer.parseInt(clazz.getField("status_bar_height")
.get(object).toString());
statusHeight = context.getResources().getDimensionPixelSize(height);
} catch (Exception e) {
e.printStackTrace();
}
return statusHeight;
}
/**
* 获取标题栏的高度
*
* @param activity
* @return
*/
public static int getTitleheight(Activity activity) {
//应用区域
Rect outRect1 = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect1);
//View绘制区域
//获取顶端的像素值
int viewTop = activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();
return viewTop - outRect1.top;
}
/**
* 获取当前屏幕截图,包含状态栏
*
* @param activity
* @return
*/
public static Bitmap snapShot(Activity activity) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap bp = null;
bp = Bitmap.createBitmap(bmp, 0, 0, width, height);
view.destroyDrawingCache();
return bp;
}
/**
* 获取当前屏幕截图,不包含状态栏
*
* @param activity
* @return
*/
public static Bitmap snapShotWithoutStatusBar(Activity activity) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
Rect frame = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap bp = null;
bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height
- statusBarHeight);
view.destroyDrawingCache();
return bp;
}
/**
* 获取当前屏幕截图,不包含状态栏和标题栏
*
* @param activity
* @return
*/
public static Bitmap snapShotWithoutTitle(Activity activity) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
//绘制View的区域
Rect outRect2 = new Rect();
activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(outRect2);
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap bp = null;
bp = Bitmap.createBitmap(bmp, 0, height - outRect2.height()
, width, outRect2.height());
view.destroyDrawingCache();
return bp;
}
/**
* 软键盘弹出的时候,部分控件上移,背景等不发生变化
* 这是别人写的,支持原创 http://blog.csdn.net/harryweasley/article/details/50266749
*
* @param root 最外层布局,需要调整的布局,所有你要调整的布局包在同一个父布局中
* @param scrollToView 被键盘遮挡的scrollToView,滚动root,使scrollToView在root可视区域的底部(简单的说就是你要移动控件的最下面一个控件)
*/
private void controlKeyboardLayout(final View root, final View scrollToView) {
// 注册一个回调函数,当在一个视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变时调用这个回调函数。
root.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect rect = new Rect();
// 获取root在窗体的可视区域
root.getWindowVisibleDisplayFrame(rect);
// 当前视图最外层的高度减去现在所看到的视图的最底部的y坐标
int rootInvisibleHeight = root.getRootView()
.getHeight() - rect.bottom;
Log.i("tag", "最外层的高度" + root.getRootView().getHeight());
// 若rootInvisibleHeight高度大于100,则说明当前视图上移了,说明软键盘弹出了
if (rootInvisibleHeight > 100) {
//软键盘弹出来的时候
int[] location = new int[2];
// 获取scrollToView在窗体的坐标
scrollToView.getLocationInWindow(location);
// 计算root滚动高度,使scrollToView在可见区域的底部
int srollHeight = (location[1] + scrollToView
.getHeight()) - rect.bottom;
root.scrollTo(0, srollHeight);
} else {
// 软键盘没有弹出来的时候
root.scrollTo(0, 0);
}
}
});
}
}
5.SPUtils
import android.content.Context;
import android.content.SharedPreferences;
import java.util.ArrayList;
import java.util.List;
/**
* SharedPreferences工具类<p>
* <li>put 存数据</li>
* <li>get 取数据</li>
* <li>cleanFile 清空指定SP文件</li>
* <li>cleanAll 清空所有的SP文件</li>
* Author:蔡小树 <p>
* Date:2017/10/16<p>
* Time:14:07<p>
* No bug!No bug!No bug!<p>
*/
public class SPUtils {
//保存文件的集合
private static List<String> files = new ArrayList<>();
//SharedPreferences 的实例
private static SharedPreferences mSp;
/**
* 存入数据
*
* @param context
* @param fileName 文件名,这样做的目的是分类存储数据
* @param key 键
* @param value 值
*/
public static void put(Context context, String fileName, String key, Object value) {
if (files != null && !files.contains(fileName)) {
files.add(fileName);
}
if (mSp == null) {
mSp = context.getSharedPreferences(fileName, 0);
}
SharedPreferences.Editor editor = mSp.edit();
if (value instanceof Integer) {
editor.putInt(key, Integer.parseInt(value.toString()));
} else if (value instanceof Long) {
editor.putLong(key, Long.parseLong(value.toString()));
} else if (value instanceof Boolean) {
editor.putBoolean(key, Boolean.parseBoolean(value.toString()));
} else if (value instanceof Float) {
editor.putFloat(key, Float.parseFloat(value.toString()));
} else {
editor.putString(key, value.toString());
}
editor.apply();
}
/**
* 获取int值
*
* @param context
* @param fileName 文件名
* @param key 键
* @return 默认值为-1024
*/
public static int getInt(Context context, String fileName, String key) {
if (mSp == null) {
mSp = context.getSharedPreferences(fileName, 0);
}
return mSp.getInt(key, -1024);
}
/**
* 获取long值
*
* @param context
* @param fildName 文件名
* @param key 键
* @return 默认值为-1024
*/
public static long getLong(Context context, String fildName, String key) {
if (mSp == null) {
mSp = context.getSharedPreferences(fildName, 0);
}
return mSp.getLong(key, -1024);
}
/**
* 获取Boolean值
*
* @param context
* @param fileName 文件名
* @param key 键
* @return 默认值是false
*/
public static boolean getBoolean(Context context, String fileName, String key) {
if (mSp == null) {
mSp = context.getSharedPreferences(fileName, 0);
}
return mSp.getBoolean(key, false);
}
/**
* 获取float值
*
* @param context
* @param fileName 文件名
* @param key 键
* @return 默认值是-10.24
*/
public static float getFloat(Context context, String fileName, String key) {
if (mSp == null) {
mSp = context.getSharedPreferences(fileName, 0);
}
return mSp.getFloat(key, -10.24f);
}
/**
* 获取String值
*
* @param context
* @param fileName 文件名
* @param key 键
* @return 默认值是-1024
*/
public static String getString(Context context, String fileName, String key) {
if (mSp == null) {
mSp = context.getSharedPreferences(fileName, 0);
}
return mSp.getString(key, "-1024");
}
/**
* 清空指定sp文件
*
* @param context
* @param fileName 文件名
*/
public static void cleanFile(Context context, String fileName) {
if (mSp == null) {
mSp = context.getSharedPreferences(fileName, 0);
}
if (files != null) {
SharedPreferences.Editor editor = mSp.edit();
editor.clear();
editor.apply();
files.remove(fileName);
}
}
/**
* 清空所有SP文件
*
* @param context
*/
public static void cleanAll(Context context) {
if (files != null) {
for (String fileName :
files) {
files.remove(fileName);
if (fileName != null) {
SharedPreferences sharedPreferences = context.getSharedPreferences(fileName, 0);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.clear();
editor.apply();
}
}
}
}
}
6.ToastUtils
import android.content.Context;
import android.widget.Toast;
/**
* Toast消息展示工具类<p>
* <li>showShort 短时间展示</li>
* <li>showLong 长时间展示</li>
* <li>showAuto 自定义时长展示</li>
* Author:蔡小树 <p>
* Date:2017/10/16<p>
* Time:13:46<p>
* No bug!No bug!No bug!<p>
*/
public class ToastUtils {
//Toast的实例
private static Toast mToast;
/**
* 短时间展示
*
* @param context
* @param msg 消息
*/
public static void showShort(Context context, Object msg) {
if (mToast != null) {
mToast.cancel();
}
mToast = Toast.makeText(context, String.valueOf(msg), Toast.LENGTH_SHORT);
mToast.show();
}
/**
* 长时间展示
*
* @param context
* @param msg 消息
*/
public static void showLong(Context context, Object msg) {
if (mToast != null) {
mToast.cancel();
}
mToast = Toast.makeText(context, String.valueOf(msg), Toast.LENGTH_LONG);
mToast.show();
}
/**
* 自定义时长展示
*
* @param context
* @param msg 消息
* @param duration 显示时间,按毫秒记
*/
public static void showAuto(Context context, Object msg, int duration) {
if (mToast != null) {
mToast.cancel();
}
mToast = Toast.makeText(context, String.valueOf(msg), duration);
mToast.show();
}
}
7.LanguageUtils
import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.DisplayMetrics;
import java.util.Locale;
/**
* APP国际化,多语言工具类
* <li>isSaveLanguage 检查是否是保存的Language</li>
* <li>getLanguage 获取APP的language</li>
* <li>setLanguage 设置app的language</li>
* Author:蔡小树 <p>
* Date:2017/10/18<p>
* Time:11:42<p>
* No bug!No bug!No bug!<p>
*/
public class LanguageUtils {
/**
* 检查是否是保存的Language
*
* @return
*/
public static boolean isSaveLanguage() {
Locale currentLocale = MyApp.getApp().getResources().getConfiguration().locale;
return currentLocale.equals(getLanguage());
}
/**
* 获取APP的language
*
* @return
*/
public static Locale getLanguage() {
String language = SPUtils.getString(MyApp.getApp(), "language", "language");
Locale locale;
switch (language) {
case "en":
locale = Locale.ENGLISH;
break;
case "zh":
locale = Locale.SIMPLIFIED_CHINESE;
break;
case "tw":
locale = Locale.TRADITIONAL_CHINESE;
break;
default:
locale = Locale.getDefault();
break;
}
return locale;
}
/**
* 设置app的language
*/
public static void setLanguage(Activity activity) {
Resources resources = activity.getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
Configuration config = resources.getConfiguration();
config.locale = LanguageUtils.getLanguage();
resources.updateConfiguration(config, dm);
//关闭除当前界面外所有的界面
ActivityManager.cleanActivityWithOutThis(activity);
Intent intent = new Intent(activity, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
activity.startActivity(intent);
//跳转之后移除活动
ActivityManager.removeActivity(activity);
}
}
8.BaseActivity
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
/**
* BaseActivity 基础Activity<p>
* Author:蔡小树 <p>
* Date:2017/10/13<p>
* Time:9:59<p>
* No bug!No bug!No bug!<p>
*/
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!LanguageUtils.isSaveLanguage()) {
LanguageUtils.setLanguage(this);
}
ActivityManager.addActivity(this);
setContentView();
initView();
}
/**
* 加载布局
*/
protected abstract void setContentView();
/**
* 初始化控件
*/
protected abstract void initView();
}
9.MyApp
import android.app.Application;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.DisplayMetrics;
/**
* Application
* Author:蔡小树 <p>
* Date:2017/10/17<p>
* Time:14:19<p>
* No bug!No bug!No bug!<p>
*/
public class MyApp extends Application {
private static MyApp instance;
/**
* 获取Application
*/
public static MyApp getApp() {
return instance;
}
public static MyApp getInstance(Application context) {
if (instance == null) {
instance = (MyApp) context;
}
return instance;
}
@Override
public void onCreate() {
super.onCreate();
setLanguage();
}
/**
* 设置language
*/
private void setLanguage() {
Resources resources = MyApp.getInstance(this).getApp().getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
Configuration config = resources.getConfiguration();
config.locale = LanguageUtils.getLanguage();
resources.updateConfiguration(config, dm);
}
}
10.双击退出
//是否是要退出应用
private static boolean isExit = false;
private static Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
isExit = false;
}
};
@Override
public void onBackPressed() {
exit();
}
/**
* 双击退出应用
*/
private void exit() {
if (!isExit) {
isExit = true;
ToastUtils.showShort(this, "双击退出应用!");
//2s内没有再次点击将不认为要退出应用
mHandler.sendEmptyMessageDelayed(0, 2000);
} else {
ActivityManager.cleanActivity();
}
}