一、Activity相关

Activity: 负责用户界面的展示和用户交互,学习Activity就要学习Fragment,虽然它不是四大组件之一,但是它在我们的开发工作中也是频频被使用到,且必须和Activity一块使用,常用于分模块开发,比如慕课首页的几个tab,每个tab都是对应着一个Fragment

图片和部分文字转载自https://www.songyubao.com/book/primary/activity/Activity.html

Activity必知必会

1.Activity 生命周期

android_activity_lifecycle

方法作用
onCreate()该方法会在 Activity 第一次创建时进行调用,在这个方法中通常会做 Activity 初始化相关的操作,例如:加载布局、绑定事件等。
onStart()这个方法会在 Activity 由不可见变为可见的时候调用,但是还不能和用户进行交互
onResume()表示Activity已经启动完成,进入到了前台,可以同用户进行交互了。
onPause()这个方法。可以在这里释放系统资源,动画的停止,不宜在此做耗时操作。
发生场景1.在系统准备去启动另一个 Activity 的时候调用 2.按下返回键 3.从前台切换到后台
onStop()当Activity不可见的时候回调此方法。需要在这里释放全部用户使用不到的资源。可以做较重量级的工作,如对注册广播的解注册,对一些状态数据的存储。此时Activity还不会被销毁掉,而是保持在内存中,但随时都会被回收。通常发生在启动另一个Activity或切换到后台时
发生场景和onPause()相同
onDestroy()Activity即将被销毁。此时必须主动释放掉所有占用的资源。
onRestart()这个方法在 Activity 由停止状态变为运行状态之前调用,也就是 Activity 被重新启动了(APP切到后台会进入onStop(), 再切换到前台时会触发onRestart()方法)

按home键 : 运行中状态 转变 开始 执行onPause() onStop()

返回键: onPause() —> onResume()

回到这个Activity : 从onStop() 转变 开始执行 onRestart() —> onStart() —>onResume()

2.Activity组件创建

class SecondActivity : AppCompatActivity(){

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

}

Tips:

选择复写只有一个参数的onCreate方法

3.Activity组件注册

四大组件需要在AndroidManifest文件中配置否则无法使用,类似Activity无法启动,

一般情况下: 在新建一个activity后,为了使intent可以调用此活动,我们要在androidManifest.xml文件中添加一个标签,标签的一般格式如下:

<activity android:name=".SecondActivity"
    android:exported="true">
    <intent-filter>
        <!--自定义 action时一般包名.action.全大写类名-->
        <action android:name="com.example.componentLearn.action.SECONDACTIVITY"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>
  • android:name是对应Activity的类名称
  • android:exported 是否支持其它应用调用当前组件。默认值:如果包含有intent-filter 默认值为true; 没有intent-filter默认值为false。
  • android:label是Activity标题栏显示的内容. 现已不推荐使用
  • intent-filter 是意图过滤器. 常用语隐式跳转
    • action android:name 是动作名称,是指intent要执行的动作
    • category android:name 是过滤器的类别, 一般情况下,每个 中都要显示指定一个默认的类别名称,即<category android:name="android.intent.category.DEFAULT" />

但是上面的代码中没有指定默认类别名称,这是一个例外情况,因为其 中的是"android.intent.action.MAIN",意思是这个Activity是应用程序的入口点,这种情况下可以不加默认类别名称。

4. Activity启动与参数传递

Tips

在Android中我们可以通过下面两种方式来启动一个新的Activity,注意这里是怎么启动,分为显示启动和隐式启动!

4.1 显式启动:通过包名来启动

无参跳转
textView.setOnClickListener {
    //MainActivity@this : Context
    val intent = Intent(MainActivity@this , SecondActivity::class.java)
    startActivity(intent)
}

日志 ActivityA跳转到ActivityB

2021-11-03 22:08:59.781 4562-4562/com.example.componentlearn E/MainActivity:: onCreate
2021-11-03 22:08:59.790 4562-4562/com.example.componentlearn E/MainActivity:: onStart
2021-11-03 22:08:59.797 4562-4562/com.example.componentlearn E/MainActivity:: onResume
2021-11-03 22:09:07.295 4562-4562/com.example.componentlearn E/MainActivity:: onPause
2021-11-03 22:09:07.332 4562-4562/com.example.componentlearn E/SecondActivity:: onCreate
2021-11-03 22:09:07.337 4562-4562/com.example.componentlearn E/SecondActivity:: onStart
2021-11-03 22:09:07.338 4562-4562/com.example.componentlearn E/SecondActivity:: onResume
2021-11-03 22:09:08.009 4562-4562/com.example.componentlearn E/MainActivity:: onStop
有参跳转
textView.setOnClickListener {
    //有参跳转
    val intent = Intent(MainActivity@this , SecondActivity::class.java)
    intent.putExtra("extra_data","extra_data")
    intent.putExtra("extra_int_data",100)
    startActivity(intent)
}

