Android面试基础android基础知识学习笔记

android 四大组件之一Activity

2018-08-15  本文已影响28人  liys_android

一. Activity生命周期

activity生命周期图
简单说明一下Activity每个生命周期函数:
onCreate():

表示Activity正在被创建,这是Activity生命周期的第一个方法

onStart():

表示Activity正在被启动,这时候的Activity已经被创建好了,完全过了准备阶段,但是没有出现在前台,需要执行onResume()函数才可以进入到前台与用户进行交互。

onResume():

表示Activitiy已经可见了,并且Activity处于运行状态,也就是Activity不止出现在了前台,而且还可以让用户点击,滑动等等操作与它进行交互。

onPause(): (注意)

onPause被触发,并不是Activity的主界面处于被其它东西不完全覆盖状态,而是被某个其它Activity不完全覆盖。

onStop():

表示Activity即将停止,我们程序员应该在此函数中做一些不那么耗时的轻量级回收操作。

onRestart():

表示Activity正在重新启动。一般情况下,一个存在于后台不可见的Activity变为可见状态,都会去执行onRestart()函数,然后会继续执行onStart()函数,onResume()函数出现在前台并且处于运行状态。

onDestory():

表示Activity要被销毁了。这是Activity生命中的最后一个阶段,我们可以在onDestory()函数中做一些回收工作和资源释放等,比如:广播接收器的注销等。

Activity常见几种状态的生命周期分析

Activity启动–>onCreate()–>onStart()–>onResume()

点击home键回到桌面–>onPause()–>onStop()

再次回到原Activity时–>onRestart()–>onStart()–>onResume()

退出当前Activity时–>onPause()–>onStop()–>onDestroy()

二 android 任务栈

参考地址:http://blog.csdn.net/javazejian/article/details/52071885

1. android任务栈特点

(1) android任务栈又称为Task,它是一个栈结构,具有后进先出的特性,用于存放我们的Activity组件。

(2) 我们每次打开一个新的Activity或者退出当前Activity都会在一个称为任务栈的结构中添加或者减少一个Activity组件,因此一个任务栈包含了一个activity的集合, android系统可以通过Task有序地管理每个activity,并决定哪个Activity与用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。

(3) 在我们退出应用程序时,必须把所有的任务栈中所有的activity清除出栈时,任务栈才会被销毁。当然任务栈也可以移动到后台, 并且保留了每一个activity的状态. 可以有序的给用户列出它们的任务, 同时也不会丢失Activity的状态信息。

(4) 需要注意的是,一个App中可能不止一个任务栈,某些特殊情况下,单独一个Actvity可以独享一个任务栈。还有一点就是一个Task中的Actvity可以来自不同的App,同一个App的Activity也可能不在一个Task中。

2. taskAffinity属性,一个APP引用多个任务栈(下面singTask特殊场景用到)

(1). TaskAffinity 参数标识着Activity所需要的任务栈的名称,默认情况下,一个应用中所有Activity所需要的任务, 栈名称都为该应用的包名。

(1). TaskAffinity 属性一般跟singleTask模式或者跟allowTaskReparenting属性结合使用,在其他情况下没有实际意义。

(3). TaskAffinity属性的值不能与当前应用包名相同,否则其值跟作废没两样。

使用方法:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
              package="comzejian.myapplication">
<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

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

    <activity android:name=".ActivityA"
                android:launchMode="singleTask"
                android:taskAffinity="com.zejian.singleTask.affinity"/>
</application>
</manifest>

我们可以通过singleTask与android:taskAffinity属性相结合的方式来指定我们Activity所需要的栈名称,使相应的Activity存在于不同的栈中,图解如下:


任务栈.png

3. allowTaskReparenting属性
(1) 主要作用是activity的迁移,即从一个task迁移到另一个task,这个迁移跟activity的taskAffinity有关。

(2) 使用方法:

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

(3) 使用过程图解:


allowTaskReparenting.png

说明:如果allowTaskReparenting值为false时,ActivityC并不会直接从A应用的任务栈迁移到B应用的任务栈,而是B应用直接重新创建了ActivityC的实例

注意:allowTaskReparenting仅限于singleTop和standard模式

例:TaskAffinity与singleTask应用场景
  假如现在有这么一个需求,我们的客户端app正处于后台运行,此时我们因为某些需要,让微信调用自己客户端app的某个页面,用户完成相关操作后,我们不做任何处理,按下回退或者当前Activity.finish(),页面都会停留在自己的客户端(此时我们的app回退栈不为空),这显然不符合逻辑的,用户体验也是相当出问题的。我们要求是,回退必须回到微信客户端,而且要保证不杀死自己的app.这时候我们的处理方案就是,设置当前被调起Activity的属性为:

LaunchMode=""SingleTask" taskAffinity="com.tencent.mm"

4.清空任务栈
清空任务栈的方法,在一般情况下我们只需要在<activity>标签中指明相应的属性值即可。
(1) android:clearTaskOnLaunch .
这个属性用来标记是否从task清除除根Activity之外的所有的Activity,“true”表示清除,“false”表示不清除,默认为“false”。
注意的,这个属性只对任务栈内的root Activity起作用,任务栈内其他的Activity都会被忽略。
例如:一个应用的Activity A,B,C。 A跳转B,B跳转C,点击HOME,再在桌面点击图标,结果只能看到A,如下图所示:

