Day11-activity

生命周期

  • onCreate();
  • onStart(); 可见,
  • onResume(); 可操作,在前台
  • onPause();
  • onStop();
  • onDestroy();
    • onRestart(); 返回前activity, 让他重新启动
  • 当Activity只执行onPause方法时(透明Activity),这时候如果App设置的targetVersion大于11则不会执行onSaveInstanceState方法

处理广播, 在onStart和onStop, onResume和onPause易触发并且可能只是暂时不能执行(被透明activity挡住)

跳转B前操作数据库, 并且B需要数据库, 在onPause,

onPause
onCreate--B
onStart--B
onResume--B
onStop

所以得确保B没出来的时候数据加载完毕, 但是如果B是半透明的, 则不会执行onStop
B返回A

onPause -B
onRestart
onStart
onResume
onStop --B
onDestroy --B

黑屏/按home/按任务列表生命周期:

onPause
onStop
onRestart
onStart
onResume

横竖屏切换生命周期,此时开 alertDialog.Builder 格式的dialog, 生命周期不影响

onPause
onStop
onDestroy
onCreate
onStart
onResume

Activity 是否运行

(activity == null || activity.isDestroyed() || activity.isFinishing())
原因: isFinishing 根据 mFinished, mFinished只在finish时改变, 无法确定finish一定会执行, 且 finish 执行后, 无法保证立马走到 onDestroy

public boolean isFinishing() {
       return mFinished;
   }

根据Google源码中的Dialer应用的源码Link, 添加 isDestroyed 判断

@Override
    protected void onPostExecute(Void result) {
        final Activity activity = progressDialog.getOwnerActivity();

        if (activity == null || activity.isDestroyed() || activity.isFinishing()) {
            return;
        }

        if (progressDialog != null && progressDialog.isShowing()) {
            progressDialog.dismiss();
        }
    }

onUserLeaveHint 和 onUserInteraction

  • onUserLeaveHint
    当用户的操作导致activity即将进入后台的时候, 此方法会被调用, 但在来电时不被调用
  • onUserInteraction
    activity 在分发各种事件之前会调用, 但启动另一个activity会被调用两次, 一次是 activity 补货到事件时, 一次是调用activity.onUserLeaveHint之前会调用onUserInteraction

临时状态保存 -- onSaveInstanceState 和 onRestoreInstanceState

是用来临时存储数据, 长期的还是需要数据库

前提是view必须有ID

保存状态

  • onSaveInstanceState(Bundle savedInstanceState)
    执行在 onStop 之前

    • 只有back不会触发
      ===================
    • home触发
    • 任务列表键会触发
    • 跳转 Activity 会触发
    • 旋转屏幕会触发
    • 黑屏会触发

    Activity 创建时有一个 bundle 对象, 该对象是上次被系统销毁时在 onSaveInstanceState 保存的参数,
    ```java
    static final String STATE_SCORE = "playerScore";
    static final String STATE_LEVEL = "playerLevel";

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        // Save the user's current game state
        savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
        savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
    
        // Always call the superclass so it can save the view hierarchy state
        super.onSaveInstanceState(savedInstanceState);
    }
    ```
    **注意,自定义的部分在super之前**
    

    使用onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState), 则onSaveInstanceState不会被调用

  • onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState)
    API21 后添加的属性, 能在关机重启后拥有数据恢复的功能, 需要在 manifest 中给 acticity 添加属性

    android:persistableMode="persistAcrossReboots"
    

    • 重写 onCreate(Bundle savedInstanceState, PersistableBundle persistentState),
    • 并不用普通的 onCreate 和 onSaveInstanceState

    重写此onSaveInstanceState会导致 onSaveInstanceState 不执行

恢复状态

  • onRestoreInstanceState
    执行在 onStart 之后, 只有有savedInstanceState时才会调用, 无需判空

    public void onRestoreInstanceState(Bundle savedInstanceState) {
        // Always call the superclass so it can restore the view hierarchy
        super.onRestoreInstanceState(savedInstanceState);
    
        // Restore state members from saved instance
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    }
    
  • onCreate中恢复, 需判空

     @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState); // Always call the superclass first
    
        // Check whether we're recreating a previously destroyed instance
        if (savedInstanceState != null) {
            // Restore value of members from saved state
            mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
            mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
        } else {
            // Probably initialize members with default values for a new instance
        }
        ...
    }
    

透明activity(继承AppCompatActivity)

  1. 透明color
<?xml version="1.0" encoding="UTF-8"?>  
<resources>  

    <color name="transparent">#0000</color>  

</resources>  
  1. style设置background, style的parent不加会报错: You need to use a Theme.AppCompat theme (or descendant) with this activity.
<style name="myTransParent" parent="Theme.AppCompat.Light.NoActionBar">
    <item name ="android:windowBackground">@color/transParent</item>
    <item name ="android:windowNoTitle">true</item>
    <item name ="android:windowIsTranslucent">true</item>
    <item name ="android:colorBackgroundCacheHint">@null</item>
    <item name ="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
    <item name ="android:statusBarColor">@color/transParent</item>
</style>
  1. 清单设置 activity 的 theme
android:theme="@style/myTransparent"

ActivityA 打开透明ActivityB

onPause
onCreate --B
onStart --B
onResume --B

透明ActivityB返回ActivityA

onPause --B
onResume
onStop --B
onDestroy --B

启动模式

A组件运行在A应用, A组件调用系统的照相组件, 虽然不在一个应用, 但是安卓运行跨应用组件, 虽然两者不在一个进程, 但是可以通过Task来实现, Task可以理解为实现一个功能而负责管理所有用到的 Activity实例的栈

