开启Android学习之旅-3-Android Activity

Android Activity

本文总结《第一行代码 Android》第3版的内容

环境:

Android Studio Giraffe | 2022.3.1 Patch 3

Activity 是什么?

Activity 简单将就是UI界面,包含两部分 Activity 类 和应用布局文件,如果是 Compose 则另说,一般入门Android,都是从Activity开始的。

我们写一个程序,常常找应用启动入口,像 java 的 main()函数,那么 Activity 的应用入口在哪?下面通过创建项目认识。

在创建 Android 项目时,要选择 No Activity,是因为 Android Studio 2022 中如果选择 Empty Activity,会默认使用 Compose UI。在创建完成后,手动添加"Empty Activity":

如果勾选 Launcher Activity,那么该 Activity 一般就是应用启动的时候,首先显示的。

在创建 Activity 之后,会自动在 AndroidManifest 注册 Activity:

应用入口在 AndroidManifest.xml 中一般会有标识:

xml 复制代码
<activity
            android:name=".FirstActivity"
            android:launchMode="singleTask"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

Acttivity 的基本用法

在Android Studio 添加 Activity 之后,会创建两个文件:一个类,一个xml文件。类用来写逻辑,xml写UI布局。

修改 xml 布局,使用LinearLayout,默认的太复杂,添加 Button 控件

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FirstActivity">
    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button 1"/>
</LinearLayout>

然后在 Activity中添加逻辑:

kotlin 复制代码
// button 点击事件
button1.setOnClickListener{
	Toast.makeText(this,"你点击了按钮",Toast.LENGTH_SHORT).show()

一个最简单的应用就完成了。

使用 Toast 消息提示

Toast 用于提示用户,用法如上面,第三个参数有两种 Toast.LENGTH_SHORT 和 Toast.LENGTH_LONG,显示时长不一样。

步骤1: 添加 Menu 资源文件

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/add_item"
        android:title="添加"/>
    <item
        android:id="@+id/remove_item"
        android:title="删除"/>
</menu>

步骤二:在 Activity中 重写 onCreateOptionsMenu() 方法

kotlin 复制代码
override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            R.id.add_item -> Toast.makeText(this,"添加菜单项",Toast.LENGTH_SHORT).show()
            R.id.remove_item -> Toast.makeText(this,"删除菜单项",Toast.LENGTH_SHORT).show()
        }
        return true
    }

效果:

销毁Activity

在按返回键时,Activity 可以被销毁,在代码中使用 finish() 方法

不同 Activity 中跳转

首先理解什么是 Intent?

在Android中,Intent是一种消息传递机制,用于在组件之间进行通信,如启动活动、启动服务、传递数据等。根据其使用方式,Intent可以分为显式Intent和隐式Intent。

显式Intent:显式Intent是指明确指定要启动的组件(如Activity、Service等)的名称。这种Intent通常用于应用内部的组件间通信。例如,从一个Activity启动另一个Activity。

kotlin 复制代码
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)

在上述代码中,我们明确指定了要启动的Activity是SecondActivity,因此这是一个显式Intent。

FirstActivity 跳转到 SecondActivity 使用 显式 Intent。

隐式Intent:隐式Intent并没有明确指定要启动的组件,而是指定了一种动作(Action)和数据(Data),然后由系统解析这个Intent,找到合适的组件来处理这个Intent。这种Intent通常用于启动其他应用的组件。例如,打开网页、拨打电话等。

kotlin 复制代码
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("https://www.baidu.com")
startActivity(intent)

在上述代码中,我们指定了一个动作ACTION_VIEW和一个数据https://www.baidu.com,系统会找到能处理这个动作和数据的应用(如浏览器)来启动。因此这是一个隐式Intent。

如果让我们的程序能够响应隐式Intent,需要在 AndroidManifest.xml 中注册:

xml 复制代码
<activity
            android:name=".ThirdActivity"
            android:exported="true" >
            <intent-filter tools:ignore="AppLinkUrlError">
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:scheme="https"/>
            </intent-filter>
        </activity>

调用方法:

kotlin 复制代码
 // 隐式Intent
 val intent = Intent("com.alex.activitytest.ACTION_START")
 intent.addCategory("com.alex.activitytest.MY_CATEGORY")
 startActivity(intent)

不同Activity传递数据

FirstActivty 启动 SecondActivity 并传递数据:

kotlin 复制代码
  // 启动Activity并传递数据
  val data="Hello SecondActivity"
  val intent = Intent(this,SecondActivity::class.java)
  intent.putExtra("extra_data",data)
  startActivity(intent)

SecondActivity 接收数据:在 onCreate方法中

