摸鱼日记09/15 day6 Android基础---Activity

概览

在这里插入图片描述

1. Activity

Activity是整个Android app直接与用户进行交互的核心组件,是用户交互的第一接口,提供了一个用户完成指令的窗口,当开发者创建Activity之后,通过调用setContentView(View)方法来给Activity指定一个显示界面,并以此为基础给用户一个交互接口。系统采用Activity栈的方式来管理Activity

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

Activity的形态

Activity的最大特点是用有多种形态,他可以在此种切换,由此来控制自己的声明周期。

  1. Activity/Running
    Activity位于Activity栈的最顶层,可见并与用户进行交互,并且获取了焦点
  2. Pause
    当Activity失去焦点,被一个全新的非全屏的Activity或者一个透明的Activity或者一个透明的Activity放置在栈顶时,Activity就转化为Paused状态,但只是失去了与用户交互的能力,所有的状态信息、成员变量都还保持着,只有在系统内存极低的情况下才会被回收。此时Activity仍然是可见的。
  3. Stopped
    与paused状态相似,stopped状态的Activity是完全不可见的,但是内存里面的成员变量,状态信息仍然存在,但是也没有被销毁
  4. Killed
    当Activity被系统回收掉或者Activity从来没有被创建过,Acticity就处于Killed形态,由此可见,用户的不同动作,会让Activity四种形态来回切换,Activity可被控制生,但是无法被控制合适dead

生命周期

在这里插入图片描述
在Activity中只有三个状态是稳定的,而其他状态都是过渡状态,很快就会结束。

正常情况下的生命周期:
Activity启动-》onCreate-》onStart()-》onResume()
此时点击home键回桌面-》onPause()-》onStop()
再次回到原Activity-》onRestart()-》onStart()-》onResume()
退出当前的Activity-》onPause-》onStop-》onDestory()

接下来是生命周期的详解:

  1. 启动一个Activity,通常是Intent来完成。启动一个Activity首先要执行的回调函数时onCreate()通常是在代码中需要在此函数中绑定布局,绑定控件,初始化数据等一些列操作。
@Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        final AppCompatDelegate delegate = getDelegate();
        delegate.installViewFactory();
        delegate.onCreate(savedInstanceState);
        super.onCreate(savedInstanceState);
    }
  1. 接下来是执行Activity的onStart函数,执行之后Activity已经可见,但是还没有出现在前台,无法与用户进行交互。这个时候Activity已经在后台准备好了,就差执行onResume函数回到前台。
    @Override
 protected void onStart() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
        mCalled = true;

        mFragments.doLoaderStart();

        dispatchActivityStarted();

        if (mAutoFillResetNeeded) {
            getAutofillManager().onVisibleForAutofill();
        }
    }
  1. 执行Activity的onResume函数,执行之后Activity可见,且还会出现在前台,可以与用户进行交互
    @Override
  protected void onResume() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
        dispatchActivityResumed();
        mActivityTransitionState.onResume(this);
        enableAutofillCompatibilityIfNeeded();
        if (mAutoFillResetNeeded) {
            if (!mAutoFillIgnoreFirstResumePause) {
                View focus = getCurrentFocus();
                if (focus != null && focus.canNotifyAutofillEnterExitEvent()) {
                    // TODO: in Activity killed/recreated case, i.e. SessionLifecycleTest#
                    // testDatasetVisibleWhileAutofilledAppIsLifecycled: the View's initial
                    // window visibility after recreation is INVISIBLE in onResume() and next frame
                    // ViewRootImpl.performTraversals() changes window visibility to VISIBLE.
                    // So we cannot call View.notifyEnterOrExited() which will do nothing
                    // when View.isVisibleToUser() is false.
                    getAutofillManager().notifyViewEntered(focus);
                }
            }
        }

        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_RESUME);

        mCalled = true;
    }

  1. 如果处于运行的Activity即将执行onPause函数,此时可能有两种情况:
    启动了一个新的Activity
    返回了上一个Activity
    可以理解为当需要其他的Activity时,当前的Activity必须先把手头的工作停下来,再把当前页面的界面空间交给下一个需要界面的Activity,而onPause可以看做一个转接的过程,因为屏幕空间只有那么一个,每次只允许有一个Activity出现在前台进行工作。通常情况下onPause函数不会被单独执行,执行完onPause函数不会被单独执行,执行完的onPause方法会继续执行onStop方法,执行完onStop方法才真正意味着当前Activity已经退出了前台。存在于后台
  protected void onPause() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);
        dispatchActivityPaused();
        if (mAutoFillResetNeeded) {
            if (!mAutoFillIgnoreFirstResumePause) {
                if (DEBUG_LIFECYCLE) Slog.v(TAG, "autofill notifyViewExited " + this);
                View focus = getCurrentFocus();
                if (focus != null && focus.canNotifyAutofillEnterExitEvent()) {
                    getAutofillManager().notifyViewExited(focus);
                }
            } else {
                // reset after first pause()
                if (DEBUG_LIFECYCLE) Slog.v(TAG, "autofill got first pause " + this);
                mAutoFillIgnoreFirstResumePause = false;
            }
        }

        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_PAUSE);
        mCalled = true;
    }

  1. 当前的Activity即将执行onStop哈数,当次Activity要从前台切换至后台时才会执行。
