Android复习(Android基础-四大组件)—— Activity

  • Activity作为四大组件之首,是使用最为频繁的一种组件,中文直接翻译为"活动",不过如果被翻译为"界面"会更好理解。正常情况,除了Window,Dialog和Toast , 我们能见到的界面只有Activity。

1. 进程模式

  • APP进程的级别,由其活跃的处于栈顶的组件的活动状态(比如生命周期)决定。
  • Activity的进程模式分为:前台进程、可见进程、Service进程、后台进程、空白进程
  1. 前台进程适用于目前操作所需的进程。在不同的情况下,进程可能因为其所包含的各种应用组件而被视为前台进程。以下任一条件成立,就是前台进程。
  • 当前进程Activity正在与用户进行交互。(已调用onResume)
  • 当前Service正在执行回调的代码 生命周期(Service.onCreate() , Service.onStart(), Service.onDestory())
  • 进程有一个正在运行的BroadcastReceiver(BroadcastReceiver.onReceive()正在执行)
  1. 可见进程:前台进程是一个Dialog;进程有一个Service,这个Service正在和一个可见的Activity绑定。
  • Activity在屏幕上对用户可见,但是失去了焦点,调用了onPause,暂时无法操作。
  • Service正在通过Service.startForeground()。
  • 实现特定功能的系统服务:动态壁纸,输入法服务。
  1. 服务进程:服务进程包含了一个已使用startService()方法启动的Service的进程。

  2. 后台进程:当Activity的onStop被调用,但是onDestroy并没有被调用

  3. 空白进程:当系统需要内存的时候,会暂时将背景进程清除,就成为了空白进程。

  • 进程优先级:前台进程 > 可见进程 > service进程 > 后台进程 > 空进程
  • 系统内存不足时,会删除优先级低的进程。

2. Activity的生命周期

  1. onCreate:表示Activity正在被创建,这是生命周期的第一个方法。可以做一些初始化的工作(加载界面布局资源,初始化Activity所需数据)
  2. onRestart:表示Activity正在被重新启动。一般情况下,当当前Activity从不可见更新为可见状态的时候,onRestart就会被调用
  3. onStart:表示Activity正在被启动,即将开始。这时Activity已经可见,但是没有出现在前台,还无法和用户交互了。
  4. onResume:表示Activity已经可见,并且出现在前台并开始活动。要注意这个和onStart的对比。onStart和onResume都表示Activity已经可见,但是onStart的时候Activity还在后台,onResume的时候Activity才显示到前台。
  5. onPause:表示Activity正在暂停,正常情况下,紧跟着onStop就会被调用。在特殊情况下,如果快速再回到当前Activity,那么onResume会被调用。(这种属于特殊情况,一般不会发生)。在这可以做一些存储数据,停止动画等操作,但是注意不能太耗时,不然会影响到新Activity的显示,onPause执行完,新的Activity的onResume才会执行。
  6. onStop:表示Activity即将停止,可以做一些稍微重量级的回收工作,同样不能太过耗时。
  7. onDestroy:表示Activity即将被销毁,这是生命周期中的最后一个回调。在这里,我们可以做一些回收工作和最终资源的释放。
    Android复习(Android基础-四大组件)—— Activity_第1张图片

2.1 典型情况下的生命周期

  1. 打开新的Activity或者切换到桌面的时候,生命周期的回调?
    在这里插入图片描述
  2. onStart 和 onResume、onPause 和 onStop实质有什么不同?
    在这里插入图片描述
  3. 假设当前Activity为A,如果这时用户打开了一个新的ActivityB,那么B的onResume和A的onPause哪个先执行呢?
    Android复习(Android基础-四大组件)—— Activity_第2张图片

2.2 异常情况下的生命周期

  • Activity除了受用户操作所导致的正常的生命周期方法调度,还有一些异常情况,比如当资源相关的系统配置发生改变以及系统内存不足时,Activity可能会被杀死。