clearTaskOnLaunch.png

情况1 当:ActivityA的clearTaskOnLaunch = true的时候,只要ActivityA没有finish(),其它的Activity设置clearTaskOnLaunch属性全部没用。假如ActivityA.finish(),任务栈最底部Activity设置clearTaskOnLaunch有效。

情况2 当:ActivityA的clearTaskOnLaunch = false的时候,无论ActivityA有没有被finish(),其它的Activity设置clearTaskOnLaunch属性全部没用。

如下图: clearTaskOnLaunch2.png

clearTaskOnLaunch2.png

(2)android:finishOnTaskLaunch
这个属性是作用在自己身上(把自己移除任务栈,不影响别的Activity).
把ActivityB的android:finishOnTaskLaunch = true时,点击HOME,再在桌面点击图标进入APP,此时任务栈里已经没有ActivityB了。如下图:

finishOnTaskLaunch.png

(3)android:alwaysRetainTaskState
alwaysRetainTaskState实际上是给了当前Activity所在的任务栈一个“免死金牌”,如果当前Activity的android:alwaysRetainTaskState设置为true时,那么该Activity所在的任务栈将不会受到任何清理命令的影响,一直保持当前任务栈的状态。

默认任务栈的缺点:
(1)每开启一次页面都会在任务栈中添加一个Activity,而只有任务栈中的Activity全部清除出栈时,任务栈被销毁,程序才会退出,这样就造成了用,户体验差, 需要点击多次返回才可以把程序退出了。
(2)每开启一次页面都会在任务栈中添加一个Activity还会造成数据冗余, 重复数据太多, 会导致内存溢出的问题(OOM)。

为了解决任务栈的缺点,我们引入了启动模式。

三 Activity启动模式

参考地址:http://blog.csdn.net/javazejian/article/details/52071885

Activity的4种启动模式(standard,singleTop,singTask和singleInstance)

1. Standard 模式
又称为标准模式,也是系统的默认模式(可以不指定),在这样模式下,每启动一个Activity都会重新创建一个Activity的新实例,并且将其加入任务栈中,而且完全不会去考虑这个实例是否已存在。我们通过图解来更清晰地了解Standard模式:

Standard.png
通过上图,我们可以发现,这个过程中,在standard模式下启动了三次MainActivity后,都生成了不同的新实例,并添加到同一个任务栈中。这个时候Activity的onCreate、onStart、onResume方法都会被调用。

2. singleTop 模式
又称栈顶复用模式,顾名思义,在这种模式下,如果有新的Activity已经存在任务栈的栈顶,那么此Activity就不会被重新创建新实例,而是复用已存在任务栈栈顶的Activity。这里重点是位于栈顶,才会被复用,如果新的Activity的实例已存在但没有位于栈顶,那么新的Activity仍然会被重建。需要注意的是,Activity的onNewIntent方法会被调用,方法原型如下:

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
}

通过此方法的参数,我们可以获取当前请求的相关信息,此时Activity的onCreate、onStart方法不会被调用,因为Activity并没有被重建。同理,我们通过图解来协助我们更清晰的理解singleTop模式:


singleTop1.png

从上图我们可以看出,当需要新创建的MainActivity位于栈顶时,MainActivity并没有重新创建。下面我们再来看看新创建的MainActivity没有位于栈顶的情况。

singleTop2.png

从图中可以看出,当我们再次启动MainActivity时,由于MainActivity位于栈中,所以系统直接将其置于栈顶,并移除其上方的所有Activity。当然如果所需要的MainActivity不存在栈中,则会创建新的Activity并添加到栈中。singleTask 模式比较适合应用的主界面activity(频繁使用的主架构),可以用于主架构的activity,(如新闻,侧滑,应用主界面等)里面有好多fragment,一般不会被销毁,它可以跳转其它的activity 界面再回主架构界面,此时其他Activity就销毁了。当然singTask还有一些比较特殊的场景这个我们后面会一一通过情景代码分析。

3. singleTask 模式
又称为栈内复用模式。这是一种单例模式,与singTop点类似,只不过singTop是检测栈顶元素是否有需要启动的Activity,而singTask则是检测整个栈中是否存在当前需要启动的Activity,如果存在就直接将该Activity置于栈顶,并将该Activity以上的Activity都从任务栈中移出销毁,同时也会回调onNewIntent方法。情况如下图:

singleTask.png
从图中可以看出,当我们再次启动MainActivity时,由于MainActivity位于栈中,所以系统直接将其置于栈顶,并移除其上方的所有Activity。当然如果所需要的MainActivity不存在栈中,则会创建新的Activity并添加到栈中。singleTask 模式比较适合应用的主界面activity(频繁使用的主架构),可以用于主架构的activity,(如新闻,侧滑,应用主界面等)里面有好多fragment,一般不会被销毁,它可以跳转其它的activity 界面再回主架构界面,此时其他Activity就销毁了。

