【Android】四大组件之Activity

Android四大组件之Activity

一、创建Activity

  • 定义java类,继承Activity
  • 在清单文件中配置Activity标签
  • 设为启动的activity,需要在activity标签下配置
<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
  • 多个activity可以配置启动标签,每配置一个,系统就会创建一个快捷图标

二、Activity跳转

Activity的跳转需要创建Intent对象,通过设置intent对象的参数指定要跳转Activity

显式意图
  • 通过设置Activity的包名和类名实现跳转,称为显式意图
  • 跳转至同一项目下的另一个Activity,直接指定该Activity的字节码即可
Intent intent = new Intent();
intent.setClass(this, SecondActivity.class);
startActivity(intent);
  • 跳转至其他应用中的Activity,需要指定该应用的包名和该Activity的类名
Intent intent = new Intent();
//启动系统自带的拨号器应用
//这个不一定能启动(启动其他应用都是使用隐式启动)
intent.setClassName("com.android.dialer", "com.android.dialer.DialtactsActivity");
startActivity(intent);
  • 跳转传递数据

把数据封装到intent对象中,数据可以是八大基本数据类型,字符串和它们的数组,两个序列化接口,还有Bundle对象

放在intent中

        intent.putExtra("name","张三")
        intent.putExtra("age",10)
        val name = intent.getStringExtra("name")
        val age = intent.getIntExtra("age", 0)

放在Bundle中

        val bundle = Bundle()
        bundle.putString("", "")
        intent.putExtras(bundle)
		intent.extras?.getString("","")
隐式意图
  • 通过指定动作实现跳转,称为隐式意图。系统会在所有应用中寻找匹配的intent-filter,找到则启动,找不到则异常
  • 在清单文件中的activity标签下,配置标签,设置action和category
  • intent-filter下的标签
    • action:指定动作(可以自定义,可以使用系统自带的)
    • data:指定数据(操作什么内容)
      • scheme
      • mimetype
    • category:类别 (默认类别,机顶盒,车载电脑)
  • category必须在清单文件中指定,因为使用intent隐式启动时,默认是设置了intent.addCategory(Intent.CATEGORY_DEFAULT)
  • 隐式意图启动Activity,需要为intent设置以上三个属性,且值必须与该Activity在清单文件中对三个属性的定义匹配
  • intent-filter节点及其子节点都可以同时定义多个,隐式启动时只需与任意一个匹配即可
//隐式启动拨号界面
val intent = Intent()
intent.action = Intent.ACTION_DIAL
intent.addCategory(Intent.CATEGORY_DEFAULT)
startActivity(intent)
  • 有多个action时,匹配一个就可以了,如果有多个data,但是有的data下还有mimetype,这时需要匹配mimetype才行。同时有data和type时,需要使用setDataAndType
val intent = Intent()
intent.action = "a.b.c"
//匹配schema
intent.data = Uri.parse("wzh2:ppp")
//匹配mimetype
intent.type = "text/haha"

//同时有data和mimetype时,不能使用上面的设置,会互相清除,需要调用下面的方法
intent.setDataAndType( Uri.parse("wzh:ppp"),"text/haha")
startActivity(intent)
<activity android:name=".SecondActivity">
    <intent-filter>
        <action android:name="a.b.c"/>
        <data android:scheme="wzh"/>
        <data android:scheme="wzh2" android:mimeType="text/haha"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>
  • 跳转传递数据

在清单文件中设置data标签,传递数据

<data android:scheme="wzh2" android:mimeType="text/haha"/>

在目标的activity中获取数据

val uri = intent.data
println("uri:${uri}")//uri:wzh2:xxx
应用场景
  • 在同一应用中的activity,使用显式
  • 启动不同应用中的activity,使用隐式,虽然显式也可以,但是一定要使用隐式,因为可以多个选择
  • 显式的效率高于隐式(隐式启动,底层是遍历整个系统中的清单文件,找出对应的activity)

三、Activity的生命周期

activity的生命周期

生命周期方法

  • onCreate():Activity已经被创建完毕
  • onStart():Activity已经显示在屏幕,但没有得到焦点
  • onResume():Activity得到焦点,可以与用户交互
  • onPause():Activity失去焦点,无法再与用户交互,但依然可见
  • onStop():Activity不可见,进入后台
  • onDestroy():Activity被销毁
  • onRestart():Activity从不可见变成可见时会执行此方法

手机内存不足时,会杀死之前启动的进程,按照LRU算法(最近最少使用)杀死进程

完整生命周期(entire lifetime)