2.2.1 情况1:资源相关的系统配置发生改变导致Activity被杀死并重新创建

  1. 首先要对系统的资源加载机制有一定的理解。把一张图片放在drawable目录后,可以通过Resources去获取这张图片。同时为了兼容不同的设备,我们可能还需要在其他一些目录放置不同的图片,比如drawable-mdpi、drawable-hdpi 等等。 这样,当应用程序启动的时候,系统就会根据设备去加载合适的Resources资源。比如说横屏手机和竖屏手机会**拿到两张不同的图片。
  2. 突然旋转屏幕,由于**系统配置发生了变化,在默认情况下,Activity就会被销毁并且重新创建,当然我们也可以组织重新创建我们的Activity
    Android复习(Android基础-四大组件)—— Activity_第3张图片

2.2.2 情况2:资源内存不足导致优先级低的Activity被杀死

  • 这种情况不好模拟,但是其数据存储和恢复过程和情况1完全一致。这里我们简单描述一下Activity的优先级情况。
  • 前台进程 > 可见进程 > 服务进程 > 后台进程 > 空进程
  1. 前台Activity——正在和用户进行交互的Activity,优先级最高
  2. 可见但非前台Activity——比如Activity弹出了一个对话框,导致Activity可见,但是位于后台无法和用户直接交互。
  3. 后台Activity——已被暂停的Activity,比如执行了onStop,优先级最低。

如果一个进程中没有四大组件在执行,那么这个进程很快就会被系统杀死。因此,一些后台工作不适合脱离四大组件而独自运行在后台中,这样进程很容易被杀死。比较好的方法是将后台工作放入Service中从而保证有一定的优先级,这样就不会轻易被杀死。

3. Activity的重建机制

  • 重建机制就是在onStop()后,调用onSaveInstanceState将Activity的某些状态保存下来。然后在重新创建onStart()之后调用onRestoreInstanceState()把这状态显示出来。
  1. onSaveInstanceState:这个方法将要保存的数据 以键值对形式 保存在Bundle对象中。并把保存下来的bundle对象作为参数同时传递给onRestoreInstanceState和onCreate,保存了当前Activity的视图结构。(API29之后一定会调用在onStop之后)
  2. onRestoreInstanceState:一旦被调用,Bundle参数一定有值,不用额外判空,但onCreate正常启动Bundle参数为null。

3.1 onSaveInstanceState & onRestoreInstanceState

  • 主要是 onSaveInstanceStateonRestoreInstanceState方法。
  • 系统为我们做了一定的恢复工作。当Activity在异常情况下需要重新创建时,系统会默认为我们保存当前Activity 的视图结构,并且在 Activity重启后为我们恢复这些数据。
  • 例如:文本框(TextView)中用户输入的数据、ListView滚动的位置等。这些View相关的状态系统都能够默认为我们恢复。
  • 针对某一特定的View系统能够为我们恢复哪些数据,我们可以查看View的源码。 和Activity一样,每个View都有onSaveInstanceStateonRestoreInstanceState。 看一下它们的具体实现,就可以知道系统自动为每个View恢复哪些数据。
  • 拿TextView来说,我们分析一下它保存了哪些数据。
@Override
public Parcelable onSaveInstanceState() {
    Parcelable superState = super.onSaveInstanceState();

    // Save state if we are forced to
    final boolean freezesText = getFreezesText();
    //文本框是否选中
    boolean hasSelection = false;
    int start = -1;
    int end = -1;
    //如果文本框不为空
    if (mText != null) {
        start = getSelectionStart();
        end = getSelectionEnd();
        if (start >= 0 || end >= 0) {
            // Or save state if there is a selection
            //表示选中
            hasSelection = true;
        }
    }

    if (freezesText || hasSelection) {
        SavedState ss = new SavedState(superState);

        if (freezesText) {
            if (mText instanceof Spanned) {
                final Spannable sp = new SpannableStringBuilder(mText);

                if (mEditor != null) {
                    removeMisspelledSpans(sp);
                    sp.removeSpan(mEditor.mSuggestionRangeSpan);
                }

                ss.text = sp;
            } else {
            //保存文本框上的数据
                ss.text = mText.toString();
            }
        }

        if (hasSelection) {
            // XXX Should also save the current scroll position!
            ss.selStart = start;
            ss.selEnd = end;
        }

        if (isFocused() && start >= 0 && end >= 0) {
            ss.frozenWithFocus = true;
        }

        ss.error = getError();

        if (mEditor != null) {
            ss.editorState = mEditor.saveInstanceState();
        }
        return ss;
    }

    return superState;
}

