我们先介绍一下Android 对进程和内存的管理
如果内存足够,Android不会杀掉任何进程,如果内存不足就是进程随时可能会被杀掉。
而Android会在内存充足的时候,重启被杀掉的进程。
也就是说静态变量的值,如果不做处理,是不可靠的,可以说内存中的一切都不可靠。
如果要可靠,还是得保存到文件中去,在重启的时候恢复回来。
Android Application其实是一个单例对象,也是放在内存中的,当进程被杀掉,缓存数据就全清空了,只不过Android系统会帮重建Application,而我们存放在Application的缓存数据自然就没有了,还是得自己处理。
不过我们可以在Application被销毁时直接退出程序,其实Application都被销毁了,程序就应该退出的。
看完之后是不是感觉都要晕了,Android 你杀死进程就杀死嘛,干嘛又要重启。。。重启之后,再用一些缓存数据(Application里的数据,静态变量数据等等),就容易造成一些问题(比如:NullPointerException),为了避免这些问题,我们要在内存不足的时候彻底杀死App。
1.写一个Activity的管理类。
package com.phone.common_library.manager;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.text.TextUtils;
import java.util.List;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicBoolean;
public class ActivityPageManager {
private static final String TAG = "ActivityPageManager";
private static ActivityPageManager mActivityPageManager;
private Stack mActivityStack = new Stack<>();
private Stack mActivityAliveStack = new Stack<>();
private AtomicBoolean isLastAliveActivity = new AtomicBoolean(false);
private ActivityPageManager() {
}
public static ActivityPageManager getInstance() {
if (mActivityPageManager == null) {
synchronized (ActivityPageManager.class) {
if (mActivityPageManager == null) {
mActivityPageManager = new ActivityPageManager();
}
}
}
return mActivityPageManager;
}
public void addActivity(Activity activity) {
mActivityStack.add(activity);
}
public void removeActivity(Activity activity) {
if (activity != null && mActivityStack.contains(activity)) {
mActivityStack.remove(activity);
}
}
public Activity getCurrentActivity() {
return mActivityStack.lastElement();
}
public Activity getActivity(Class> cls) {
if (mActivityStack != null)
for (Activity activity : mActivityStack) {
if (activity.getClass().equals(cls)) {
return activity;
}
}
return null;
}
public void finishCurrentActivity() {
Activity activity = mActivityStack.lastElement();
finishActivity(activity);
}
public void finishActivity(Activity activity) {
if (activity != null && mActivityStack.contains(activity)) {
mActivityStack.remove(activity);
LogManager.i(TAG, "finishActivity");
activity.finish();
}
}
public void finishAliveActivity(Activity activity) {
if (activity != null && mActivityAliveStack.contains(activity)) {
mActivityAliveStack.remove(activity);
LogManager.i(TAG, "finishActivity");
activity.finish();
}
}
public void finishActivity(Class> clazz) {
for (Activity activity : mActivityStack) {
if (activity.getClass().equals(clazz)) {
finishActivity(activity);
break;
}
}
}
public void finishAllActivity() {
mActivityAliveStack.clear();
for (int i = mActivityStack.size() - 1; i >= 0; i--) {
if (mActivityStack.get(i) != null) {
mActivityAliveStack.add(mActivityStack.get(i));
}
}
for (int i = mActivityAliveStack.size() - 1; i >= 0; i--) {
if (i == 0) {
isLastAliveActivity.set(true);
LogManager.i(TAG, "isLastAliveActivity.set(true)");
}
finishAliveActivity(mActivityAliveStack.get(i));
}
mActivityAliveStack.clear();
mActivityStack.clear();
}
public AtomicBoolean isLastAliveActivity() {
return isLastAliveActivity;
}
public void finishAllActivityExcept(Class> clazz) {
for (int i = mActivityStack.size() - 1; i >= 0; i--) {
if (mActivityStack.get(i) != null && !mActivityStack.get(i).getClass().equals(clazz)) {
finishActivity(mActivityStack.get(i));
}
}
}
public void exitApp() {
try {
finishAllActivity();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.exit(0);
}
}
public void exitApp2() {
try {
LogManager.i(TAG, "exitApp2");
finishAllActivity();
} catch (Exception e) {
e.printStackTrace();
}
}
public static boolean isForeground(Context context, String className) {
if (context == null || TextUtils.isEmpty(className)) {
return false;
}
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List list = am.getRunningTasks(1);
if (list != null && list.size() > 0) {
ComponentName cpn = list.get(0).topActivity;
if (className.equals(cpn.getClassName())) {
return true;
}
}
return false;
}
}
2.写一个基础Activity(只要在自己的Activity加上和ActivityPageManager关联的方法,还有killAppProcess方法就行了)。
package com.phone.common_library.base;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.os.Looper;
import android.view.Gravity;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import com.gyf.immersionbar.ImmersionBar;
import com.phone.common_library.BaseApplication;
import com.phone.common_library.R;
import com.phone.common_library.manager.ActivityPageManager;
import com.phone.common_library.manager.CrashHandlerManager;
import com.phone.common_library.manager.LogManager;
import com.phone.common_library.manager.ToolbarManager;
import com.trello.rxlifecycle3.components.support.RxAppCompatActivity;
import java.util.List;
import java.util.Map;
public abstract class BaseRxAppActivity extends RxAppCompatActivity {
private static final String TAG = "BaseRxAppActivity";
// protected QMUILoadingView loadView;
// protected FrameLayout.LayoutParams layoutParams;
protected Intent intent;
protected Bundle bundle;
protected RxAppCompatActivity rxAppCompatActivity;
protected BaseApplication baseApplication;
private ActivityPageManager activityPageManager;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rxAppCompatActivity = this;
baseApplication = (BaseApplication) getApplication();
activityPageManager = ActivityPageManager.getInstance();
activityPageManager.addActivity(rxAppCompatActivity);
setContentView(initLayoutId());
// loadView = new QMUILoadingView(rxAppCompatActivity);
// loadView.setVisibility(View.GONE);
// loadView.setSize(100);
// loadView.setColor(getResources().getColor(R.color.color_80000000));
// layoutParams = new FrameLayout.LayoutParams(
// FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
// layoutParams.gravity = Gravity.CENTER;
// setToolbar();
initData();
initViews();
initLoadData();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
//非默认值
if (newConfig.fontScale != 1) {
getResources();
}
super.onConfigurationChanged(newConfig);
}
@Override
public Resources getResources() {//还原字体大小
Resources res = super.getResources();
//非默认值
if (res.getConfiguration().fontScale != 1) {
Configuration newConfig = new Configuration();
newConfig.setToDefaults();//设置默认
res.updateConfiguration(newConfig, res.getDisplayMetrics());
}
return res;
}
protected abstract int initLayoutId();
protected void setToolbar(boolean isDarkFont) {
if (isDarkFont) {
ImmersionBar.with(rxAppCompatActivity) //原理:如果当前设备支持状态栏字体变色,会设置状态栏字体为黑色,如果当前设备不支持状态栏字体变色,会使当前状态栏加上透明度,否则不执行透明度
.statusBarDarkFont(isDarkFont)
.statusBarColor(R.color.color_FFFFFFFF) //状态栏颜色,不写默认透明色
// .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦
.keyboardEnable(true)
.init();
} else {
ImmersionBar.with(rxAppCompatActivity)
.statusBarDarkFont(isDarkFont)
.statusBarColor(R.color.color_FF198CFF) //状态栏颜色,不写默认透明色
// .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦
.keyboardEnable(true)
.init();
}
ToolbarManager.assistActivity(findViewById(android.R.id.content));
}
protected void setToolbar(boolean isDarkFont, boolean isResizeChildOfContent) {
if (isDarkFont) {
ImmersionBar.with(rxAppCompatActivity) //原理:如果当前设备支持状态栏字体变色,会设置状态栏字体为黑色,如果当前设备不支持状态栏字体变色,会使当前状态栏加上透明度,否则不执行透明度
.statusBarDarkFont(isDarkFont)
.statusBarColor(R.color.color_FFFFFFFF) //状态栏颜色,不写默认透明色
// .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦
.keyboardEnable(true)
.init();
} else {
ImmersionBar.with(rxAppCompatActivity)
.statusBarDarkFont(isDarkFont)
.statusBarColor(R.color.color_FF198CFF) //状态栏颜色,不写默认透明色
// .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦
.keyboardEnable(true)
.init();
}
if (isResizeChildOfContent) {
ToolbarManager.assistActivity(findViewById(android.R.id.content));
}
}
protected void setToolbar(boolean isDarkFont, int color) {
if (isDarkFont) {
ImmersionBar.with(rxAppCompatActivity) //原理:如果当前设备支持状态栏字体变色,会设置状态栏字体为黑色,如果当前设备不支持状态栏字体变色,会使当前状态栏加上透明度,否则不执行透明度
.statusBarDarkFont(isDarkFont)
.statusBarColor(color) //状态栏颜色,不写默认透明色
// .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦
.init();
} else {
ImmersionBar.with(rxAppCompatActivity)
.statusBarDarkFont(isDarkFont)
.statusBarColor(color) //状态栏颜色,不写默认透明色
// .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦
.init();
}
ToolbarManager.assistActivity(findViewById(android.R.id.content));
}
protected void setToolbar(boolean isDarkFont, int color, boolean isResizeChildOfContent) {
if (isDarkFont) {
ImmersionBar.with(rxAppCompatActivity) //原理:如果当前设备支持状态栏字体变色,会设置状态栏字体为黑色,如果当前设备不支持状态栏字体变色,会使当前状态栏加上透明度,否则不执行透明度
.statusBarDarkFont(isDarkFont)
.statusBarColor(color) //状态栏颜色,不写默认透明色
// .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦
.init();
} else {
ImmersionBar.with(rxAppCompatActivity)
.statusBarDarkFont(isDarkFont)
.statusBarColor(color) //状态栏颜色,不写默认透明色
// .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦
.init();
}
if (isResizeChildOfContent) {
ToolbarManager.assistActivity(findViewById(android.R.id.content));
}
}
protected void initImmersionBar() {
//设置共同沉浸式样式
ImmersionBar.with(rxAppCompatActivity).navigationBarColor(R.color.color_FFE066FF).init();
}
protected abstract void initData();
protected abstract void initViews();
protected abstract void initLoadData();
protected void showToast(String message, boolean isLongToast) {
// Toast.makeText(rxAppCompatActivity, message, Toast.LENGTH_LONG).show();
if (!rxAppCompatActivity.isFinishing()) {
Toast toast;
int duration;
if (isLongToast) {
duration = Toast.LENGTH_LONG;
} else {
duration = Toast.LENGTH_SHORT;
}
toast = Toast.makeText(rxAppCompatActivity, message, duration);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
}
protected void showCustomToast(int left, int right,
int textSize, int textColor,
int bgColor, int height,
int roundRadius, String message) {
FrameLayout frameLayout = new FrameLayout(rxAppCompatActivity);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
frameLayout.setLayoutParams(layoutParams);
TextView textView = new TextView(rxAppCompatActivity);
FrameLayout.LayoutParams layoutParams1 = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, height);
textView.setLayoutParams(layoutParams1);
textView.setPadding(left, 0, right, 0);
textView.setTextSize(textSize);
textView.setTextColor(textColor);
textView.setGravity(Gravity.CENTER);
textView.setIncludeFontPadding(false);
GradientDrawable gradientDrawable = new GradientDrawable();//创建drawable
gradientDrawable.setColor(bgColor);
gradientDrawable.setCornerRadius(roundRadius);
textView.setBackground(gradientDrawable);
textView.setText(message);
frameLayout.addView(textView);
Toast toast = new Toast(rxAppCompatActivity);
toast.setView(frameLayout);
toast.setDuration(Toast.LENGTH_LONG);
toast.show();
}
public boolean isOnMainThread() {
return Looper.getMainLooper().getThread().getId() == Thread.currentThread().getId();
}
protected void startActivity(Class> cls) {
intent = new Intent(rxAppCompatActivity, cls);
startActivity(intent);
}
protected void startActivityCarryParams(Class> cls, Map params) {
intent = new Intent(rxAppCompatActivity, cls);
bundle = new Bundle();
if (params != null && params.size() > 0) {
for (String key : params.keySet()) {
if (params.get(key) != null) {//如果参数不是null,才把参数传给后台
bundle.putString(key, params.get(key));
}
}
intent.putExtras(bundle);
}
startActivity(intent);
}
protected void startActivityForResult(Class> cls, int requestCode) {
intent = new Intent(rxAppCompatActivity, cls);
startActivityForResult(intent, requestCode);
}
protected void startActivityForResultCarryParams(Class> cls, Map params, int requestCode) {
intent = new Intent(rxAppCompatActivity, cls);
bundle = new Bundle();
if (params != null && params.size() > 0) {
for (String key : params.keySet()) {
if (params.get(key) != null) {//如果参数不是null,才把参数传给后台
bundle.putString(key, params.get(key));
}
}
intent.putExtras(bundle);
}
startActivityForResult(intent, requestCode);
}
protected boolean isEmpty(String dataStr) {
if (dataStr != null && !"".equals(dataStr)) {
return false;
} else {
return true;
}
}
private void killAppProcess(Context context) {
LogManager.i(TAG, "killAppProcess");
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List processInfos = manager.getRunningAppProcesses();
// 先杀掉相关进程,最后再杀掉主进程
for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : processInfos) {
if (runningAppProcessInfo.pid != android.os.Process.myPid()) {
android.os.Process.killProcess(runningAppProcessInfo.pid);
}
}
LogManager.i(TAG, "执行killAppProcess,應用開始自殺");
CrashHandlerManager crashHandlerManager = CrashHandlerManager.getInstance(context);
crashHandlerManager.saveTrimMemoryInfoToFile("执行killAppProcess,應用開始自殺");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
LogManager.i(TAG, "error");
}
android.os.Process.killProcess(android.os.Process.myPid());
// 正常退出程序,也就是结束当前正在运行的 java 虚拟机
System.exit(0);
}
@Override
protected void onDestroy() {
if (activityPageManager != null) {
if (activityPageManager.isLastAliveActivity().get()) {
killAppProcess(baseApplication);
}
activityPageManager.removeActivity(rxAppCompatActivity);
}
super.onDestroy();
}
}
3.写一个基础Application(只要在自己的Application加上和ActivityPageManager关联的方法,还有onTrimMemory方法就行了)。
package com.phone.common_library;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.multidex.MultiDex;
import androidx.multidex.MultiDexApplication;
import com.alibaba.android.arouter.launcher.ARouter;
import com.phone.common_library.manager.ActivityPageManager;
import com.phone.common_library.manager.CrashHandlerManager;
import com.phone.common_library.manager.LogManager;
import com.phone.common_library.manager.RetrofitManager;
public class BaseApplication extends MultiDexApplication {
private static final String TAG = "BaseApplication";
//声明 初始化
protected SharedPreferences sp;
protected SharedPreferences.Editor editor;
protected static final int MODE = Context.MODE_PRIVATE;
private boolean isLogin;
private String accessToken;
private String systemId;
protected static BaseApplication baseApplication;
private ActivityPageManager activityPageManager;
@Override
public void onCreate() {
super.onCreate();
baseApplication = this;
//文件为mySp 存放在/data/data//shared_prefs/目录下的
sp = getSharedPreferences("app", MODE);
editor = sp.edit();
//初始化retrofit
RetrofitManager.getInstance();
activityPageManager = ActivityPageManager.getInstance();
CrashHandlerManager crashHandlerManager = CrashHandlerManager.getInstance(this);
crashHandlerManager.sendPreviousReportsToServer();
crashHandlerManager.init();
if (true) {
ARouter.openLog();
ARouter.openDebug();
}
ARouter.init(this);
// RxJavaPlugins.setErrorHandler(new Consumer() {
// @Override
// public void accept(Throwable throwable) {
// //异常处理
// LogManager.i(TAG, "throwable*****" + throwable.toString());
// LogManager.i(TAG, "throwable message*****" + throwable.getMessage());
// }
// });
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
public static BaseApplication getInstance() {
return baseApplication;
}
public boolean isLogin() {
isLogin = sp.getBoolean("isLogin", false);
LogManager.i(TAG, "isLogin***" + isLogin);
return isLogin;
}
public void setLogin(boolean isLogin) {
LogManager.i(TAG, "setLogin***" + isLogin);
editor.putBoolean("isLogin", isLogin);
editor.commit();
if (!isLogin) {
setLogout();
}
}
public String getAccessToken() {
accessToken = sp.getString("accessToken", "");
return accessToken;
}
public void setAccessToken(String accessToken) {
LogManager.i(TAG, "setAccessToken***" + accessToken);
editor.putString("accessToken", accessToken);
editor.commit();
}
public String getSystemId() {
systemId = sp.getString("systemId", "");
return systemId;
}
public void setSystemId(String systemId) {
LogManager.i(TAG, "setSystemId***" + systemId);
editor.putString("systemId", systemId);
editor.commit();
}
public void setLogout() {
LogManager.i(TAG, "setLogout***");
// editor.clear();
editor.remove("accessToken");
editor.remove("isLogin");
editor.commit();
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (level == TRIM_MEMORY_MODERATE) {
//App开始自杀,清理掉所有的activity(最後一個存活的Activity退出的时候(onDestroy)做了退出應用程序處理)
activityPageManager.exitApp2();
}
}
}
因内存不足进程被杀掉,而Android会在内存充足的时候,重启被杀掉的进程,然后再用一些缓存数据(Application里的数据,静态变量数据等等),就容易造成一些问题(比如:NullPointerException)。
这样就可以在内存不足的时候彻底杀死App,这样就会避免因以上原因造成的问题了。
如对此有疑问,请联系qq1164688204。
推荐Android开源项目
项目功能介绍:RxJava2和Retrofit2项目,添加自动管理token功能,添加RxJava2生命周期管理,使用App架构设计是MVP模式和MVVM模式,同时使用组件化,部分代码使用Kotlin,此项目持续维护中。
项目地址:https://gitee.com/urasaki/RxJava2AndRetrofit2