protected void onStop() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
        if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
        mActivityTransitionState.onStop();
        dispatchActivityStopped();
        mTranslucentCallback = null;
        mCalled = true;

        if (mAutoFillResetNeeded) {
            getAutofillManager().onInvisibleForAutofill();
        }

        if (isFinishing()) {
            if (mAutoFillResetNeeded) {
                getAutofillManager().onActivityFinishing();
            } else if (mIntent != null
                    && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
                // Activity was launched when user tapped a link in the Autofill Save UI - since
                // user launched another activity, the Save UI should not be restored when this
                // activity is finished.
                getAutofillManager().onPendingSaveUi(AutofillManager.PENDING_UI_OPERATION_CANCEL,
                        mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN));
            }
        }
        mEnterAnimationComplete = false;
    }
  1. 当前Activity即将执行onDestory函数,代表着这个Activity即将进入生命的终结点,这是Activity生命周期的最后一次回调生命周期,我们可以在onDestory函数中做一些回收工作和资源释放操作,比如广播寄售期的注销工作。执行完onDestory方法的Activity接下来面对的是GC回收,宣告生命终结。

异常情况下的生命周期

在这里插入图片描述
情况1: 资源相关的系统配置发生改变导致Activity被杀死并重建
情况2:内存资源不足导致低优先级的Activity被杀死
当Activity发生意外情况的时候,如配置系统发生改变,Activity会被销毁,其中onPause,onStop,onDestory函数均会被调用,同时由于Activity是在异常情况下被终止的,系统会调用onSaveInstance来保存当前Activity状态。调用onSaveInstanceState的时机总会发生在onStop之前,至于会不会调用时机发生在onPause之前,是不确定的。当Activity被重建,系统回调用onSaveInstanceState,并将onSaveInstance方法所保存的Bundle对象作为参数传递给onRestoreInstanceSate和onCreate方法。从时序上来看,onRestoreinstancestate理论上是应该发生在Start之后没因为oncreate是开始绘制,而start状态代表绘制完成,此时填入数据才能让Activity实现恢复工作。

关于保存和恢复View
当Activity别意外终止,Activity会调用onSaveInstanceState去保存数据,然后Activity会委托Window去保存数据,接着window再委托它内部的顶级容器去保存数据,这个容器就是ViewGroup,然后顶层容器在分发通知它的子元素来保存数据,这样数据的保存过程就完事了。

关于Activity的优先级:
优先级最高:与用户正在交互的Activity,就是前台Activity
优先级中等:可见但是非前台的Activity,比如一个弹出对话框的Activity,可见但是非前台运行
优先级最低:完全存在于后台的的Activity,比如执行了onStop

Android任务栈简介