Android复习(Android基础-四大组件)—— Activity_第4张图片

3.2 Activity的configChanges属性

  • 上面分析了系统的数据存储和恢复机制,我们知道,当系统配置发生改变的时候,Activity会被重新创建,有没有办法不重新创建呢?系统配置中有很多内容,如果当某项内容发生改变后,我们不想系统重新创建Activity。可以给Activity指定configChanges属性。
android:configChanges="orientation"
  • 如果我们想指定多个值,可以用 " |" 连接起来。
    Android复习(Android基础-四大组件)—— Activity_第5张图片
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.activitytext" >

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.ActivityText" >
        <activity
            android:name=".MainActivity"
            //我们常用的只有locale,orientation,keyboardHidden这三个选项
            android:configChanges="orientation|screenSize"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

3.3 重建机制中保存和恢复数据

保存数据

  • Activity通过onSaveInstanceState()方法来保存状态,onSaveInstanceState()执行在onStop()后。
  • 然后Activity会委托Window去保存数据,接着Window再委托它上面的等级容器去保存数据。
  • 顶层容器是一个ViewGroup,一般来说可能是一个DecorView
  • 最后顶层容器再去通知它的子元素来保存数据,这样整个保存数据过程就完成了。
    Activity里面有两个数据结构专门保存状态
  1. View States保存View的状态
  2. Instance State存储View states 以及开发者在 onSaveInstanceState中手动保存的Activity成员变量。

恢复数据

  • 通过onRestoreInstanceState方法来恢复状态,在保存期间,会自动收集View Hieracht(视图层次)中每一个实现了状态保存和恢复方法的View状态,这些数据会在onRestoreInstanceState方法时回传给View,并且回传是根据view的id来逐一匹配。

注意事项

  1. 为了成功保存状态,要求在View内部实现保存和恢复的算法。(原生的View都有做到,自定义View需要自己来重写实现)
  2. 为了成功恢复状态,要给View赋对应的ID
  3. 如果需要保存Activity的成员变量,重写方法时,需要保留基类的实现。

4. Activity的启动模式

4.1 LaunchMode

Android复习(Android基础-四大组件)—— Activity_第6张图片

  1. standard(标准模式)
    Android复习(Android基础-四大组件)—— Activity_第7张图片
  2. singleTop(栈顶复用模式)
    Android复习(Android基础-四大组件)—— Activity_第8张图片
    在这里插入图片描述
  3. singleTask(栈内复用模式)
    Android复习(Android基础-四大组件)—— Activity_第9张图片

如果D所需的任务栈为S1,并且当前任务栈S1的情况为 ADBC,根据栈内复用的原则,此时D不会重新创建,系统会把D切换到栈而并调用onNewIntent 方法,同时由于singleTask 默认具有clearTop的效果,会导致栈内所有在D上面的 Activity全部出栈,于是最终S1中的情况为 AD。这一点比较特殊,在后面还会对此情况详细分析。

  1. singleInstance(单实例模式)
    Android复习(Android基础-四大组件)—— Activity_第10张图片
    Android复习(Android基础-四大组件)—— Activity_第11张图片
  • 设置启动模式