singleTask 特殊场景
现在我们假设有如下两个Task栈,分别为前台任务栈和后台任务栈,如下图:

singleTask特殊场景.png

情况一:
此时我们先启动CD,然后再启动AB,再有B启动D,此时后台任务栈便会被切换到前台,而且这个时候整个后退列表就变成了ABCD,请注意我们这里强调的是后退列表,而非栈合并。因此当用户点击back键时,列表中的Activity会依次按DCBA顺序出栈,如下图所示:

singleTask特殊场景1.png

情况二:
如果上面B请求启动C,那么又会是什么情况呢?其实这个时候任务栈退出列表变成C->B->A,其实原因很简单,singleTask模式的ActivityC切换到栈顶时会导致在他之上的栈内的Activity出栈,如下图:

singleTask特殊场景2.png

4. singleInstance 模式
在singleInstance模式下,该Activity在整个android系统内存中有且只有一个实例,而且该实例单独尊享一个Task。换句话说,A应用需要启动的MainActivity 是singleInstance模式,当A启动后,系统会为它创建一个新的任务栈,然后A单独在这个新的任务栈中,如果此时B应用也要激活MainActivity,由于栈内复用的特性,则不会重新创建,而是两个应用共享一个Activity的实例。如下图所示:

singleInstance.png
从图中我们可以看到最终AB应用都共享一个singleInstance模式的MainActivity,也没有去重新创建。到此Activity的四种启动模式我们都介绍完了,下面我们接着来聊聊怎么使用启动模式。
Activity启动模式的使用方式

1.通过AndroidMenifest.xml文件为Activity指定启动模式,代码如下:

<activity android:name=".ActivityC"           android:launchMode="singleTask" />

2.通过在Intent中设置标志位(addFlags方法)来为Activity指定启动模式,示例代码如下:

Intent intent = new Intent();
intent.setClass(ActivityB.this,ActivityA.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

Flags对应的值
Intent.FLAG_ACTIVITY_SINGLE_TOP
  该标志位表示使用singleTop模式来启动一个Activity,与在清单文件指定android:launchMode="singleTop"效果相同。

Intent.FLAG_ACTIVITY_CLEAR_TOP
该标志位表示使用singleTask模式来启动一个Activity,与在清单文件指定android: launchMode="singleTask"效果相同。

Intent.FLAG_ACTIVITY_NO_HISTORY
  使用该模式来启动Activity,当该Activity启动其他Activity后,该Activity就被销毁了,不会保留在任务栈中。如A-B,B中以这种模式启动C,C再启动D,则任务栈只有ABD。

Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
  使用该标识位启动的Activity不添加到最近应用列表,也即我们从最近应用里面查看不到我们启动的这个activity。与属性android:excludeFromRecents="true"效果相同。

四. scheme跳转协议(简单的应用)

Android中的scheme是一种页面内跳转协议,通过自定义scheme协议,可以非常方便的跳转到app中的各个页面,通过scheme协议,服务器可以定制化告诉app跳转到哪个页面,可以通过通知栏消息定制化跳转页面,可以通过H5页面跳转到相应页面等等。

目前主要用于以下几种场景:

(1) 服务器下发跳转路径,客户端根据服务器下发跳转路径跳转相应的页面;

(2) H5页面点击锚点,根据锚点具体跳转路径App端跳转具体的页面;

(3) App端收到服务器端下发的PUSH通知栏消息,根据消息的点击跳转路径跳转相关页面

scheme协议跳转的一个完整实例

第一步:在Mainefest配置文件中配置需要用scheme协议跳转的Activity

        <!-- scheme协议 -->
        <activity
            android:name=".SchemeActivity"
            android:label="@string/app_name">
            <!-- 要想在别的App上能成功调起App,必须添加intent过滤器 -->
                <!-- 协议部分,随便设置 -->
                <intent-filter>
                    <!--协议部分,随便设置-->
                    <data android:scheme="scheme" android:host="mtime" android:path="/goodsDetail" />
                    <!--下面这几行也必须得设置-->
                    <category android:name="android.intent.category.DEFAULT"/>
                    <action android:name="android.intent.action.VIEW"/>
                    <category android:name="android.intent.category.BROWSABLE"/>
                </intent-filter>
        </activity>

第二步:模拟从网络中获取scheme协议的url,跳转到指定Activity

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
                 // (1)在manifest配置文件中配置了scheme参数
                 // (2)网络端获取url
                 // (3)跳转
                String url = "scheme://mtime/goodsDetail?goodsId=10011002";
                Intent intent = new Intent(Intent.ACTION_VIEW,Uri.parse(url));
                startActivity(intent);
    }
}

第三步:获取scheme协议参数

public class SchemeActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scheme);
       //获取参数
        Uri data = getIntent().getData();
        Log.i(TAG, "host = " + data.getHost() + " path = " + data.getPath() + " query = " + data.getQuery());
        String param = data.getQueryParameter("goodsId");
    }
}
上一篇下一篇

猜你喜欢

热点阅读