一个Android应用程序功能通常被拆分为多个Activity,而且各个Activity之间通过Intent进行连接,而Android系统,通过栈结构来保存整个App的Activity,栈底的元素是整个任务栈的发起者。一个合理的任务调度栈不仅是性能的保证,更是提供性能的基础。
当一个App启动的时候,如果当前环境中不存在该App的任务栈,那么系统会创建一个任务栈。此后,这个App启动的Activity都将在这个任务栈中被管理,这个栈也被称为一个Task,即表示若干个Activity的集合,他们组合成一个Task。一个Task中的Activity可以来自不同的app,同一个App的Activity也可能不在同一个Task中。
关于栈结构,是一种先进后出的线性表。根据Activity在当前栈结构的位置,来决定该Activity的状态。正常情况下的Android任务栈,当一个Activity启动了另一个Activity时,新启动的Activity会置于任务栈的顶端,并处于活动状态,而启动它的Activity虽然功成身退,但依然保留在任务栈里,当用户调用返回时,系统会溢出顶部的Activity,让后面的Activity里恢复活动状态,当然也有例外,通过在AndroidMainfest中设置android:launchMode来设置或者通过Intent的flag来设置。

Android的启动模式

首先是问题:

  1. Activity为什么需要启动模式?
    当启动一个Activity后,这个Activity的实例就会被放在任务栈中,当点击返回键的时候,位于任务栈的顶端的Activity就会被清理出去,当任务栈中不存在任何Activity实例后,,系统就会去回收这个任务栈,也就是任务退出了,假如没有启动模式,每次启动一个Activity就会把对应的要启动的Activity的实例放在任务栈中,假如这个Activity被频繁启动,或者A启动B,B启动A,A在启动B,在这叠千层饼,白白的浪费资源。所以有了启动模式。
  2. Activity的启动模式有哪些?
    Activity共有四种模式:standard,singleTop,singleTask和singleInstance

系统默认的启动模式Standart:

标准模式,这也是系统的默认模式,每次启动一Activity都会重新创建一个新的实例,不管这个实例是否存在。被创建的实例的生命周期符合典型情况下的Activity的生命周期。在这种模式下,谁启动了这个Activity,那么这个Activity就在谁的任务栈中。比如A启动了B(B也是标准模式),那么B就会进入到A所运行的任务栈中。当我们用ApplicationContex去启东standard的Activity就会报错,因为standard模式的Activity默认会进入到启动它的所属的任务栈中,但是由于非Activity类型的Context如Application并没有所谓的任务栈,所以这就会出现错误。解决方法是为启动的Activity指定的FLAG_ACTIVITY_NEW_TASK标记位,这样启动的时候会为它创建一个新的任务栈,这个时候启动Activity实际上是以singleTask模式启动的
在这里插入图片描述

singleTop启动模式

在这种模式下,如果新的Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法的参数我们可以取出当前请求的信息。这个Activity的onCreat,onStart不会被系统调用,因为并没有发生改变如果新的Activity已经存在但不是位于栈顶,那么新的Activity仍然会重新重建。
例如:假设目前栈内的情况为ABCD,其中ABCD为四个Actvity,A位于栈底,D位于栈顶,这个时候假设要启动D,如果D的启动模式为singleTop,那么栈内的情况仍为ABCD,如果D的启动模式standart,那么由于D被重新创建,导致栈内为ABCDD
在这里插入图片描述
如果指定启动的Activity为singleTop模式,那么在启动时,系统会判断当前栈顶的Activity是不是要启动的Activity,如果是则不创建新的Activity而是直接引用这个Activity。这种模式常用于接收消息后显示页面,例如QQ接收到消息后弹出Activity。这种启动模式通常适用于接收到消息后显示的界面,例如QQ接受到消息后弹出的Activity,如果一次来10条消息,总不可能一次性弹出10个Activity。

singleTask