//通过在Intent中设置标志位来为Activity指定启动模式
Intent intent = new Intent();
intent.setClass(MainActivity.this,SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

Android复习(Android基础-四大组件)—— Activity_第12张图片

4.2 复用调用的方法 onNewIntent()

  1. 当ActivityA的LaunchModeSingleTop,并且ActivityA在栈顶,现在启动ActivityA,会调用onNewIntent()方法 。
  • 生命周期顺序为:onResume—>onPause—>onNewIntent—>onResume
  1. 当ActivityA的LaunchModeSingleInstance,SingleTask
  • 如果之前栈内没有它,就会去创建一个它的实例,也就是会调用 onCreate()→onStart()→onResume()
  • 如果之前栈内有它的实例存在的话,生命周期的调用变成了onNewIntent()→onRestart()→onStart()→onResume 。
  • 只对以上的情况,再次启动它们的时候才会调用,即只对startActivity有效。如果仅仅从后台切换到前台而不再次启动的情形,不会触发onNewIntent。
  1. 当ActivityA的LaunchMode为SingleTop,并且ActivityA在栈顶,现在启动ActivityA,会调用onNewIntent()方法 。
  • 生命周期顺序为:onResume—>onPause—>onNewIntent—>onResume
  1. 当ActivityA的LaunchMode为SingleInstance,SingleTask。
    • 如果之前栈内没有它,就会去创建一个它的实例,也就是会调用 onCreate()→onStart()→onResume()
    • 如果之前栈内有它的实例存在的话,生命周期的调用变成了onNewIntent()→onRestart()→onStart()→onResume 。
  • 只对以上的情况,再次启动它们的时候才会调用,即只对startActivity有效。如果仅仅从后台切换到前台而不再次启动的情形,不会触发onNewIntent。
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);         //设置新的intent
    int data = getIntent().getIntExtra("tanksu", 0);//此时的到的数据就是正确的了
}

5. Activity的TaskAffinity

  • 我们在上文中,多次提到了某个Activity所需的任务栈,什么是Activity所需要的任务栈?这要从一个参数说起:TaskAffinity [afineting] ,可以翻译为任务相关性。这个参数标识了一个Activity所需要的任务栈的名字
  • 如果没有显示指明taskAffinity,那么它的taskAffinity就等于Application指明的taskAffinity,如果Application也没有指明,那么该taskAffinity的值就等于包名
    Android复习(Android基础-四大组件)—— Activity_第13张图片
android:taskAffinty="com.ning.task1"
  • taskAffinity的作用就是指定想要的任务栈。
  1. 当启动模式设置为standard或singleTop时,taskAffinity是不起作用的。待启动的 Activity 会跟随源 Activity 的任务栈,即使你显式声明了不一样的taskAffinity。
  2. 当启动模式设置了 singleTask或者 singleInstance时,taskAffinity就会新建任务栈来存储待启动的 Activity 实例。

5.1 TaskAffinity和allowTaskReparenting结合

  • TaskAffinity属性主要是用于和allowTaskReparenting属性配对使用。
  • 另外,任务栈分为前台任务栈和后台任务栈,后台任务栈中的Activity位于暂停状态,用户可以通过切换将后台任务栈再调到前台。
  • allowTaskReparenting允许Activity在任务栈之间进行迁移。
    具体点来说,就是一个Activity现在是处于某个Task当中的,但是它与另外一个Task具有相同的affinity值。当另外这个任务切换到前台的时候,该Activity就可以转移到切换到前台的这个任务当中。allowTaskReparenting默认是继承至application中的allowTaskReparenting=false,不可以。
  1. 当一个应用A启动应用B的某个Activity之后,如果这个Activity的allowTaskReparenting属性为true的话。那么当应用B被启动后,此Activity会直接从应用A的任务栈转移到应用B的任务栈中。
  2. 具体一点说就是,比如有两个应用A和B,A启动了B的一个ActivityC,然后按Home 键回到桌面,然后再单击B的桌面图标,这个时候不是启动了B上的 主Activity,而是重新显示了已经被应用A启动的ActivityC。或者说,C从A的任务栈转移到了B的任务栈中。
    Android复习(Android基础-四大组件)—— Activity_第14张图片
    Android复习(Android基础-四大组件)—— Activity_第15张图片

5.2 使用FLAG_ACTIVITY_NEW_TASK标记

  • 单独的FLAG_ACTIVITY_NEW_TASK并不等于singleTask,它仅表示寻找Activity所需的任务栈压入。(即TaskAffinity指定的任务栈)
  • FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TOP 也不等价于启动模式singleTask
  • 当调用startActivity()方法来启动一个Activity时,默认是将它放入到当前的Task(任务)当中。但是,如果在Intent中加入了FLAG_ACTIVITY_NEW_TASK 的话,情况就会变的复杂起来。首先,系统会去检查这个 Activity要求的affinity是否与当前任务栈相同。
  1. 如果相同,把Activity放到当前的Task当中。
  2. 如果不同,先去检查是否有一个名字与该Activity的Affinity相同的Task。
    1. 如果有,这个Task被调到前台,同时将这个Activity显示到这个Task的顶端。
    2. 如果没有,系统将会尝试为这个Activity创建一个新的Task。需要注意的是,如果一个Activity在manifest文件中声明的启动模式是”singleTask”,那么他被启动的时候,行为模式会和前面提到的指定FLAG_ACTIVITY_NEW_TASK一样。