kotlin 复制代码
val extraData=intent.getStringExtra("extra_data")
Toast.makeText(this,extraData,Toast.LENGTH_SHORT).show()

如果 SecondActivity 需要向 FirstActivty 返回数据,需要三步,在 FirstActivty 调用的时候:把 startActivity(intent) 替换为

kotlin 复制代码
startActivityForResult(intent,1)

SecondActivity 返回数据:

kotlin 复制代码
val intent = Intent()
intent.putExtra("data_return","Hello, FirstActivity")
setResult(RESULT_OK,intent)
// 销毁当前Activity
finish()

FirstActivty 接收数据:

kotlin 复制代码
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
 	super.onActivityResult(requestCode, resultCode, data)
	 when (requestCode) {
		 1 -> if (resultCode == RESULT_OK) {
		 	val returnedData = data?.getStringExtra("data_return")
		 	Log.d("FirstActivity", "returned data is $returnedData")
	 	}
 	}
}

startActivityForResult 与 onActivityResult 被废弃了,可以参考这篇文章进行更新:

startActivityForResult被标记为废弃?Activity Result API闪亮登场!

Activity 生命周期

Android 使用 task 来管理 Activity,一个任务就是一组存放在返回栈里的 Activity的集合。启动Activity,Activity入栈,Activity销毁就会出栈。显示的Activity总是在栈顶。

Activity 的四种状态

  • 运行状态
    Activity处于栈顶
  • 暂停状态
    比如一个Activity上弹出一个对话框,此时Activity处于暂停状态
  • 停止状态
    Activity 不处于栈顶,并且完全不可见
  • 销毁状态
    Activity 从返回栈中移除

Activity 生命周期

  • onCreate()。会在Activity第一次被创建的时候调用。应该在这个方法中完成Activity的初始化操作,比如加载布局、绑定事件等。
  • onStart()。这个方法在Activity由不可见变为可见的时候调用。
  • onResume()。这个方法在Activity准备好和用户进行交互的时候调用。此时的Activity一定位于返回栈的栈顶,并且处于运行状态。
  • onPause()。这个方法在系统准备去启动或者恢复另一个Activity的时候调用。我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶Activity的使用。
  • onStop()。这个方法在Activity完全不可见的时候调用。它和onPause()方法的主要区别在于,如果启动的新Activity是一个对话框式的Activity,那么onPause()方法会得到执行,而onStop()方法并不会执行。
  • onDestroy()。这个方法在Activity被销毁之前调用,之后Activity的状态将变为销毁状态。
  • onRestart()。这个方法在Activity由停止状态变为运行状态之前调用,也就是Activity被重新启动了。

结合GPT,谈谈应用场景:

onCreate():

应用场景: 初始化 Activity,设置布局,初始化成员变量和数据绑定。

例子: 在一个音乐播放器应用中,在 onCreate() 中加载布局,初始化播放控制按钮和音轨信息。

onStart():

应用场景: 让 Activity 对用户可见,进行一些轻量级的资源初始化或恢复操作。

例子: 在新闻应用中,当 Activity 变为可见时,可以在 onStart() 中开始加载新闻列表。

onResume():

应用场景: 当 Activity 与用户交互前,恢复暂停的动画,初始化相机等。

例子: 在相机应用中,在 onResume() 方法中打开相机预览。

onPause():

应用场景: 暂停或调整不再需要的操作,如暂停动画,释放相机资源。

例子: 如果用户在编辑照片的应用中接到电话,onPause() 可用于暂停编辑进度或保存状态。

onStop():

应用场景: 当 Activity 不再可见时,释放或调整资源和操作,如停止播放媒体,取消网络请求。

例子: 在视频播放应用中,当用户离开播放界面,可以在 onStop() 中停止视频播放并释放播放器资源。

onDestroy():

应用场景: 清理资源,如关闭数据库连接,注销广播接收器。

例子: 在社交应用中,当 Activity 销毁时,关闭数据库连接和注销监听网络变化的广播接收器。

onRestart():

应用场景: 在 Activity 从停止状态回到活动状态时调用,用于重新初始化在 onStop() 中释放的资源。

例子: 在购物应用中,如果用户从购物车界面切换到其他应用然后返回,可以在 onRestart() 中刷新购物车数据。

如果从网络请求新闻列表数据,可以写在 onStart 或 onResume 方法中。如果你希望每次 Activity 变得可见时都刷新数据,那么 onStart() 是合适的地方。如果你希望在 Activity 每次回到用户交互前台时刷新数据,则 onResume() 更为合适。此外,考虑到网络请求可能会耗时并影响用户体验,推荐使用异步处理(如使用 AsyncTask 或 Retrofit 等网络库)来进行网络请求,避免阻塞主线程。

