安卓艺术开发探索-----学习笔记(生命周期和启动模式)

Activity的声明周期和启动模式

这里写图片描述

正常情况下,activity会经历上图的过程:

onCreate():表示activity正在被创建,这是生命周期的第一个方法。在这个方法中,我们可以做一些初始化,比如setContentView去加载界面资源,初始化activity所需要的数据

onStart():表示activity正在被启动,这个时候activity已经可见了,但是还没有出现在前台,所以不能和用户进行交互。这个可以理解为,activity已经可见了,但是我们看不见

onResume():表示activity已经可见了,并且出现在前台并开始活动。
和onStart()的区别:onStart和onResume都表示activity已经可见了,但是onStart的时候,activity在后台,onResume()的时候,activity才显示在前台

onPause():表示activity正在停止,正常情况下,onStop会紧接着被调用。在特殊情况下,如果在这个时候,重新返回activity,那么又会调用onResume。如果是新的activity被启动,那么要圆activity的onPause执行完后,新activity的activity得出onResume()才会执行,所以一般不要在onPause()中执行太耗时的操作

onStop():表示activity即将停止,可以做一些回收工作,注意不要太耗时

onDestroy():表示activity即将被销毁。这是activity生命周期的最后一个回调,我们可以在这里做一些资源的回收和释放

onRestart():表示Activity正在被重启。一般情况下,当activity从不可见变成可见的时候,onRestart就会被调用。这种一般出现在用户用Home键切换到桌面或者打开一个新的activity

注意:
当用户打卡新的activity或者切换到桌面的时候。回调是onPause->onStop,但是如果新的activity采用了透明主题,那么当前的activity不会回调onStop
当用户按back键回退的时候,回调是onPause->onStop->onDestroy
onStart和onStop是从activity是否可见来回调的
onResume和onPause是从activity是否位于前台来回调的

我们来看注意中的第一句话:
我做了一个小测试,我现在有两个activity,一个MainActivity和SecondActivity,MAinActivity中声明一个Button,用来转到第二个activity
两个activity都是用了透明主题

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((Button)findViewById(R.id.btn)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(
                        new Intent(MainActivity.this,SecondActivity.class));
            }
        });

    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d("1111","onStart");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d("1111","onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d("1111","onStop");
    }

}

这里写图片描述

这是它的UI

第二个Activity没有指定背景
当我跳转到第二个activity的时候,就这样了:
这里写图片描述

第一个activity还是可以看见,这是因为我采用的是透明主题,当我跳转到第二个activity的时候,一个activity没有执行onStop方法,只执行了onPause方法,导致我的第一个activity是可见的,但是出于后台,不可操作


异常情况下的声明周期

1,资源相关的系统配置发生改变导致Activity被杀死并重建

关于资源加载机制可以参考:
http://blog.csdn.net/thesingularityisnear/article/details/51581311
简单说明一下,拿简单的图片来说,当我们放一张图片在drawable目录下,我们就可以用Resources去获取这张照片。同时,我们为了兼容不同的设备,我们可能会在不同的目录下放置不同的图片,比如drawable—mdpi,drawable-hdpi,drawable-land等。这样,当应用程序启动的时候。系统会根据当前设备的情况去加载合适的Resources资源。
比如,当activity处于竖屏状态的时候,如果突然选择屏幕,由于系统配置发生了变化,在默认情况下,activity会销毁然后重建,我们也可以阻止系统重建activity
这里写图片描述

注意:onSaveInstanceState方法的调用是在onStop之前,它和onPause没有顺序关系,可以在onPause之前也可以在之后,这个方法只会在activity被异常终止的情况下才会调用
从时序上说,onRestoreInstanceState的调用时机在onStart之后

关于保存和恢复View层次结构,系统dev工作流程是这样的:

每一个View都有onSaveInstanceState和onRestoreInstanceState这两个方法。
首先Activity被意外终止的时候,会调用onSaveInstanceState去保存数据,然后activity再去委托window去保存数据,接着window再委托它上面最顶层的容器去保存数据,顶层容器是一个ViewGroup,一般来说是一个DecorView。最后顶层元素再去通知它的子元素去保存数据

2,资源内存不足导致低优先级的activity被杀死
activity按照优先级从高到低,可以分为如下三种:
1)前台activity—–正在和用户交互的activity,优先级最高
2)可见但非前台activity,比如activity中弹出一个对话框,导致activity可见但是位于后台无法和用户直接交互
3)后台activity,已经被暂停的activity,比如执行了stop,优先级最低