singleTask模式与singeTop模式类似,只是singleTop是检测栈顶元素是否是需要启动的Activity,而singleTask是检测整个Activity栈中是否存在当前需要启动的Activity,如果存在则将此Activity以上的Activity都销毁。并将Activity以上的Activity都销毁。这里是指在同一个App中启动这个singleTask的Activity,如果是其他程序来以singleTask模式来启动这个Activity,那么它将创建一个新的任务栈,如果启动模式的singleTask的Activity已经在后台的一个任务栈中了,那么启动后,这个后台的任务栈将一起被切换到前台。
当Activity2启动ActivityY(启动模式为singleTask)时,它所在的Task都被切换到前台,且范围键返回时,也会返回Activity所在的Task的Acticity。
在这里插入图片描述

使用这个模式创建的Activity不是在新的任务栈中被打开,就是将已打开的Activity切换到前台,所以这种启动模式通常可以用来退出整个应用,将主Activity设置为singleTask模式,然后再要退出的Activity中转到主Activity,从而将主Activity纸上的Activity都清除,然后重写Acitivity的onNewIntent方法,在方法中加入Finish,最后一个Activity结束掉。
本质上,栈内复用是一种单例模式,在这种模式下,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新建立实例,和singleTop一样,系统也会回调其onNewIntent。
几个例子:

  1. 当前任务栈S1的情况为ABC,这个时候ActivityD以singleTask模式请求启动,其所需的任务栈为S2,由于S2和D的实例均不存在,所以系统会先创建任务栈S2,在将D投入到S2中。,如果所需的任务栈是S1,那么会直接投入到S1中
  2. 如果所需的任务栈是S1,但是S1中是ADBC,根据栈内复用的原理,D不会重新创建,系统会切换到栈顶并调用其onNewIntent方法,同时由于singleTask默认具有clearTop的效果,会导致栈内所有的D上面的Activity全部出栈,最终S1中的情况时AD.

singleInstance模式

加强化的singleTask模式,除了具有singleTask模式所具有的的所有的特性外,还加强了此模式下的Activity只能单独位于一个任务栈中,如果ActivityA是singleInstance模式,当A启动时,系统会为它创建一个新的任务栈。由于栈内复用的特性,后续的请求不会创建新的Activity,除非这个单独的任务栈被系统销毁。

  1. 以singleInstance模式启动的Activity具有全局唯一性,即整个系统中只会存在一个这样的实例
  2. 以singleInstance模式启动的Activity在整个系统中是单例的,如果启动这样的Activity,那么会把它的所在的任务栈调度到前台,重用这个实例
  3. 以singleInstance模式启动的Activity具有独占性,即它会独自占用一个任务栈,被他开启的的任何Activity都会运行在其他任务中
  4. 被singleInstance模式的Activity开启的其他Activity,能够在新的任务栈启动,但不一定开启新的任务栈,也可能存在一个已有的任务栈中开启

IntentFlag 启动

系统通过两种方式来设置一个Activity的启动模式,接下来是Intent的Flag模式来设置一个Activity的启动模式

  1. Intent.FLAG_ACTIVITY_NEW_TASK
  2. Intent.FLAG_ACTIVITY_SINGLE_TOP
  3. Intent.FLAG_ACTIVITY_CLER_TOP
  4. Intent.FLAG_ACTIVITY_NO_HISTORY

清空任务栈

系统提供了清空任务栈的方法来实现将一个任务Task全部清除。通常情况下可以在AndroidMainifest文件中的activity标签中使用以下几种属性来清理任务栈

  1. clearTaskLauch
    顾名思义,就是在每次返回该Activity时,都将该Activity之上的所有Activity都清除,通过这个属性,可以让这个Task每次在初始化的时候,都只有一个Activity。
  2. finishOnTaskLaunch
    finnishOnTaskLaunch属性与clearTaskOnLaunch属性类似,只不过clearTaskOnLauch作用在别人身上,而finishOnTaskLauch作用在自己身上,通过这个属性,当离开这个Activity所在的Task,那么用户再返回时,该Activity就会被finish
  3. alwaysRetainTaskState
    alwaysRetainTaskSatate属性给Task一道免死禁片,如果Activity的这个属性设置为True,那么该Acitity所在的Task将不接受任何清理命令,直至保持当前Task状态。