ActivityB接受参数

val stringExtra = intent.getStringExtra("extra_data")
val intExtra = intent.getIntExtra("extra_int_data" , 0 )
期待从目标页获取数据

registerForActivityResult---->比如启动相册获取图片

lateinit延迟初始化

①假设从A--->B页面,以registerForActivityResult方式启动
registerForActivityResult(
   ActivityResultContracts.StartActivityForResult()
){result ->
      val data = result.data
      val resultCode = result.resultCode
      val stringExtraResult = data?.getStringExtra("result_extra_string")
      val intExtraResult = data?.getIntExtra("result_extra_int",0)
      textView.text = "MainActivity result [${resultCode}] ${stringExtraResult} ---- ${intExtraResult}"
}.launch(Intent(this,SecondActivity::class.java))
 
②如果B页面返回时,调用了 
textView.setOnClickListener {
      val resultIntent = Intent()
      resultIntent.putExtra("result_extra_string" , "result_extra_string")
      resultIntent.putExtra("result_extra_int" , 1000)
      setResult(Activity.RESULT_OK , resultIntent)
      finish() //关闭SecondActivity 等同于点击返回键
}

startActivityForResult 过时用 registerForActivityResult代替

https://www.zbug.cc/index.php/archives/registerForActivityResult.html

这个事件中两个Activity的生命周期

2021-11-04 11:19:12.221 4381-4381/com.example.componentlearn E/MainActivity:: onCreate
2021-11-04 11:19:12.233 4381-4381/com.example.componentlearn E/MainActivity:: onStart
2021-11-04 11:19:12.235 4381-4381/com.example.componentlearn E/MainActivity:: onResume
2021-11-04 11:19:12.267 4381-4381/com.example.componentlearn E/MainActivity:: onPause
2021-11-04 11:19:12.705 4381-4381/com.example.componentlearn E/SecondActivity:: onCreate
2021-11-04 11:19:12.709 4381-4381/com.example.componentlearn E/SecondActivity:: onStart
2021-11-04 11:19:12.709 4381-4381/com.example.componentlearn E/SecondActivity:: onResume
2021-11-04 11:19:12.883 4381-4381/com.example.componentlearn E/MainActivity:: onStop
2021-11-04 11:19:20.553 4381-4381/com.example.componentlearn E/SecondActivity:: onPause
2021-11-04 11:19:20.565 4381-4381/com.example.componentlearn E/MainActivity:: onRestart
2021-11-04 11:19:20.568 4381-4381/com.example.componentlearn E/MainActivity:: onStart
2021-11-04 11:19:20.569 4381-4381/com.example.componentlearn E/MainActivity:: onResume
2021-11-04 11:19:21.141 4381-4381/com.example.componentlearn E/SecondActivity:: onStop
2021-11-04 11:19:21.142 4381-4381/com.example.componentlearn E/SecondActivity:: onDestroy

4. 2. 隐式启动

通过指定 actioncategory 的信息,让系统去分析这个 Intent,并找出合适的 Activity 去启动。

<activity android:name=".SecondActivity"
    android:exported="true">
    <intent-filter>
        <!--自定义 action时一般包名.action.全大写类名-->
        <action android:name="com.example.componentLearn.action.SECONDACTIVITY"/>
        <category android:name="com.example.componentLearn.category.SecondActivity"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>
textView.setOnClickListener {
    val intent = Intent()
    intent.action = "com.example.componentLearn.action.SECONDACTIVITY"
    intent.addCategory("com.example.componentLearn.category.SECONDACTIVITY")

    intent.putExtra("extra_data" , "extra_data")
    intent.putExtra("extra_data_int" , 111)
    //隐式启动
    startActivity(intent)
}

5.原生常见的Activtiy

拨打电话

给 11111 拨打电话

val uri: Uri = Uri.parse("tel: 11111")
val intent = Intent(Intent.ACTION_DIAL,uri)
startActivity(intent)