当系统内存不足的时候,会按照上面的优先级去杀死activity所在的进程。
如果一个进程中没有四大组件,那么这个进程很容易被杀死,所以一些后台工作可以放在Service中


如果我们不想Activity重建,那么我们可以给activity指定configChanges属性。比如不想activity在屏幕旋转的时候重新创建,就可以给configChanges属性添加orientation这个值
如果想使用多个值,可以用|来连接
这里写图片描述

当给configChanges设置属性的时候,如果activity关于这个属性的系统配置发生改变后,activity不会重新创建,所以也不会调用onSaveInstanceState和onRestoreSaveInstanceState方法,而是会去调用onConfigurationChanged方法,这个时候我们就可以在里面做一些操作。

Activity的启动模式
  1. standard:标准模式,也是系统的模式模式。每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。在这种模式下,谁启动了这个Activity,那么这个Acivity锯运行在启动它的那个Activity所在的栈中。
  2. singleTop:栈顶复用模式。在这种模式下,如果新Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法的参数我们可以取出当前请求的信息。 需要注意的是,这个Activity的onCreate,onStart不会被系统调用,因为它并没有发生改变。
    如果新的Activity实例已存在但不是位于栈顶,那么新Activity仍然会重新创建。
  3. singleTask:栈内复用模式。这是一种单实例模式。这这种模式下,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,和singleTop一样,系统也会回调其onNewIntent。如果要启动的Activity在此栈中有,就会将此Activity上面的其他Activity出栈,让要显示的位于栈顶
  4. singleInstance:单实例模式。这是一种加强的singleTask模式,它除了具有singleTask模式的所有特性外,还加强了一点,就是具有此模式的Activity安能单独地位于一个任务栈中。只要这个Activity在栈中,由于栈内复用,后续的请求都不会创建新的Activity,除非这个栈被系统销毁了

注意:
在singleTask中,在Acitity新建的时候,会寻找它所需要的任务栈。这里需要提到一个参数:TaskAffinity,任务相关性。这个参数标识了一个Activity所需要的任务栈的名字,在默认情况下,所有Activity所需要的任务栈的名字都为应用的包名。我们也可以为每个Activity单独指定TaskAffinity属性。
TaskAffinity与SingleTask配合使用的时候,它是具有该Activity目前任务栈的名字,待启动的Activity会运行在名字和TaskAffinity相同的任务栈中
TaskAffinity与allowTaskReparenting结合的时候,它是表示两个应用之间,如果应用A启动了应用B的某个Activity,这个启动的这个Activity的allowTaskReparenting为true的话,那么当应用B启动后,这个Activity又会从应用A的任务栈转移到应用B的任务栈(前面提过,A启动B,B就在A的任务栈),这个时候,打开应用B看到的是被A启动的Activity
另外,任务栈分为前台任务栈和后台任务栈


Activity的Flag
  • FLAG_ACTIVITY_NEW_TASK:这个标志位的作用是为activity指定singleTask启动模式,其效果和在XML中指定该模式相同
  • FLAG_ACTIVITY_SINGLE_TOP:这个标志位的作用是为activity指定singTop启动模式,其效果在和XML中指定该模式相同
  • FLAG_ACTIVITY_CLEAR_TOP:具有此标志位的Activity,当它启动的时候,在同一个任务栈中所有位于它上面的Activity都要出栈。这个模式一般和FLAG_ACTIVITTY_NEW_TASK配合使用,在这种情况下,被启动的Activity的实例如果已经存在,那么系统就会调用它的onNewIntent方法。如果被启动的Activity采用的是standard模式启动,那么它连同它之上的Activity都要出栈,系统会创建新的Activity实例并放入栈顶
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有这个标志的Activity不会出现在历史Activity的列表中,适用于不希望用户通过历史列表回到这个activity、它等同于在XML中指定Activity的属性:android:excludeFromRecents = “true“

IntentFilter的匹配规则