standard

默认, 先进后出

singleTop

栈顶不重复, 唯一
如果要开启的 activity 已经在栈顶存在, 就不会创建新的实例, 而去调用 onNewIntent().
如果栈顶没有, 则创建新的实例
比如 通知栏的通知点击打开activity, 用singleTop可以避免重复创建
快速点击不能只依赖这个, 不靠谱, 第一个栈实例可能还没入栈,就创建了第二个然后和第一个一起入栈了, 建议对快速点击另作判断

singleTask

栈内不重复, 干掉头上的其他activity
如果要开启的activity已经在栈内存在, 就不会创建新的栈和新的实例, 而去调用 onNewIntent(), 并且清空它上面的所有activity
比如 主界面, 保证主界面上面没有activity

singleInstance

单一实例, 单一栈, 栈里只有自己
谨慎使用
如果要开启的activity已经在进程中存在, 就不会创建新的实例, 而去调用 onNewIntent().
比如 呼叫来电界面

指定启动模式

  • manifest指定
<activity android:name=".SecondActivity"
            android:launchMode="singleTask"/>
  • 代码指定
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
               //通过 intent.addFlags 设置
               intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
               startActivity(intent);
  • 对比

    • 代码指定优先于 manifest
    • manifest无法设定singleInstance模式
  • Intent.FLAG_:

    • FLAG_ACTIVITY_NEW_TASK = 开新栈, 多用在service和Application, 因为他俩没有栈
    • FLAG_ACTIVITY_SINGLE_TOP = singleTop
    • FLAG_ACTIVITY_CLEAR_TOP = singleTask
    • FLAG_ACTIVITY_NO_HISTORY 启动完其他的后, 自己消失
  • StartActivityForResult 5.0 分水岭

    • 5.0 之前可能不回调
    • 5.0 后全部有回调
  • adb 查看任务栈

    1. 运行

      adb shell dumpsys activity
      
    2. 搜 Recent tasks 查看已经存在的任务栈

      Recent tasks:
         * Recent #0: TaskRecord{5bd8fdd #749 A=com.taskaffinity U=0 sz=1}
         * Recent #1: TaskRecord{a972e43 #748 A=com.activityfull U=0 sz=1}
         * Recent #2: TaskRecord{7a2180c #664 I=com.android.launcher3/.Launcher U=0 sz=1}
      
    3. 搜 Running activities (most recent first)查看activity

      Running activities (most recent first):
         TaskRecord{25d22cd #684 A=com.activityfull U=0 sz=2}
           Run #1: ActivityRecord{8e55d0b u0 com.activityfull/.SecondActivity t684}
           Run #0: ActivityRecord{d26b857 u0 com.activityfull/.MainActivity t684}
      

    栈的唯一标号是#682, sz 表示栈内有几个组件, 栈顶的是 SecondActivity,

    1. Recent tasks查看手机程序的任务栈, != 应用数(一个应用可能包含多个栈), 更不是进程数
      任务栈数 = 手机任务列表里显示的数量 + com.android.launcher + com.android.systemui
      ACTIVITY MANAGER RECENT TASKS (dumpsys activity recents)
        Recent tasks:
        * Recent #0: TaskRecord{42a273f #682 A=com.activityfull U=0 sz=1}
        * Recent #1: TaskRecord{7a2180c #664 I=com.android.launcher3/.Launcher U=0 sz=1}
        * Recent #2: TaskRecord{8a01555 #667 A=com.android.systemui U=0 sz=1}
      
android:exported="true"

允许其他app打开这个activity

taskAffinity + allowTaskReparenting

  • taskAffinity
    设置activity进入指定完整栈名的栈,一般和singleTask一起使用
    • Application中设置(推荐activity设置), 不设定则默认包名, 设定了内部activity和Application一致
    • Activity中设置, 如果指定的任务栈不存在, 那么会自己新开一个指定包名的任务栈
  • allowTaskReparenting
    是否依附与开启这个activity的任务栈
  • 举例:
    • APP1内有activity1, activity2; APP2内有activity3和activity4, 当APP1 的 activity1 在 APP1 内打开这个 APP2 的 activity4 时,

      <activity android:name=".FourActivity"
               android:exported="true"
               />
      

      a. 只有 APP1 的任务栈打开, 存放的是 activity1 和 activity4;
      b. 按home, 点开 APP1 看到的是 activity4, 按back, 看到activity1, 按back, 退出
      c. 按home, 点开 APP2 看到的是 activity3, 按back, 退出

      <activity android:name=".FourActivity"
                 android:exported="true"
                 android:allowTaskReparenting="true"
                 />
      

      a. 只有 APP1 的任务栈打开, 存放的是 activity1 和 activity4;
      b. 按home, 点开 APP1 看到的是 activity1,
      c. 按home, 点开 APP2 看到的是 activity4, 按back, 看到activity3, 按back, 退出

      <activity android:name=".FourActivity"
                 android:exported="true"
                 android:allowTaskReparenting="true"
                 android:launchMode="singleTask"
                 />
      

      a. APP1 任务栈存放 activity1, APP2 的任务栈存放activity4
      b. 按home, 点开APP1 看到的是 activity1
      c. 按home, 点开APP2 看到的是 activity4, 按back退出

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,271评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,725评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,252评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,634评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,549评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,985评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,471评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,128评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,257评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,233评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,235评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,940评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,528评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,623评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,858评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,245评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,790评论 2 339

推荐阅读更多精彩内容