onCreate–>onStart–>onResume–>onPause–>onStop–>onDestory

可视生命周期(visible lifetime)

onStart–>onResume–>onPause–>onStop

前台生命周期(foreground lifetime)

onResume–>onPause


四、任务和返回栈

task

点击最近任务列表按钮,出现的一个个「app」,其实是一个个的task,activity在任务栈中可以堆叠,并且每个任务栈也是可以进行堆叠的。同一应用也有可能出现多个不同的task。不同task堆叠时,顶部的task称为前台task,下面的称为后台task,点击home键或者最近任务列表时,此时堆叠的task会进行分离成不同的task(前台和后台的task分开)。在最近任务列表看见的task未必是「活的」,看不见的task也未必是「死的」(singleInstance的taskAffinity冲突时,只显示一个task,另一个还活着,被隐藏了)

launchMode

  • standard
    每启动一个activity就会创建一个新的activity实例。在不同应用的情况下,启动新的activity会被放入当前task中,与另一个应用互不干扰

  • singleTop
    被标记singleTop的activity实例如果存在,启动时会复用此activity,调用onNewIntent(),并移动到栈顶。不存在则会被创建
    应用场景:浏览器的书签

  • singeTask
    在同一应用中,如果activity被设置为singleTask,不存在,会创建一个实例,下次启动时复用该实例,同时堆叠在上面的activity会被移除。如果此时的taskAffinity与启动该activity的activity不同时,则会加入它所声明的taskAffinity的task中(可以是新的task,也可以是其他应用的task,具体看taskAffinity的定义)。
    在不同的应用启动该activity时,连该应用的task都堆叠到当前task上面。
    存在该实例,再次启动,会调用onNewIntent()

  • singleInstance
    启动模式非常特殊, activity会运行在自己(新的)的task里面,并且这个task里面只有一个实例存在。如果内存中没有此实例,则会创建新的任务栈,并且创建此activity实例,这个栈移至前台。整个系统中只有一个实例,存在该实例,再次启动,会调用onNewIntent()
    应用场景:打电话界面

allowTaskReparenting

如果不使用singletask,而是使用allowTaskReparenting=true时,比如在A应用中打开B应用的allowTaskReparenting=true的activity,这时会进入A的task,并且在栈顶,然后回到桌面,点击B应用,会发现这个activity会跳回到B应用的栈顶,点击A应用时,这个activity消失了。

但是这个属性要慎用,有一些版本失效了

taskAffinity

任务的相关性,默认情况下,所有的activity的taskAffinity都是application中的taskAffinity,默认是当前包名。每个 Task 也都有它的 taskAffinity,它的值取自栈底 Activity 的 taskAffinity;我们可以通过 AndroidManifest.xml 来定制 taskAffinity,但在默认情况下,一个 App 里所有的 Task 的 taskAffinity 都是一样的,就是这个 App 的包名。当我们启动一个新的 Task 的时候,它的值就是它所启动的第一个 Activity 的 taskAffinity。当我们继续从已经打开的 Activity 再打开新的 Activity 的时候,taskAffinity 就会被忽略了,新的 Activity 会直接入栈,不管它来自哪。taskAffinity在launchmode为singletask或者singleinstance时才有意义。不同的taskAffinity在最近任务列表中以不同的task进行显示,根据taskAffinity入栈,没有则创建task


五、横竖屏切换

默认情况下 ,横竖屏切换, 销毁当前的activity,重新创建一个新的activity。之所以这样设计,是为了切换横竖屏的布局

禁用横竖屏切换的生命周期

  • 将屏幕的方向固定

1.清单文件中配置

android:screenOrientation="landscape"
android:screenOrientation="portrait"

2.代码中设置

requestedOrientation =  ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
  • 切换方向时,不处理生命周期,不会更换布局文件
android:configChanges="orientation|screenSize|keyboardHidden"

六、Activity销毁时传递数据

  • 开启activity并且获取返回值

    startActivityForResult(intent, 0);
    
  • 在新开启的界面里面实现设置数据的逻辑

    Intent data = new Intent();
    data.putExtra("phone", phone);
    //设置一个结果数据,数据会返回给调用者
    setResult(0, data);
    finish();//关闭掉当前的activity,才会返回数据
    
  • 在开启者activity里面实现方法

    //通过data获取返回的数据
    onActivityResult(int requestCode, int resultCode, Intent data)
    
  • 通过判断请求码和结果码确定返回值的作用

    • 请求码是区分哪个activity启动的
    • 结果码是判断传递过来的是什么数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值