启动Activity分为显示和隐式。在隐式调用中,需要Intent能够匹配目标组件的IntentFilter中所设置的过滤信息,如果不匹配将无法启动目标Activity。
IntentFilter中的过滤信息有action,category,data。
只有一个Intent同时匹配action类别,category类别,data类别才能算完全匹配,只有完全匹配才能成功启动目标Activity。
一个Activity中可以有多个IntentFilter,只要一个Intent可以和其中的任何一个IntentFilter完全匹配,就可以启动该Activity
1. action匹配规则:
action是一个字符串,系统预定义了一些action,同时我们也可以在应用中定义自己的action。一个IntentFilter中可以有多个action,只要Intent中的action能够和过滤规则中任何一个action相同就算匹配成功。action区分大小写
2. category匹配规则:
category是一个字符串,系统预定义了一些category,同时我们也可以在应用中自己定义category。如果Intent中含有category,那么多有的category必须和过滤规则中的其中一个category相同,也就是说Intent中含有的category必须在过滤规则中定义过。如果Intent中没有category,系统会在启动Activity的时候自动加上一个category:android:intent.category.DEFAULT。所以为了目标activity可以接收隐式调用,就应该在Intent-filter中指定“android.intent.category.DEFAULT”
3. data匹配规则:
data的语法:
这里写图片描述

data由两部分组成,mimeType和URI。mimeType指媒体类型,比如image/jpeg,audio/mpeg4-geneic和video/*,可以表示图片,文本,视频等不同的媒体格式
URI的结构:
这里写图片描述

例子:
这里写图片描述

  • Scheme:URI的模式,比如http,file,content等,如果URI中没有指定scheme,那么整个URI的其他参数无效,也就意味着URI是无效的
  • Host:URI的主机名,比如www.baidu.com,host必须指定
  • Port,URI中的端口号,比如80,仅当URI中指定了Scheme和Host,port才有意义
  • Path,pathPattern,和pathPrefix,这三个参数表示路径信息,其中path表示完整信息,pathPattern也表示完整信息,但是它里面可以包含通配符“”,“”表示0个或者多个任意字符,需要注意的是,由于正则表达式的规范,如果想表示真实的字符串,那么“”要写成“\”,“\”要写成“\\”;pathPrefix表示路径的前缀信息

data的匹配规则和action类似,Intent中必须要有data数据,并且data数据能够完全匹配过滤规则中的某一个data。就是说过滤规则中出现的data部分也要出现在Intent中的data中
data的URI默认值为content和file

例子:

 <activity android:name=".SecondActivity">

            <intent-filter>
                <action android:name="com.vivian.fighting"/>
                <action android:name="com.vivian.world"/>
                <category android:name="com.vivian.f1"/>
                <category android:name="com.vivian.f2"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>

        </activity>
-----

 Intent intent = new Intent();
 intent.setAction("com.vivian.fighting");
 intent.addCategory("com.vivian.f1");
 startActivity(intent);

一定要在Manifest中加android:name="android.intent.category.DEFAULT"/>,这表示这个Activity接受隐式调用,如果不加,就会出错

将代码改为:

 <activity android:name=".SecondActivity">

            <intent-filter>
                <action android:name="com.vivian.fighting"/>
                <action android:name="com.vivian.world"/>
                <category android:name="com.vivian.f1"/>
                <category android:name="com.vivian.f2"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:mimeType="text/plain"
                      android:scheme="file"
                       android:host="www.baidu.com"
                    />
                <data android:mimeType="image/jpeg"
                    android:scheme="file"
                    android:host="www.baidu.com"
                    />
            </intent-filter>

 Intent intent = new Intent();
intent.setAction("com.vivian.fighting");
intent.addCategory("com.vivian.f1");
intent.setDataAndType(Uri.parse("file://www.baidu.com"),"text/plain");
startActivity(intent);

这样可以启动成功,根据实验,其他就是在action,category,data匹配的时候,只要Intent中含有目标Activity匹配规则中的任何一个,都可以成功启动
需要多说一点的是,action和data,系统给我们提供了很多action,可以让我们去调用系统的东西,比如相册,action是android.intent.action.GET_CONTENT,data的mimeType是image/*
我们在做分享的时候,当我们要分享一些信息到其他应用,用的action是ACTION_SEND,按需要设置data的mineType,如果有些应用要分享信息到该应用的某个activity,这个activity中的IntentFilter中的data要设置我们允许分享过来的mimeType

分享到其他App:

Intent sendIntent = new Intent();
        sendIntent.setAction(Intent.ACTION_SEND);
        sendIntent.putExtra(Intent.EXTRA_TEXT,"this is my text");
        sendIntent.setType("text/plain");
        startActivity(Intent.createChooser(sendIntent,"Share to"));

分享到该App

<activity android:name=".ui.MyActivity" >
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.SEND_MULTIPLE" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值