Activity 保存状态数据

如果 Activity 在停止状态时,有可能被回收,再返回时,如果没有数据,Activity可能无法正常显示,此时需要保存状态,可以使用 onSaveInstanceState方法,确保在回收前保存

kotlin 复制代码
override fun onSaveInstanceState(outState: Bundle) {
 super.onSaveInstanceState(outState)
 val tempData = "Something you just typed"
 outState.putString("data_key", tempData)
}

在onCreate() 恢复数据:

kotlin 复制代码
override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 Log.d(tag, "onCreate")
 setContentView(R.layout.activity_main)
 if (savedInstanceState != null) {
 val tempData = savedInstanceState.getString("data_key")
 Log.d(tag, "tempData is $tempData")
 }
 ...
}

Activity 四种启动模式

Android 中Activity的四种启动模式及使用场景如下:

  1. Standard

用途: 每次启动 Activity 时都会创建一个新的实例,无论该 Activity 是否已经存在于任务栈中。

应用场景: 这是默认模式。适用于大多数标准的 Activity,如显示列表项的详细信息。例如,在邮件应用中,用户点击一个邮件时,每次都会创建一个新的邮件详情 Activity,即使是同一个邮件。

  1. SingleTop

用途: 如果新的 Activity 已经是任务栈的顶端,则不会创建新的实例,而是复用栈顶的实例,并通过 onNewIntent() 方法接收新的 Intent。

应用场景: 适用于需要接收新信息且频繁启动但不需要多实例的 Activity。例如,在聊天应用中,如果用户已经在聊天界面,新消息的通知点击后只更新当前的聊天界面,而不重新创建 Activity。

  1. SingleTask

用途: 只创建一个实例,该实例会在新的任务栈中。如果 Activity 已经存在,则把这个 Activity 之上的所有其他 Activity 出栈,使这个 Activity 显示在最前。

应用场景: 适用于作为应用中单一入口的 Activity,如主页。例如,在浏览器应用中,主页 Activity 设置为 singleTask,无论从哪里启动,都只有一个主页实例。

  1. SingleInstance

用途: 类似于 singleTask,但系统会为这种 Activity 创建一个新的任务栈,并且在这个栈中只有这个 Activity 实例。

应用场景: 适用于需要与应用完全分离的模块,例如,一个应用内的浮动小窗口或者是需要与其他应用共享的 Activity。例如,一款具有浮动小窗功能的音乐播放器,其播放控制界面可以设置为 singleInstance 模式。

Activity最佳实践

通过BaseActivity知晓当前在哪一个Activity

kotlin 复制代码
open class BaseActivity : AppCompatActivity() {
	 override fun onCreate(savedInstanceState: Bundle?) {
	 	super.onCreate(savedInstanceState)
	 	Log.d("BaseActivity", javaClass.simpleName)
	 }
}

全局管理Activity,随时退出程序

新建单例类ActivityCollector

kotlin 复制代码
package com.alex.activitytest
import android.app.Activity

/**
 * @Author      : alex
 * @Date        : on 2023/12/28 15:59.
 * @Description :描述
 */
object ActivityCollector {
    private val activities = ArrayList<Activity>()

    fun addActivity(activity: Activity){
        activities.add(activity)
    }

    fun removeActivity(activity: Activity){
        activities.remove(activity)
    }

    fun finishAll(){
        for(activity in activities){
            if(!activity.isFinishing){
                activity.finish()
            }
        }
        activities.clear()
    }
}

这个方法在测试的时候不行,比如点击按钮执行 ActivityCollector.finishAll(), 系统会重启App,即时加了下面的代码也一样。

kotlin 复制代码
android.os.Process.killProcess(android.os.Process.myPid())

可参考:https://blog.csdn.net/shulianghan/article/details/116402759

相关推荐
南宫生2 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
拭心2 小时前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android
sanguine__2 小时前
Web APIs学习 (操作DOM BOM)
学习
数据的世界014 小时前
.NET开发人员学习书籍推荐
学习·.net
带电的小王4 小时前
WhisperKit: Android 端测试 Whisper -- Android手机(Qualcomm GPU)部署音频大模型
android·智能手机·whisper·qualcomm
四口鲸鱼爱吃盐4 小时前
CVPR2024 | 通过集成渐近正态分布学习实现强可迁移对抗攻击
学习
梦想平凡4 小时前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
元争栈道5 小时前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
阿甘知识库6 小时前
宝塔面板跨服务器数据同步教程:双机备份零停机
android·运维·服务器·备份·同步·宝塔面板·建站
元争栈道6 小时前
webview+H5来实现的android短视频(短剧)音视频播放依赖控件资源
android·音视频