5.3 任务栈和返回栈

  • 任务栈和返回栈是独立存在的。
  1. 任务栈:Activity想要的任务栈,taskAffinity的作用就是指定想要的任务栈,是APP层面的一个东西。
  • 任务栈一般有前台任务栈后台任务栈之分。比如我们手机中打开了飞书,按下Home键之后打开了抖音,此时抖音就在前台任务栈,飞书就在后台任务栈。
  1. 返回栈:它是Activity层面的,用户页面的返回依赖的是返回栈,而不是任务栈。 一个返回栈中可能会包含来自不同任务栈的Activity,返回栈就是为了维护正确的回退栈关系。
    Android复习(Android基础-四大组件)—— Activity_第16张图片

6. Activity的FLAG

  • 标记位只能在Activity中设置
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  1. FLAG_ACTIVITY_NEW_TASK:这个标记位的作用是为Activity指定"singleTask"启动模式(近似于)。

    • 在不设置taskAffinity的情况下,单独设置FLAG_ACTIVITY_NEW_TASK并没有任何意义,不会创建新的任务栈,每次都会创建新的Activity实例,不会栈内复用。
    • 在一个新的任务栈中启动Activity。如果这个Activity想要的任务栈已经存在,并且其中已经运行着待启动的Activity,那么这个任务栈就会被带到前台,并回调onNewIntent。这个行为和singleTask一致。
  2. FLAG_ACTIVITY_SINGLE_TOP:这个标记位的作用是为Activity指定"singleTop"启动模式,其效果和在XML中指定该启动模式相同

  3. FLAG_ACTIVITY_CLEAR_TOP:具有此标记位的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。这个标记位一般会和singleTask启动模式一起出现。如果此时被启动的Activity采用standard模式启动,那么它连同它之上的Activity都要出栈,系统会创建新的Activity实例并放入栈顶

    • NEW_TASK+CLEAR_TOP != singleTask,因为在standard模式下启动,会把栈内本身的Activity也删除,所以不等于signleTask。
  4. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有这个标识位的Activity不会出现在历史Activity的列表中,当某些情况下我们用户通过历史列表回到我们的Activity的时候这个标记比较有用。他等同于在XML中指定Activity属性:

android:excludeFromRecents="true"
  1. FLAG_ACTIVITY_NO_HOSTORY:被指定的Activity在跳转到其他Activity后,将它从任务栈中移除。

7. IntentFilter

  • 我们知道启动Activity,一般有显示调用和隐式调用两种。显示调用需要明确指定被启动对象的组件信息,包括包名和类名。而隐式调用则不需要。
  • 这里简单介绍一下隐式调用,隐式调用需要Intent能够匹配目标组件的IntentFilter中所设置的过滤信息。
  1. 只有一个Intent同时匹配了action类别、category类别、data类别才算完全匹配,只有完全匹配才能启动目标Activity。
  2. 一个Activity可以有多个IntentFilter,一个Intent只要能匹配任何一组IntentFilter即可成功启动对应的Activity。
    Android复习(Android基础-四大组件)—— Activity_第17张图片

8. Activity的数据传输

  1. 使用Intent的putExtra传递(传递数据大小有限制,1M左右,根据Binder)
  2. SharedPreference进行数据传递
  3. 使用静态变量传递数据
  4. 使用Bundle对象
  5. 使用Activity销毁时传递数据(onActivityResult)
  6. 使用序列化对象Seriazable

