【我的Android开发】AMS中Activity栈管理
概述
Activity栈管理是AMS的另一个重要功能,栈管理又和Activity的启动模式和startActivity时所设置的Flag息息相关,Activity栈管理的主要处理逻辑是在ActivityStarter#startActivityUnchecked方法中,本文也会围绕着这个方法进进出出,反复摩擦,直到脑海中都是它的形状。goolge的工程师起名还是很讲究的,为什么要带Unchecked呢? Unchecked-不确定,是因为在执行这个方法时,我要启动哪个Activity还没决定呢,具体为什么,我想看过这篇文章你就明白了。
Activity栈管理相关类
ActivityStackSupervisor
Activity栈的管理人
ActivityDisplay
表示一个屏幕,Android支持三种屏幕,主屏幕,外接屏幕,虚拟屏幕(投屏)【这个介绍是从其他地方看来的,并不确定】。一般在手机上只有主屏幕,此时ActivityStackSupervisor与ActivityDisplay都是系统唯一的
TaskRecord
是ActivityTask的记录,TaskRecord是Activity栈的重要管理单元。形象一点理解,记得启动模式的 singleTask 吧?意思就是让这个Activity在单独的TaskRecord中启动。“Task":任务。
ActivityRecord
记录着每个Activity的信息,ActivityRecord和Activity一一对应。
ActivityStack
是ActivityRecord和TaskRecord两者的统一上司,记录着ActivityRecord和TaskRecord的状态。
如果在只有主屏幕的设备上,他们之间的关系大概是这样子的:

可以理解为一个屏幕上,可能会有很多个APP进程,每个APP进程对应一个ActivityStack,也就是activity栈,其中由于Activity的启动模式不同,又形成了若干个TaskRecord,其中包含着若干个ActivityRecord。
Activity 的四种启动模式,以及启动标识符
Standard
标准启动模式,启动Activity的时候向发起人的Task顶直接添加即可,返回时依次退出。
SingleTop
栈顶唯一,如果栈顶Activity不是要启动的Activity,则会创建一个新的Activity实例,但如果栈顶Activity就是我们要启动的Activity,就只会调用onNewIntent,而不去再重新创建一个实例。相比Standard,Standard不论如何,都会创建一个新的实例。
SingleTask
栈内唯一。如果发起启动的ActivityRecord所在的TaskRecord中,有要启动的Activity对应的ActivityRecord,则首先将TaskRecord中,目标Activity之上的所有ActivityRecord全都弹出,然后将所在TaskRecord变为ActivityStack的栈顶。
如果发起启动的ActivityRecord所在的TaskRecord中,没有要启动的Activity对应的ActivityRecord,则会在栈顶新建一个TaskRecord,并向其中实例化一个需要启动的Activity对应的ActivityRecord。
SingleInstance
独占一个TaskRecord。启动时,在ActivityStack中查找是否有相同的Activity,如果有,则用这个独占TaskRecord的ActivityRecord对应的Activity。否则新建一个TaskRecord,里面只有它存在。由singleInstance发起的启动,不论是谁,都会在另一个task中启动。
代码实现
通过对"android.app.ActivityThread"进行反射。获取android系统的activity栈
遍历activity栈能够得到当前应用中的全部存活的activity。
Log.e("Baseactivty", this.getClass().getName() +":oncreate");Class activityThreadClass = null;try {activityThreadClass = Class.forName("android.app.ActivityThread");Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null);Field activitiesField = activityThreadClass.getDeclaredField("mActivities");activitiesField.setAccessible(true);Map activities = (Map) activitiesField.get(activityThread);int i = 0;for (Object activityRecord : activities.values()) {Class activityRecordClass = activityRecord.getClass();Field activityField = activityRecordClass.getDeclaredField("activity");activityField.setAccessible(true);Activity activity = (Activity) activityField.get(activityRecord);Log.e("activityThreadClass", "index:" + i + ",sum:" + activities.size()+ ", class name:" + activity.getClass().getName());i++;}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}
当你在Activity的oncreate中调用上述方法时。你会发现activity列表activities中没有当前的activity,这是由于当前activity还没有被增加栈中。可是onResume中调用上面的函数。就发现当前activity已经被增加栈中。
2.2 重写Instrumentation
监听activity的声明周期。现实自己想要的操作。
首先"绕庄"操作,即在当前project的src文件夹以下新建anroid.app包,然后声明ActivityThread、Instrumentation、LoadedApk三个文件。
ActivityThread类
package android.app;import android.content.pm.ApplicationInfo;public final class ActivityThread {/*** NOTICE: 必须在UI线程调用本方法,否则返回NULL** @return*/public static ActivityThread currentActivityThread() {return null;}public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai) {return null;}
}
Instrumentation类
package android.app;import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.view.KeyEvent;
import android.view.MotionEvent;public class Instrumentation {public void onCreate(Bundle arguments) {}public void start() {}public void onStart() {}public boolean onException(Object obj, Throwable e) {return false;}public void sendStatus(int resultCode, Bundle results) {}public void finish(int resultCode, Bundle results) {}public void setAutomaticPerformanceSnapshots() {}public void startPerformanceSnapshot() {}public void endPerformanceSnapshot() {}public void onDestroy() {}public Context getContext() {return null;}public ComponentName getComponentName() {return null;}public Context getTargetContext() {return null;}public boolean isProfiling() {return false;}public void startProfiling() {}public void stopProfiling() {}public void setInTouchMode(boolean inTouch) {}public void waitForIdle(Runnable recipient) {}public void waitForIdleSync() {}public void runOnMainSync(Runnable runner) {}public Activity startActivitySync(Intent intent) {return null;}public void addMonitor(ActivityMonitor monitor) {}public Instrumentation.ActivityMonitor addMonitor(IntentFilter filter, ActivityResult result, boolean block) {return null;}public ActivityMonitor addMonitor(String cls, ActivityResult result, boolean block) {return null;}public boolean checkMonitorHit(ActivityMonitor monitor, int minHits) {return false;}public Activity waitForMonitor(ActivityMonitor monitor) {return null;}public Activity waitForMonitorWithTimeout(ActivityMonitor monitor, long timeOut) {return null;}public void removeMonitor(ActivityMonitor monitor) {}public boolean invokeMenuActionSync(Activity targetActivity, int requestCode, int flag) {return false;}public boolean invokeContextMenuAction(Activity targetActivity, int requestCode, int flag) {return false;}public void sendStringSync(String text) {}public void sendKeySync(KeyEvent event) {}public void sendKeyDownUpSync(int key) {}public void sendCharacterSync(int keyCode) {}public void sendPointerSync(MotionEvent event) {}public void sendTrackballEventSync(MotionEvent event) {}public Application newApplication(ClassLoader cl, String className, Context who) throws InstantiationException, IllegalAccessException, ClassNotFoundException {return null;}public void callApplicationOnCreate(Application app) {}public Activity newActivity(Class<?> clazz, Context who, IBinder token, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance) throws InstantiationException, IllegalAccessException {return null;}public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {return null;}public void callActivityOnCreate(Activity target, Bundle icicle) {}public void callActivityOnDestroy(Activity target) {}public void callActivityOnRestoreInstanceState(Activity target, Bundle savedInstanceState) {}public void callActivityOnPostCreate(Activity target, Bundle icicle) {}public void callActivityOnNewIntent(Activity target, Intent intent) {}public void callActivityOnStart(Activity target) {}public void callActivityOnRestart(Activity target) {}public void callActivityOnResume(Activity target) {}public void callActivityOnStop(Activity target) {}public void callActivityOnSaveInstanceState(Activity target, Bundle outState) {}public void callActivityOnPause(Activity target) {}public void callActivityOnUserLeaving(Activity target) {}public void startAllocCounting() {}public void stopAllocCounting() {}public Bundle getAllocCounts() {return null;}public Bundle getBinderCounts() {return null;}public UiAutomation getUiAutomation() {return null;}public ActivityResult execStartActivity(final Context who, final IBinder contextThread, final IBinder token, final Activity target, final Intent intent, final int requestCode) {return null;}public ActivityResult execStartActivity(final Context who, final IBinder contextThread, final IBinder token, final Activity target, final Intent intent, final int requestCode, final Bundle options) {return null;}public ActivityResult execStartActivity(final Context who, final IBinder contextThread, final IBinder token, final Fragment fragment, final Intent intent, final int requestCode) {return null;}public ActivityResult execStartActivity(final Context who, final IBinder contextThread, final IBinder token, final Fragment fragment, final Intent intent, final int requestCode, final Bundle options) {return null;}protected static final class ActivityMonitor {}public static final class ActivityResult {}}
LoadedApk类
package android.app;public class LoadedApk {public Application makeApplication(boolean forceDefaultAppClass,Instrumentation instrumentation) {return null;}public ClassLoader getClassLoader() {return null;}
}
首先"绕庄"的目的是为绕过编译过程,Instrumentation属于内核实现类型,不能直接使用,否则会编译出错。
以下是一个反射的工具类,有lody大神设计
NULL类
/*** 用来表示null的类.**/
public class NULL {
}
Reflect类
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;import android.annotation.SuppressLint;/*** 一个拥有流畅特性(Fluent-API)的反射工具类,* 使用起来就像直接调用一样流畅易懂.**/
@SuppressLint("DefaultLocale")
public class Reflect {private final Object object;private final boolean isClass;private Reflect(Class<?> type) {this.object = type;this.isClass = true;}private Reflect(Object object) {this.object = object;this.isClass = false;}/*** 依据指定的类名构建反射工具类** @param name 类的全名* @return 反射工具类* @throws 假设反射出现意外* @see #on(Class)*/public static Reflect on(String name) throws ReflectException {return on(forName(name));}/*** 从指定的类载入起寻找类,并构建反射工具类** @param name 类的全名* @param classLoader 须要构建工具类的类的类载入器* loaded.* @return 反射工具类* @throws ReflectException 假设反射出现意外* @see #on(Class)*/public static Reflect on(String name, ClassLoader classLoader) throws ReflectException {return on(forName(name, classLoader));}/*** 依据指定的类构建反射工具类* <p>* 当你须要訪问静态字段的时候本方法适合你,* 你还能够通过调用 {@link #create(Object...)} 创建一个对象.** @param clazz 须要构建反射工具类的类* @return 反射工具类*/public static Reflect on(Class<?> clazz) {return new Reflect(clazz);}// ---------------------------------------------------------------------// 构造器// ---------------------------------------------------------------------/*** Wrap an object.* <p>* Use this when you want to access instance fields and methods on any* {@link Object}** @param object The object to be wrapped* @return A wrapped object, to be used for further reflection.*/public static Reflect on(Object object) {return new Reflect(object);}/*** 让一个{@link AccessibleObject}可訪问.** @param accessible* @param <T>* @return*/public static <T extends AccessibleObject> T accessible(T accessible) {if (accessible == null) {return null;}if (accessible instanceof Member) {Member member = (Member) accessible;if (Modifier.isPublic(member.getModifiers()) &&Modifier.isPublic(member.getDeclaringClass().getModifiers())) {return accessible;}}if (!accessible.isAccessible()) {accessible.setAccessible(true);}return accessible;}// ---------------------------------------------------------------------// Fluent Reflection API// ---------------------------------------------------------------------/*** 将给定字符串的开头改为小写.** @param string* @return*/@SuppressLint("DefaultLocale")private static String property(String string) {int length = string.length();if (length == 0) {return "";} else if (length == 1) {return string.toLowerCase();} else {return string.substring(0, 1).toLowerCase() + string.substring(1);}}private static Reflect on(Constructor<?> constructor, Object... args) throws ReflectException {try {return on(accessible(constructor).newInstance(args));} catch (Exception e) {throw new ReflectException(e);}}private static Reflect on(Method method, Object object, Object... args) throwsReflectException {try {accessible(method);if (method.getReturnType() == void.class) {method.invoke(object, args);return on(object);} else {return on(method.invoke(object, args));}} catch (Exception e) {throw new ReflectException(e);}}/*** 取得内部维护的对象.*/private static Object unwrap(Object object) {if (object instanceof Reflect) {return ((Reflect) object).get();}return object;}/*** 将Object数组转换为其类型的数组.* 假设对象中包括null,我们用NULL.class取代.** @see Object#getClass()*/private static Class<?>[] types(Object... values) {if (values == null) {return new Class[0];}Class<?>[] result = new Class[values.length];for (int i = 0; i < values.length; i++) {Object value = values[i];result[i] = value == null ?NULL.class : value.getClass();}return result;}/*** 取得一个类,此操作会初始化类的static区域.** @see Class#forName(String)*/private static Class<?> forName(String name) throws ReflectException {try {return Class.forName(name);} catch (Exception e) {throw new ReflectException(e);}}private static Class<?> forName(String name, ClassLoader classLoader) throws ReflectException {try {return Class.forName(name, true, classLoader);} catch (Exception e) {throw new ReflectException(e);}}/*** 假设给定的Class是原始类型,那么将其包装为对象类型,* 否则返回本身.*/public static Class<?> wrapper(Class<?> type) {if (type == null) {return null;} else if (type.isPrimitive()) {if (boolean.class == type) {return Boolean.class;} else if (int.class == type) {return Integer.class;} else if (long.class == type) {return Long.class;} else if (short.class == type) {return Short.class;} else if (byte.class == type) {return Byte.class;} else if (double.class == type) {return Double.class;} else if (float.class == type) {return Float.class;} else if (char.class == type) {return Character.class;} else if (void.class == type) {return Void.class;}}return type;}/*** 取得内部维护的实际对象** @param <T>* @return*/@SuppressWarnings("unchecked")public <T> T get() {return (T) object;}/*** 设置指定字段为指定值** @param name* @param value* @return* @throws ReflectException*/public Reflect set(String name, Object value) throwsReflectException {try {Field field = field0(name);field.setAccessible(true);field.set(object, unwrap(value));return this;} catch (Exception e) {throw new ReflectException(e);}}/*** @param name* @param <T>* @return* @throws ReflectException*/public <T> T get(String name) throws ReflectException {return field(name).get();}/*** 取得指定名称的字段** @param name* @return* @throws ReflectException*/public Reflect field(String name) throws ReflectException {try {Field field = field0(name);return on(field.get(object));} catch (Exception e) {throw new ReflectException(e);}}private Field field0(String name) throws ReflectException {Class<?> type = type();// 先尝试取得公有字段try {return type.getField(name);}//此时尝试非公有字段catch (NoSuchFieldException e) {do {try {return accessible(type.getDeclaredField(name));} catch (NoSuchFieldException ignore) {}type = type.getSuperclass();}while (type != null);throw new ReflectException(e);}}/*** 取得一个Map,map中的key为字段名,value为字段相应的反射工具类** @return*/public Map<String, Reflect> fields() {Map<String, Reflect> result = new LinkedHashMap<String, Reflect>();Class<?> type = type();do {for (Field field : type.getDeclaredFields()) {if (!isClass ^ Modifier.isStatic(field.getModifiers())) {String name = field.getName();if (!result.containsKey(name))result.put(name, field(name));}}type = type.getSuperclass();}while (type != null);return result;}/*** 调用指定的无參数方法** @param name* @return* @throws androidx.pluginmgr.reflect.ReflectException*/public Reflect call(String name) throws ReflectException {return call(name, new Object[0]);}/*** 调用方法依据传入的參数** @param name* @param args* @return* @throws androidx.pluginmgr.reflect.ReflectException*/public Reflect call(String name, Object... args) throws ReflectException {Class<?>[] types = types(args);try {Method method = exactMethod(name, types);return on(method, object, args);} catch (NoSuchMethodException e) {try {Method method = similarMethod(name, types);return on(method, object, args);} catch (NoSuchMethodException e1) {throw new ReflectException(e1);}}}private Method exactMethod(String name, Class<?>[] types) throws NoSuchMethodException {Class<?> type = type();try {return type.getMethod(name, types);} catch (NoSuchMethodException e) {do {try {return type.getDeclaredMethod(name, types);} catch (NoSuchMethodException ignore) {}type = type.getSuperclass();}while (type != null);throw new NoSuchMethodException();}}/*** 依据參数和名称匹配方法,假设找不到方法,*/private Method similarMethod(String name, Class<?>[] types) throws NoSuchMethodException {Class<?> type = type();for (Method method : type.getMethods()) {if (isSimilarSignature(method, name, types)) {return method;}}do {for (Method method : type.getDeclaredMethods()) {if (isSimilarSignature(method, name, types)) {return method;}}type = type.getSuperclass();}while (type != null);throw new NoSuchMethodException("No similar method " + name + " with params " + Arrays.toString(types) + " could be found on type " + type() + ".");}private boolean isSimilarSignature(Method possiblyMatchingMethod, String desiredMethodName, Class<?>[] desiredParamTypes) {return possiblyMatchingMethod.getName().equals(desiredMethodName) && match(possiblyMatchingMethod.getParameterTypes(), desiredParamTypes);}/*** 创建一个实例通过默认构造器** @return* @throws androidx.pluginmgr.reflect.ReflectException*/public Reflect create() throws ReflectException {return create(new Object[0]);}/*** 创建一个实例依据传入的參数** @param args* @return* @throws ReflectException*/public Reflect create(Object... args) throws ReflectException {Class<?>[] types = types(args);try {Constructor<?> constructor = type().getDeclaredConstructor(types);return on(constructor, args);} catch (NoSuchMethodException e) {for (Constructor<?> constructor : type().getDeclaredConstructors()) {if (match(constructor.getParameterTypes(), types)) {return on(constructor, args);}}throw new ReflectException(e);}}/*** 创建一个动态代理依据传入的类型.* 假设我们正在维护的是一个Map,那么当调用出现异常时我们将从Map中取值.** @param proxyType 须要动态代理的类型* @return 动态代理生成的对象*/@SuppressWarnings("unchecked")public <P> P as(Class<P> proxyType) {final boolean isMap = (object instanceof Map);final InvocationHandler handler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String name = method.getName();try {return on(object).call(name, args).get();} catch (ReflectException e) {if (isMap) {Map<String, Object> map = (Map<String, Object>) object;int length = (args == null ?0 : args.length);if (length == 0 && name.startsWith("get")) {return map.get(property(name.substring(3)));} else if (length == 0 && name.startsWith("is")) {return map.get(property(name.substring(2)));} else if (length == 1 && name.startsWith("set")) {map.put(property(name.substring(3)), args[0]);return null;}}throw e;}}};return (P) Proxy.newProxyInstance(proxyType.getClassLoader(), new Class[]{proxyType}, handler);}/*** 检查两个数组的类型是否匹配,假设数组中包括原始类型,将它们转换为相应的包装类型.*/private boolean match(Class<?>[] declaredTypes, Class<?>[] actualTypes) {if (declaredTypes.length == actualTypes.length) {for (int i = 0; i < actualTypes.length; i++) {if (actualTypes[i] == NULL.class)continue;if (wrapper(declaredTypes[i]).isAssignableFrom(wrapper(actualTypes[i])))continue;return false;}return true;} else {return false;}}/*** {@inheritDoc}*/@Overridepublic int hashCode() {return object.hashCode();}/*** {@inheritDoc}*/@Overridepublic boolean equals(Object obj) {if (obj instanceof Reflect) {return object.equals(((Reflect) obj).get());}return false;}/*** {@inheritDoc}*/@Overridepublic String toString() {return object.toString();}/*** 取得我们正在反射的对象的类型.** @see Object#getClass()*/public Class<?> type() {if (isClass) {return (Class<?>) object;} else {return object.getClass();}}}
ReflectException
/****/
public class ReflectException extends RuntimeException {private static final long serialVersionUID = 663038727503637969L;public ReflectException(String message) {super(message);}public ReflectException(String message, Throwable cause) {super(message, cause);}public ReflectException() {super();}public ReflectException(Throwable cause) {super(cause);}
}
接下来是activityThread的代理类
import Reflect;import android.app.ActivityThread;
import android.app.Application;
import android.app.Instrumentation;public class DelegateActivityThread {private static DelegateActivityThread SINGLETOPN = new DelegateActivityThread();private Reflect mActivityThreadReflect;public DelegateActivityThread() {mActivityThreadReflect = Reflect.on(ActivityThread.currentActivityThread());}public static DelegateActivityThread getSingletion() {return SINGLETOPN;}public Application getInitialApplication() {return mActivityThreadReflect.get("mInitialApplication");}public Instrumentation getInstrumentation() {return mActivityThreadReflect.get("mInstrumentation");}public void setInstrumentation(Instrumentation newInstrumentation) {mActivityThreadReflect.set("mInstrumentation", newInstrumentation);}
}
要在Instrumentation进行咱们自己操作的继承类DelegateInstrumentation
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Application;
import android.app.Fragment;
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;public class DelegateInstrumentation extends Instrumentation {private Instrumentation mBase;/*** @param mBase 真正的Instrumentation*/public DelegateInstrumentation(Instrumentation mBase) {this.mBase = mBase;}@Overridepublic void onCreate(Bundle arguments) {mBase.onCreate(arguments);}@Overridepublic void start() {mBase.start();}@Overridepublic void onStart() {mBase.onStart();}@Overridepublic boolean onException(Object obj, Throwable e) {return mBase.onException(obj, e);}@Overridepublic void sendStatus(int resultCode, Bundle results) {mBase.sendStatus(resultCode, results);}@Overridepublic void finish(int resultCode, Bundle results) {mBase.finish(resultCode, results);}@Overridepublic void setAutomaticPerformanceSnapshots() {mBase.setAutomaticPerformanceSnapshots();}@Overridepublic void startPerformanceSnapshot() {mBase.startPerformanceSnapshot();}@Overridepublic void endPerformanceSnapshot() {mBase.endPerformanceSnapshot();}@Overridepublic void onDestroy() {mBase.onDestroy();}@Overridepublic Context getContext() {return mBase.getContext();}@Overridepublic ComponentName getComponentName() {return mBase.getComponentName();}@Overridepublic Context getTargetContext() {return mBase.getTargetContext();}@Overridepublic boolean isProfiling() {return mBase.isProfiling();}@Overridepublic void startProfiling() {mBase.startProfiling();}@Overridepublic void stopProfiling() {mBase.stopProfiling();}@Overridepublic void setInTouchMode(boolean inTouch) {mBase.setInTouchMode(inTouch);}@Overridepublic void waitForIdle(Runnable recipient) {mBase.waitForIdle(recipient);}@Overridepublic void waitForIdleSync() {mBase.waitForIdleSync();}@Overridepublic void runOnMainSync(Runnable runner) {mBase.runOnMainSync(runner);}@Overridepublic Activity startActivitySync(Intent intent) {return mBase.startActivitySync(intent);}@Overridepublic void addMonitor(ActivityMonitor monitor) {mBase.addMonitor(monitor);}@Overridepublic ActivityMonitor addMonitor(IntentFilter filter, ActivityResult result, boolean block) {return mBase.addMonitor(filter, result, block);}@Overridepublic ActivityMonitor addMonitor(String cls, ActivityResult result, boolean block) {return mBase.addMonitor(cls, result, block);}@Overridepublic boolean checkMonitorHit(ActivityMonitor monitor, int minHits) {return mBase.checkMonitorHit(monitor, minHits);}@Overridepublic Activity waitForMonitor(ActivityMonitor monitor) {return mBase.waitForMonitor(monitor);}@Overridepublic Activity waitForMonitorWithTimeout(ActivityMonitor monitor, long timeOut) {return mBase.waitForMonitorWithTimeout(monitor, timeOut);}@Overridepublic void removeMonitor(ActivityMonitor monitor) {mBase.removeMonitor(monitor);}@Overridepublic boolean invokeMenuActionSync(Activity targetActivity, int id, int flag) {return mBase.invokeMenuActionSync(targetActivity, id, flag);}@Overridepublic boolean invokeContextMenuAction(Activity targetActivity, int id, int flag) {return mBase.invokeContextMenuAction(targetActivity, id, flag);}@Overridepublic void sendStringSync(String text) {mBase.sendStringSync(text);}@Overridepublic void sendKeySync(KeyEvent event) {mBase.sendKeySync(event);}@Overridepublic void sendKeyDownUpSync(int key) {mBase.sendKeyDownUpSync(key);}@Overridepublic void sendCharacterSync(int keyCode) {mBase.sendCharacterSync(keyCode);}@Overridepublic void sendPointerSync(MotionEvent event) {mBase.sendPointerSync(event);}@Overridepublic void sendTrackballEventSync(MotionEvent event) {mBase.sendTrackballEventSync(event);}@Overridepublic Application newApplication(ClassLoader cl, String className, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException {return mBase.newApplication(cl, className, context);}@Overridepublic void callApplicationOnCreate(Application app) {mBase.callApplicationOnCreate(app);}@Overridepublic Activity newActivity(Class<?> clazz, Context context, IBinder token, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance) throws InstantiationException, IllegalAccessException {return mBase.newActivity(clazz, context, token, application, intent, info, title, parent, id, lastNonConfigurationInstance);}@Overridepublic Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {return mBase.newActivity(cl, className, intent);}@Overridepublic void callActivityOnCreate(Activity activity, Bundle icicle) {mBase.callActivityOnCreate(activity, icicle);}@Overridepublic void callActivityOnDestroy(Activity activity) {mBase.callActivityOnDestroy(activity);}@Overridepublic void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) {mBase.callActivityOnRestoreInstanceState(activity, savedInstanceState);}@Overridepublic void callActivityOnPostCreate(Activity activity, Bundle icicle) {mBase.callActivityOnPostCreate(activity, icicle);}@Overridepublic void callActivityOnNewIntent(Activity activity, Intent intent) {mBase.callActivityOnNewIntent(activity, intent);}@Overridepublic void callActivityOnStart(Activity activity) {mBase.callActivityOnStart(activity);}@Overridepublic void callActivityOnRestart(Activity activity) {mBase.callActivityOnRestart(activity);}@Overridepublic void callActivityOnResume(Activity activity) {mBase.callActivityOnResume(activity);}@Overridepublic void callActivityOnStop(Activity activity) {mBase.callActivityOnStop(activity);}@Overridepublic void callActivityOnSaveInstanceState(Activity activity, Bundle outState) {mBase.callActivityOnSaveInstanceState(activity, outState);}@Overridepublic void callActivityOnPause(Activity activity) {mBase.callActivityOnPause(activity);}@TargetApi(Build.VERSION_CODES.CUPCAKE)@Overridepublic void callActivityOnUserLeaving(Activity activity) {mBase.callActivityOnUserLeaving(activity);}@Overridepublic void startAllocCounting() {mBase.startAllocCounting();}@Overridepublic void stopAllocCounting() {mBase.stopAllocCounting();}@Overridepublic Bundle getAllocCounts() {return mBase.getAllocCounts();}@Overridepublic Bundle getBinderCounts() {return mBase.getBinderCounts();}@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)@Overridepublic UiAutomation getUiAutomation() {return mBase.getUiAutomation();}@Overridepublic ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Fragment fragment, Intent intent, int requestCode) {doMyOperation();return mBase.execStartActivity(who, contextThread, token, fragment, intent, requestCode);}@Overridepublic ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Fragment fragment, Intent intent, int requestCode, Bundle options) {doMyOperation();return mBase.execStartActivity(who, contextThread, token, fragment, intent, requestCode, options);}@Overridepublic ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode) {doMyOperation();return mBase.execStartActivity(who, contextThread, token, target, intent, requestCode);}@Overridepublic ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {doMyOperation();return mBase.execStartActivity(who, contextThread, token, target, intent, requestCode, options);}public void doMyOperation() {}}
上面的doMyOperation是处理咱们业务逻辑的函数。
在Application里面进行初始化的类ActivityManager;
import android.app.Instrumentation;
import android.content.Context;
import android.os.Looper;public class ActivityManager {private static ActivityManager SINGLETON;private Context mContext;private ActivityManager(Context context) {if (!isMainThread()) {return;}mContext = context;DelegateActivityThread delegateActivityThread = DelegateActivityThread.getSingletion();Instrumentation originInstrumentation = delegateActivityThread.getInstrumentation();if (!(originInstrumentation instanceof DelegateInstrumentation)) {DelegateInstrumentation delegateInstrumentation = new DelegateInstrumentation(originInstrumentation);delegateActivityThread.setInstrumentation(delegateInstrumentation);}}public static void init(Context context) {if (null != SINGLETON) {return;}SINGLETON = new ActivityManager(context);}private boolean isMainThread() {return Looper.getMainLooper() == Looper.myLooper();}}
在Applicaiton进行初始化:
ActivityManager.init(this);
2.3 利用list自己管理的acitvity栈
无需多说。直接上代码。
import java.util.ArrayList;
import java.util.List;import android.app.Activity;/*** activity的管理栈,方便进行activity进行查找、处理** 眼下只适用于单线程** */
public class ActivityManager {private static ActivityManager SINGLETON = new ActivityManager();private static List<Activity> mAcitivityList = new ArrayList<Activity>();private ActivityManager() {if (null == mAcitivityList) {mAcitivityList = new ArrayList<Activity>();}mAcitivityList.clear();}public static ActivityManager getInstance() {if (null == SINGLETON) {SINGLETON = new ActivityManager();}return SINGLETON;}/*** activity入栈** */public void addActivity(Activity activity) {staticUserPage(activity);mAcitivityList.add(activity);}/*** activity出栈** */public void popActivity(Activity activity) {if (null == mAcitivityList) {return;}int total = mAcitivityList.size();if (total > 0) {mAcitivityList.remove(activity);}}/*** 获取栈顶的activity* */public Activity getTopActivity() {int total = mAcitivityList.size();if (total > 0) {Activity currentActivity = mAcitivityList.get(total - 1);return currentActivity;}return null;}/*** 清空全部的activity* */public void onExit() {if (null != mAcitivityList) {mAcitivityList.clear();}mAcitivityList = null;}}
最后
从一个LauncherActivity到APP进程的activity,Activity的栈,在其中的工作大致如下:
- Activity的启动一般可以通过startActivity()来进行,通过Instrumentation.execStartActivity(),最终会通知到AMS来进行Activity的启动。
- AMS通过binder线程获知了需要启动Activity的任务,让ActivityStarter去完成activity的启动。
- ActivityStarter在一连串的startActivity()调用过程中,为要启动的Activity创建了一个ActivityRecord。
- 最后进入到startActivityUnchecked(),根据Activity的启动模式与启动标识符的不同进行不同的处理。
- 如果这个Activity是新进程的Activity,将会通知AMS先进行APP进程的启动,APP进程的application启动完成后,会通知AMS,application初始完成,并将APP进程的binder代理交给AMS,AMS再通过ActivityStartSupervisor来realStartActivityLocked()->app.thread.scheduleLaunchActivity()来通知APP进程,可以启动activity了。
- 如果这个Activity是本进程发起的启动,那么就会根据发起者Activity的启动模式以及新Activity的启动模式综合判断,是复用Activity接着调用newIntent()呢,还是新建一个Activity,然后也进入到realStartActivityLocked()->app.thread.scheduleLaunchActivity()来启动新的Activity.
相关文章:
【我的Android开发】AMS中Activity栈管理
概述 Activity栈管理是AMS的另一个重要功能,栈管理又和Activity的启动模式和startActivity时所设置的Flag息息相关,Activity栈管理的主要处理逻辑是在ActivityStarter#startActivityUnchecked方法中,本文也会围绕着这个方法进进出出…...
C++源程序的构成————学习笔记
以下内容为,在学校上课时的课堂总结,偶尔我也会扩展一些内容内容仅供参考,欢迎大佬的指正简单的C程序#include <iostream> using namespace std;int main() {int x0;int y 0;cout << "请输入x,y的值"<<endl;cin…...
Spark Catalyst
Spark Catalyst逻辑计划逻辑计划解析逻辑计划优化Catalyst 规则优化过程物理计划Spark PlanJoinSelection生成 Physical PlanEnsureRequirementsSpark SQL 端到端的优化流程: Catalyst 优化器 : 包含逻辑优化/物理优化Tungsten : Spark SQL的优化过程 : 逻辑计划 …...
element 远程搜索下拉加载
created() { this.getList(); this.getGroupList(); }, directives: { /** 下拉框懒加载 */ “el-select-loadmore”: { bind(el, binding) { const SELECTWRAP_DOM el.querySelector( “.el-select-dropdown .el-select-dropdown__wrap” ); SELECTWRAP_DOM.addEventListener…...
空间复杂度与顺序表的具体实现操作(1)
最近更新的少,主要是因为参加了ACM竞赛空间复杂度空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用存储空间大小的量度 。空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量…...
【springmvc】Rest ful风格
RESTful 1、RESTful简介 REST:Representational State Transfer,表现层资源状态转移。 a>资源 资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一…...
华为OD机试真题Python实现【用户调度】真题+解题思路+代码(20222023)
用户调度 题目 在通信系统中有一个常见的问题是对用户进行不同策略的调度,会得到不同系统消耗的性能。 假设由N个待串行用户,每个用户可以使用A/B/C三种不同的调度策略。 不同的策略会消耗不同的系统资源,请你根据如下规则进行用户调度,并返回总的消耗资源数。 规则是: …...
JavaSE学习笔记总结day19
今日内容 二、线程安全的集合 三、死锁 四、线程通信 五、生产者消费者 六、线程池 零、 复习昨日 创建线程的几种方式 1) 继承 2) 实现Runnable 3) callable接口 Future接口 4) 线程池 启动线程的方法 start() 线程的几种状态 什么是线程不安全 setName getName Thread.curr…...
FreeSql使用
目的: 1.方库分表 2.主从分离 3.分布式事务 过程: 官网:指南 | FreeSql 官方文档 1.Startup.cs 添加配置(本地数据库MySql) ConfigureServices: Func<IServiceProvider, IFreeSql> fsql r >{IFreeSql …...
Hadoop集群搭建,基于3.3.4hadoop和centos8【图文教程-从零开始搭建Hadoop集群】,常见问题解决
Hadoop集群搭建,基于3.3.4hadoop和centos8【小白图文教程-从零开始搭建Hadoop集群】,常见问题解决Hadoop集群搭建,基于3.3.4hadoop1.虚拟机的创建1.1 第一台虚拟机的创建1.2 第一台虚拟机的安装1.3 第一台虚拟机的网络配置1.3.1 主机名和IP映…...
UE4 材质学习 (焚烧材质)
效果步骤随便从网上下载一张图片(地址:链接/链接),导入UE中新建一个材质函数这里命名为“E_Function”双击打开该材质函数,由于需要输出变发光和变透明两种效果,因此这里需要两个输出节点:分别命…...
【c++】STL常用算法2—常用查找算法
文章目录常用查找算法findfind_ifadjacent_findbinary_searchcountcount_if常用查找算法 算法简介: find//查找元素 find_if//按条件查找元素 adjacent_find//查找相邻重复元素 binary_search//二分查找法 count//统计元素个数 count_if//按条件统计元素个数find …...
史上最全最详细的Java架构师成长路径图,程序员必备
从新手码农到高级架构师,要经过几步?要多努力,才能成为为人倚重的技术专家?本文将为你带来一张程序员发展路径图,但你需要知道的是,天下没有普适的道理,具体问题还需具体分析,实践才…...
第五章 事务管理
1.事务概念 *什么是事务:事务是数据库操作最基本单元,逻辑上是一组操作,要么都成功,要么都失败 *事务的特性(ACID):原子性、隔离性、一致性、持久性 2.搭建事务操作环境 *模拟场景ÿ…...
Redis:主从同步
Redis:主从同步一. 概述二. 原理(1) 全量同步(2) 增量同步(3) 优化Redis主从集群三. 总结一. 概述 引入: Redis主从集群采用一个Master负责写,多个Slave负责读的方式(读多写少),那么如何让读取数据时多个从…...
Unity Animator.Play(stateName, layer, normalizedTime) 播放动画函数用法
原理 接口: public void Play(string stateName, int layer -1, float normalizedTime float.NegativeInfinity);参数含义stateName动画状态机的某个状态名字layer第几层的动画状态机,-1 表示播放第一个状态或者第一个哈希到的状态normalizedTime从s…...
python学习——【第三弹】
前言 上一篇文章 python学习——【第二弹】中学习了python中的运算符内容,这篇文章接着学习python中的流程控制语句。 流程控制指的是代码运行逻辑、分支走向、循环控制,是真正体现我们程序执行顺序的操作。流程控制一般分为顺序执行、条件判断和循环控…...
科技云报道:AI大模型背后,竟是惊人的碳排放
科技云报道原创。 自从ChatGPT这样的大型语言模型在全球引起轰动以来,很少有人注意到,训练和运行大型语言模型正在产生惊人的碳排放量。 虽然OpenAI和谷歌都没有说过他们各自产品的计算成本是多少,但据第三方研究人员分析,ChatG…...
如何根据实际需求选择合适的三维实景建模方式?
随着实景三维中国建设的推进,对三维实景建模的数字化需求大幅增加。由于三维实景建模具有采集速度快、计算精度高等建模优势,引起了各个行业的高度关注。三维实景建模是一种应用数码相机或者激光扫描仪对现有场景进行多角度环视拍摄,然后利用…...
CENTO OS上的网络安全工具(十八)ClickHouse及编程环境部署
这篇其实去年就写好了,孰知就在12月31日那一天打进决赛圈,一躺,二过年,三休假,四加班,居然到了三个月以后,才有机会将它发出来…… 一年也就四个季度不是,实在是光阴荏苒,…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
