Activity任务栈:Activity的活动序列
standard:标准栈
singleTop:顶复用栈
singleTask:对象唯一栈
singleInstance:单独实例栈
1.standard: 标准栈
当启动一个Activity,创建该Activity的新实例。入栈处于栈顶
测试:Activity1、2皆为standard
依次打开Activity1、2、2、1、2
E/TASK_ID: Activity1 Task id is 89
E/TASK_ID: Activity2 Task id is 89
E/TASK_ID: Activity2 Task id is 89
E/TASK_ID: Activity1 Task id is 89
E/TASK_ID: Activity2 Task id is 89
依次返回
E/TASK_ID: Activity2 销毁
E/TASK_ID: Activity1 销毁
E/TASK_ID: Activity2 销毁
E/TASK_ID: Activity2 销毁
E/TASK_ID: Activity1 销毁
2:singleTop模式:顶复用栈
在启动活动时若栈顶已经是该Activity,则直接使用它,不创建实例
测试:Activity1为standard, Activity2 为singleTop
依次打开Activity1、2、2、1、2
E/TASK_ID: Activity1 Task id is 82
E/TASK_ID: Activity2 Task id is 82
E/TASK_ID: Activity1 Task id is 82
E/TASK_ID: Activity2 Task id is 82
依次返回
E/TASK_ID: Activity2 销毁
E/TASK_ID: Activity1 销毁
E/TASK_ID: Activity2 销毁
E/TASK_ID: Activity1 销毁
3:singleTask模式:对象唯一栈
整个栈中没有相同的实例,两次相同实例之间的Activity会被杀死(够霸道,我喜欢)
测试:Activity1为standard, Activity2 为singleTask
依次打开Activity1、2、2、1、2
E/TASK_ID: Activity1 Task id is 94
E/TASK_ID: Activity2 Task id is 94
E/TASK_ID: Activity1 Task id is 94
E/TASK_ID: Activity1 销毁
依次返回
E/TASK_ID: Activity2 销毁
E/TASK_ID: Activity1 销毁
4:singleInstance 单独实例栈
启用一个新的活动栈来管理这个活动(够豪,够任性)
测试:Activity1为standard, Activity2 singleInstance
依次打开Activity1、2、2、1、2
E/TASK_ID: Activity1 Task id is 115
E/TASK_ID: Activity2 Task id is 116
E/TASK_ID: Activity1 Task id is 115
依次返回
E/TASK_ID: Activity2 销毁
E/TASK_ID: Activity1 销毁
E/TASK_ID: Activity1 销毁
注意一点:
singleTask模式和singleTop模式时,非第一次启动,不会调用onCreate方法!
但会走onNewIntent方法
四、Activity的跳转动画
这里只是简单的四个平移动画,需要的更酷炫的效果道理是一样的
关于动画的更多知识,这里不废话了,可详见:Android 动画 Animator 家族使用指南
默认 | 修改 |
---|---|
) |
|
|
1.代码实现Activity跳转
/**
- 作者:张风捷特烈
- 时间:2019/1/20/020:18:25
- 邮箱:1981462002@qq.com
- 说明:红色Activity
*/
class RedActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val view = View(this)
view.setBackgroundColor(Color.RED)
title = “RedActivity”
view.setOnClickListener { v ->
startActivity(Intent(this, BlueActivity::class.java))
overridePendingTransition(R.anim.open_enter, R.anim.open_exit);
}
setContentView(view)
}
override fun onBackPressed() {
super.onBackPressed()
overridePendingTransition(R.anim.open_enter, R.anim.open_exit);
}
}
/**
- 作者:张风捷特烈
- 时间:2019/1/20/020:18:25
- 邮箱:1981462002@qq.com
- 说明:绿色Activity
*/
class BlueActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val view = View(this)
view.setBackgroundColor(Color.BLUE)
title = “BlueActivity”
view.setOnClickListener { v ->
startActivity(Intent(this, RedActivity::class.java))
overridePendingTransition(R.anim.close_enter, R.anim.close_exit)
}
setContentView(view)
}
override fun onBackPressed() {
super.onBackPressed()//右移入—右移出
overridePendingTransition(R.anim.close_enter, R.anim.close_exit)
}
}
2.跳转动画
---->[open_enter.xml]----------------------
<?xml version="1.0" encoding="utf-8"?>
---->[open_exit.xml]----------------------
<?xml version="1.0" encoding="utf-8"?>
---->[close_enter.xml----------------------
<?xml version="1.0" encoding="utf-8"?>
---->[close_exit.xml]----------------------
<?xml version="1.0" encoding="utf-8"?>
这样就可以了
3.另外
还可以配置动画的style
用起来比在代码里方便些
五、Acticity的启动源码分析
一直想总结一下Activity的启动流程(),这里从Activity的生命周期入手
本文所讲述的启动流程主要是ActivityThread的H在接收到消息之后,即handleMessage
至于消息如何传递过来的将在跨进程通信篇讲述
1.谁是幕后黑手?
翻一下源码可以看出Context只是一个抽象类,定义了很多抽象方法
而ContextWrapper作为实现类将所有的工作甩手给了一个mBase的Context成员变量
ContextThemeWrapper寥寥百行代码,也不会是幕后黑手,现在台面上只有mBase
2.Activity是如何创建的?
相信应该没有人去
new Activity()
,framework 层是如何创建Activity的实例呢?
---->[ActivityThread]-------
final H mH = new H();
---->[ActivityThread$H#handleMessage]-------
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {//启动Activity
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “activityStart”);
//r:记录Activity的一些描述信息
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
//通过r来获取包信息
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
//开启的核心方法(划重点)
handleLaunchActivity(r, null, “LAUNCH_ACTIVITY”);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
---->[ActivityThread#handleLaunchActivity]-------
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
//在这里返回来Activity的对象
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations®;
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
//略…
}
---->[ActivityThread#performLaunchActivity]-------
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//略…
ComponentName component = r.intent.getComponent();
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//此处可见是mInstrumentation创建的Activity
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
//略…
return activity;
}
---->[Instrumentation#newActivity]-------
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
//通过类加载器生成Activity实例
return (Activity)cl.loadClass(className).newInstance();
}
3.Application实例化及onCreate()方法调用
实现移到刚才创建Activity的
performLaunchActivity
方法
---->[ActivityThread#performLaunchActivity]-------
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//略…
ComponentName component = r.intent.getComponent();
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
//略…
try {
//创建Activity之后通过ActivityClientRecord的packageInfo对象的makeApplication
//来创建Application,packageInfo是一个LoadedApk类的对象
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
//略…
}
---->[LoadedApk#makeApplication]-------
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
Application app = null;
//略…
try {
java.lang.ClassLoader cl = getClassLoader();
//略…
//这里ContextImpl出场了
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
//这里通过mInstrumentation的newApplication方法创建Application对象
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
//将创建的Application设置到appContext上
appContext.setOuterContext(app);
}
//略…
//mActivityThread将当前app加入mAllApplications列表中
mActivityThread.mAllApplications.add(app);
mApplication = app;
if (instrumentation != null) {
try {
//这时调用application的OnCreate方法
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!instrumentation.onException(app, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
- ": " + e.toString(), e);
}
}
}
return app;
}
---->[Instrumentation#newApplication]-------
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
//也是通过反射获取Application实例
return newApplication(cl.loadClass(className), context);
}
---->[Instrumentation#callApplicationOnCreate]-------
public void callApplicationOnCreate(Application app) {
app.onCreate();//直接调用onCreate onCreate
}
4.Activity的Context的创建及onCreate()方法的调用
---->[ActivityThread#performLaunchActivity]-------
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
//Activity的一些配置信息
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
- r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
//将Activity和window绑定
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
---->[ActivityThread#createBaseContextForActivity]-------
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
//略…
//看这里appContext是ContextImpl类对象,Activity的Context幕后黑手出现了
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.token, displayId, r.overrideConfig);
appContext.setOuterContext(activity);
Context baseContext = appContext;
final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
// For debugging purposes, if the activity’s package name contains the value of
// the “debug.use-second-display” system property as a substring, then show
// its content on a secondary display if there is one.
String pkgName = SystemProperties.get(“debug.second-display.pkg”);
if (pkgName != null && !pkgName.isEmpty()
&& r.packageInfo.mPackageName.contains(pkgName)) {
for (int id : dm.getDisplayIds()) {
if (id != Display.DEFAULT_DISPLAY) {
Display display =
dm.getCompatibleDisplay(id, appContext.getDisplayAdjustments(id));
baseContext = appContext.createDisplayContext(display);
break;
}
}
}
return baseContext;
}
---->[ContextImpl#createActivityContext]-------
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, int displayId,
Configuration overrideConfiguration) {
if (packageInfo == null) throw new IllegalArgumentException(“packageInfo”);
return new ContextImpl(null, mainThread, packageInfo, activityToken, null, 0,
null, overrideConfiguration, displayId);
}
---->[Instrumentation#callActivityOnCreate]-------
public void callActivityOnCreate(Activity activity, Bundle icicle,
PersistableBundle persistentState) {
prePerformCreate(activity);
activity.performCreate(icicle, persistentState);
postPerformCreate(activity);
}
---->[Activity#performCreate]-------
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
restoreHasCurrentPermissionRequest(icicle);
onCreate(icicle, persistentState);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
---->[Activity#attach]-----------------
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
attachBaseContext(context);
mFragments.attachHost(null /parent/);
//这里的Window实现类是PhoneWindow
mWindow = new PhoneWindow(this, window);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
if (voiceInteractor != null) {
if (lastNonConfigurationInstances != null) {
mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
} else {
mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
Looper.myLooper());
}
}
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
本文在开源项目:Android开发不会这些?如何面试拿高薪! 中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…
知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-ZLNnbUya-1711370727964)]
[外链图片转存中…(img-pAfDqL9X-1711370727964)]
[外链图片转存中…(img-2UDkCXVK-1711370727965)]
[外链图片转存中…(img-AKQDXu3u-1711370727965)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-DOaDqzoi-1711370727965)]
本文在开源项目:Android开发不会这些?如何面试拿高薪! 中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…