发送短信

给 11111 发送内容为“发送短信”的短信

val uri:Uri = Uri.parse("smsto:1111")
val intent = Intent(Intent.ACTION_SENDTO , uri)
intent.putExtra("sms_body" , "发送短信")
startActivity(intent)

打开浏览器:

打开baidu主页

val uri:Uri = Uri.parse("http://www.baidu.com")
val intent = Intent(Intent.ACTION_VIEW, uri)
startActivity(intent)

多媒体播放:

val intent = Intent(Intent.ACTION_VIEW)
val uri = Uri.parse("file:///sdcard/foo.mp3")
intent.setDataAndType(uri, "audio/mp3")
startActivity(intent)

打开摄像头拍照:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
startActivityForResult(intent, 0);

>>>Activity的onActivityResult方法回调中取出照片数据
Bundle extras = intent.getExtras(); 
Bitmap bitmap = (Bitmap) extras.get("data");

从图库选图并剪切

// 获取并剪切图片
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
intent.putExtra("crop", "true"); // 开启剪切
intent.putExtra("aspectX", 1); // 剪切的宽高比为1:2
intent.putExtra("aspectY", 2);
intent.putExtra("outputX", 20); // 保存图片的宽和高
intent.putExtra("outputY", 40); 
intent.putExtra("output", Uri.fromFile(new File("/mnt/sdcard/temp"))); // 保存路径
intent.putExtra("outputFormat", "JPEG");// 返回格式
startActivityForResult(intent, 0);

>>>>Activity的onActivityResult方法中去读取保存的文件

剪切指定图片文件

Intent intent = new Intent("com.android.camera.action.CROP"); 
intent.setClassName("com.android.camera", "com.android.camera.CropImage"); 
intent.setData(Uri.fromFile(new File("/mnt/sdcard/temp"))); 
intent.putExtra("outputX", 1); // 剪切的宽高比为1:2
intent.putExtra("outputY", 2);
intent.putExtra("aspectX", 20); // 保存图片的宽和高
intent.putExtra("aspectY", 40);
intent.putExtra("scale", true);
intent.putExtra("noFaceDetection", true); 
intent.putExtra("output", Uri.parse("file:///mnt/sdcard/temp")); 
startActivityForResult(intent, 0);

>>>>Activity的onActivityResult方法中去读取保存的文件

进入手机的无线网络设置页面

// 进入无线网络设置界面(其它可以举一反三)  
Intent intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS);  
startActivityForResult(intent, 0);

6. Activity四种启动模式

standard

默认值,多实例模式。每启动一次,都会创建一个新的Activity实例。

启动的生命周期为:onCreate()->onStart()->onResume()

standard

singleTop

栈顶复用模式

如果任务栈顶已经存在需要启动的目标Activity,则直接启动,并会回调onNewIntent()方法,生命周期顺序为: onPause() ->onNewIntent()->onResume()

如果任务栈上顶没有需要启动的目标Activity,则创建新的实例,此时生命周期顺序为: onCreate()->onStart()->onResume()

两种情况如下图,从图中可以看出,此模式下还是会出现多实例,只要启动的目标Activity不在栈顶的话。

singletop

singleTask

栈内复用模式,一个任务栈只能有一个实例。

有几种情况:

  • 当启动的Activity目标任务栈不存在时,则以此启动Activity为根Activity创建目标任务栈,并切换到前面
  • D为singleTask模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CqBhkA0i-1636119213858)(https://cdn.jsdelivr.net/gh/hairlyOwl/photo@master/singletask-(1)].497h6l5ebky0.png)

  • 当启动的Activity存在时,则会直接切换到Activity所在的任务栈,并且任务栈中在Activity上面的所有其他Activity都出栈(调用destroy()),此时启动的Activity位于任务栈顶,并且会回调onNewIntent()方法。

singletask2

singleInstance

singleInstance名称是单例模式,即App运行时,该Activity只有一个实例。既然只有一个,那么也就说明很重要、很特殊,我们需要将其“保护起来”。单例模式的“保护措施”是将其单独放到一个任务栈中

Bug记录

1**.LifecycleOwners must call register before they are STARTED**

java.lang.IllegalStateException: LifecycleOwner com.example.componentlearn.MainActivity@1e0bae9 is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.

registerForActivityResult 移除 OnClickListener

但仍在onCreate

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值