9. Activity的finish()

  • finish()用于结束Activity进程,关闭Activity但不关闭栈。
  • 调用finish()方法后,先pause()当前Activity,会通过AMS的ApplicationThread.scheduleDestroyActivity方法,向ActivtyThread(主线程)发送一个H.DESTROY_ACTIVITY消息
  • 主线程会调用handleDestroyActivity来处理这个消息
  • 在通过层层调用,回调Activity的onDestroy方法。
  • 业务场景
  • 比如在订单列表A点击新建订单进入新建订单ActivityB中,点击保存后,跳转到订单详细C中。在C中我们点击返回键要求返回到A中。

10. 相关问题

10.1 进程模式相关问题

  1. 何谓进程模式?
    Android复习(Android基础-四大组件)—— Activity_第18张图片

10.2 生命周期相关问题

  1. onPause() 和 onStop()的区别?
    Android复习(Android基础-四大组件)—— Activity_第19张图片
  2. A启动B,然后B退回A,两者的生命周期变化?
    Android复习(Android基础-四大组件)—— Activity_第20张图片
  3. 为什么先Activity的onResume()执行,然后才是调用源Activity的onStop()方法呢?
    Android复习(Android基础-四大组件)—— Activity_第21张图片
  4. MainActivity跳转到DialogActivity(盖不住MainActivity)再跳转到secondActivity的生命周期?
    Android复习(Android基础-四大组件)—— Activity_第22张图片
  5. 从secondActivity返回到DialogActivity的生命周期?
    Android复习(Android基础-四大组件)—— Activity_第23张图片
  6. 弹出Dialog对Activity的生命周期有什么影响?
    Android复习(Android基础-四大组件)—— Activity_第24张图片

10.3 重建机制相关问题

  1. onSaveInstanceState方法调用的时机?
    Android复习(Android基础-四大组件)—— Activity_第25张图片
  2. 什么时候会发生重建?
    Android复习(Android基础-四大组件)—— Activity_第26张图片
  3. 为什么会有重建机制?
    在这里插入图片描述
  4. 优先级较低的Activity在内存不足的被回收后,怎样恢复到销毁前的状态?
    Android复习(Android基础-四大组件)—— Activity_第27张图片

10.4 启动模式相关问题

  1. Activity的启动模式,A是standard,B是singleInstance, A启动B,又启动A会有几个对象?
    在这里插入图片描述
  2. 启动模式和FLAG的区别?
    Android复习(Android基础-四大组件)—— Activity_第28张图片

10.5 Activity和application有什么区别?

  • Activity是UI界面的抽象,而application是应用程序的抽象。两者都是Context的子类。
  • 应用程序每次启动的时候,系统会为其创建一个application对象且只有一个(单例类),用来存储一些系统的信息,相当于一个容器。
  • 启动application时,系统会创建一个PID(进程ID),所有的Activity都在这个进程上运行,在application创建时会初始化一个全局变量,同一个应用的activity,都可以获取到这个变量。

10.6 onStop和onDestroy()回调延时及延时10S的问题?

为什么回调会延时

  • Activity调用流程:打开ActivityA -> 打开ActivityB -> 关闭ActivityB -> 回到ActivityA
  • 由于要关闭的Activity B或者要打开的Activity A 往主线程的MessageQueue中连续不断地post大量的msg。
  • 导致主线程一直在不断地进行消息循环处理 没有停歇。 因此APP不能向AMS发起IPC来进行ActivityB的销毁。
  • 所以finish ActivityB之后,onDestroy不会被及时回调。具体延时多久,要看主线程中堆积的msg什么时候被处理完。

延时10S

  • Android系统安排了一套流程来保证即使正常流程被阻断以后,ActivityB还是能被销毁。

  • 在关闭Activity B返回Activity A的时候,当AMS侧发起 IPC通知 APP侧的Activity A执行resume的时候,同时也会向AMS自己的主线程发送一个msg,该msg延时10s后执行。

  • 该msg的具体内容与 正常流程APP空闲时段需要执行的任务一致,当然也包括销毁B。

  • 这样Activity B的onDestroy方法也就在延时10s后调用执行。

  • 我们就该在写代码的时候,及时关闭、清理、移除不必要的主线程消息,并且尽可能的保证每个消息处理时间不要太长。

你可能感兴趣的:(Android面试,android)