Activity组件之间的通信

  1. Activity->Activity之间的通信
    方法一:采用Intent/Bundle,最基本的方式
    方式二:采用类静态变量的方式,用于少量数据通信。
    方式三:全局变量,创建一个类,定义一批静态变量,Activity之间通信通过访问这个类变量来实现

  2. Activity->Service之间的通信
    方式一:绑定服务的方式:利用ServiceConnection这个接口
    方式二:Intent,在启动和停止Service时所调用的方法都需要传入一个Intent实例对象,通过这个Intent对象,与Service进行通信。
    方式三:CallBack+Handler,监听服务的进程变化

  3. Activity->Fragment
    方式一:Bundle在创建Fragment实例时,调用setArguments将一个Bundle对象传递给Fragment,然后在Fragment中先去判断是否和当前Activity绑定上,如果绑定上,就可以拿出Bundle中的数据
    方式二:直接进行方法调用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
cd C:\Program Files\FlightGear fgfs --fg-root=C:\Program Files\FlightGear\data --aircraft=ufo --in-air --fdm=null --telnet=5501 --telnet=5502 --telnet=5503 --disable-ai-traffic --disable-real-weather-fetch --disable-random-objects --disable-terrasync --disable-clouds --disable-sound --disable-panel --disable-hud --disable-specular-highlight --timeofday=noon --prop:/sim/rendering/multi-sample-buffers=1 --prop:/sim/rendering/multi-samples=2 --prop:/sim/rendering/draw-mask-clouds=false --prop:/sim/rendering/draw-mask-terrain=true --prop:/sim/rendering/draw-mask-objects=true --prop:/sim/rendering/draw-mask-lights=true --prop:/sim/rendering/draw-mask-internal=true --prop:/sim/rendering/draw-mask-cockpit=true --prop:/sim/rendering/draw-mask-effects=true --prop:/sim/rendering/draw-mask-overlay=true --prop:/sim/rendering/draw-mask-world=true --prop:/sim/rendering/draw-mask-panel=true --prop:/sim/rendering/draw-mask-vr=true --prop:/sim/rendering/draw-mask-2d=true --prop:/sim/rendering/draw-mask-3d=true --prop:/sim/rendering/draw-mask-sky=true --prop:/sim/rendering/draw-mask-shadows=true --prop:/sim/rendering/draw-mask-cabin=true --prop:/sim/rendering/draw-mask-weather=true --prop:/sim/rendering/draw-mask-stereo=true --prop:/sim/rendering/draw-mask-internal-cockpit=true --prop:/sim/rendering/draw-mask-internal-windows=true --prop:/sim/rendering/draw-mask-internal-instruments=true --prop:/sim/rendering/draw-mask-internal-overlay=true --prop:/sim/rendering/draw-mask-internal-effects=true --prop:/sim/rendering/draw-mask-internal-lights=true --prop:/sim/rendering/draw-mask-internal-world=true --prop:/sim/rendering/draw-mask-internal-panel=true --prop:/sim/rendering/draw-mask-internal-3d=true --prop:/sim/rendering/draw-mask-internal-sky=true --prop:/sim/rendering/draw-mask-internal-cabin=true --prop:/sim/rendering/draw-mask-internal-weather=true --prop:/sim/rendering/draw-mask-internal-stereo=true --prop:/sim/rendering/draw-mask-internal-shadow=true --prop:/sim/rendering/draw-mask-internal-stall=true --prop:/sim/rendering/draw-mask-internal-aoa=true --prop:/sim/rendering/draw-mask-internal-thermal=false --prop:/sim/rendering/draw-mask-internal-ice=false --prop:/sim/rendering/draw-mask-internal-glass=true --prop:/sim/rendering/draw-mask-internal-dead=true --prop:/sim/rendering/draw-mask-internal-reflection=true --telnet=127.0.0.1:5501 --disable-panel --disable-hud --disable-specular-highlight --disable-clouds --disable-sound --timeofday=noon --enable-hud-3d=no --enable-hud-2d=yes --enable-panel=no --enable-sound=no程序显示错误
最新发布
05-10

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值