可以先行看我的这篇 《安卓Android入门》
一、创建第一个Android项目
1.1 准备Android Studio
选择
写信息
等待构建Gradle
可以选择我们的模仿器,甚至我们可以通过手机屏幕共享的方式,把手机的开辟者模式打开等操作,下载到本机手机之中,可以0隔断的感受,程序之美。
1.2 运行程序
1.3 程序结构是什么
app下的结构
这种的结构化的项目简便明了,提高开辟效率和代码质量
build - 编译时自动天生的文件
libs - 第三方jar包放在libs目次下
java - 放置所需Java
代码,自动天生了一个MainActivity 文件
1.3.2 res - 子目次(所有图片、布局、字符串等资源)
调用方式:
[ 1 ] 通过Java
代码调用 ->
- getResources().getDrawable(R.mipmap.ic_launcher);//调用mipmap文件夹中资源文件
- getResources().getDrawable(R.drawable,icon); //调用以drawable开头的文件夹中的资源文件
复制代码 [ 2 ] 通过XML布局调用
- @mipmap/ic_launcher //调用mipmap文件夹中的资源文件
- @drawable/icon //调用以 drawable开头的文件夹中的资源文件
复制代码 我们应该创建差别分辨率的目次,如drawable-hdpi、drawable-xhdpi、drawable-xxhdpi等,并在制作程序时提供几个差别分辨率的版本,是为了适应差别设备的屏幕密度和分辨率
打开我们的子目次
这内里就是我们配置的字符串,调用利用,不用全局在中出现相同的多次构建。在res/values/目次中的strings.xml文件中定义字符串
怎么构建
在XML中通过@string/app_name可以获得该字符串的引用。
最终
点击可以替换
主题是包罗一种或多种的格式化属性聚集,可改变窗体的样式,对整个应用或某个Activity存在全局性影响。
在res/values目次下的styles.xml文件中
- <resources>
- <!-- Base application theme.-->
- <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
- <!-- Customize your theme here.-->
- <item name="colorPrimary">@color/colorPrimary
- </item>
- <item name="colorPrimaryDark">@color/colorPrimary
- Dark</item>
- <item name="colorAccent">@color/colorAccent</item>
- </style>
- </resources>
复制代码 在根元素中可以包罗多个标签,每个
标签中也可以包罗多个标签。 (1)在AndroidManifest.xml中设置主题的
- <application
- ···
- android:theme ="@style/AppTheme">
- </application>
复制代码 (2)在Java
代码中设置主题的
- setTheme(R.style.AppTheme);
复制代码 通过改变主题可以改变整个窗体样式,但不能设置View控件的具体样式,因此创建一个样式来美化View控件,放在res/values目次下的styles.xml文件中
- <resources>
- <style name="textViewSytle">
- <item name="android:layout_width">20dp</item>
- <item name="android:layout_height">20dp</item>
- <item name="android:background">#f54e39</item>
- </style>
- </resources>
复制代码 在布局文件的View控件中通过style属性调用
- <TextView
- style="estyle/textViewSytle"/>
复制代码 颜色资源通常定义在res/values/colors.xml文件中
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <color name="colorPrimary">#3F51B5</color>
- <color name="colorPrimaryDark">#303F9F</color>
- <color name="colorAccent">#FF4081</color>
- </resources>
复制代码 1.通过Java
代码调用颜色资源文件
- getResources().getColor(R.color,colorPrimary);
复制代码 2.在XML布局文件中调用颜色资源文件
颜色值必须以“#”开头,“#”后面表现Alpha-Red-Green-Blue情势的内容。此中,Alpha值可以省略,如果省略,表现颜色默认是完全不透明的。
·#RGB:利用红、绿、蓝三原色的值定义颜色,此中,红、绿、蓝分别利用0~f的十六进制数值表现。
·#ARGB:利用透明度以及红、绿、蓝三原色来定义颜色,此中,透明度、红、绿、蓝分别利用0~f的十六进制数值表现。
尺寸资源通常定义在res/values/dimens.xml文件中
要手动创建dimens创建dimens.xml文件,
- <resources>
- <dimen name="activity_horizontal_margin">16dp</dimen>
- <dimen name="activity_vertical_margin">16dp</dimen>
- </resources>
复制代码 <dimen></dimen>标签用于定义尺寸资源,此中name属性指定尺寸资源的名称。标签中心设置的是尺寸大小。在dimens.xml文件中只能有一个根元素,根元素可以包罗多个<dimen></dimen>标签。
1.通过Java
代码调用尺寸资源
- getResources().getDimension(R,dimen.activity_horizontal_margin);
复制代码 2.在XML布局文件中调用尺寸资源
- @dimen/activity_horizontal_margin
复制代码 px (pixels, 像素):像素是屏幕上的一个点,是最基本的屏幕单元。
dp(density-independent pixels, 设备独立像素):
dp是与屏幕密度无关的单元。dp单元可以根据屏幕的密度自动调整大小,使得界面元素在差别分辨率的设备上保持大致相同的物理尺寸。
sp (scaled pixels, 比例像素):
sp主要用于设置字体大小,它会根据用户的字体大小首选项进行缩放。sp与dp类似,都能根据差别的屏幕密度进行适配,但sp还会根据用户设置的系统字体大小进行调整,因此更得当用作字体大小的单元。
in (inches, 英寸):英寸是一个标准的长度单元,常用于描述屏幕大小。
pt(points, 磅): 磅是一个屏幕物理长度单元,1磅等于1/72英寸。
mm (millimeters, 毫米):毫米也是一个屏幕物理长度单元。
AndroidManifest.xml 有四大组件,程序添加权限声明
MainActivity
res/layout 目次下的activity_main.xml
Project下的结构
- .gradle 文件夹:包罗Gradle构建系统天生的缓存文件和暂时文件。
- .idea 文件夹:包罗项目相关的IDE配置文件,如编译器设置、运行配置等。
- app 文件夹:是Android应用程序的主要代码和资源目次。
- - java 文件夹:包含Java
- 源代码文件。
- - res 文件夹:包含应用程序所需的资源文件,如布局文件、图像文件、字符串等。
- - AndroidManifest.xml 文件:包含应用程序的清单文件,定义了应用程序的基本信息、权限、组件、界面等。
复制代码
- test 文件夹:包罗单元测试的源代码和资源文件。
- androidTest 文件夹:包罗Android测试的源代码和资源文件。
- build.gradle 文件:定义了应用程序的构建配置,包罗依赖项、版本号等。
- proguard-rules.pro 文件:定义了肴杂规则,用于在发布时压缩、优化和肴杂应用程序的代码。
- build 文件夹:包罗构建天生的输出文件,如APK文件、中心文件等。
- gradle 文件夹:包罗Gradle构建系统的配置文件和插件。
- wrapper 文件夹:包罗Gradle的包装器文件,用于自动下载和管理Gradle的版本。
- .gitignore 版本控制
- build.gradle 文件:定义了项目级别的构建配置,如Gradle版本、插件等。
- gradle.properties 文件:包罗Gradle属性的配置文件。
- gradlew 和 gradlew.bat 文件:Gradle的下令行构建脚本,可在下令行界面中利用。
- settings.gradle 文件:定义了项目的模块和构建立置。
这是Android Studio项目的基本目次结构,此中最重要的部门是app 文件夹,它包罗了应用程序的源代码和资源文件。其他文件夹和文件用于项目的构建和配置。
二、开辟android时,部门库下载异常慢
2.1 项目中更换下载仓库
- maven { url 'https://maven.aliyun.com/repository/public/' }
- maven { url 'https://maven.aliyun.com/repository/google/' }
- maven { url 'https://maven.aliyun.com/repository/jcenter/' }
- maven { url 'https://maven.aliyun.com/repository/central/' }
复制代码
2.2 离线模式配置 Gradle
将 Gradle.zip 解压到 “C:\User\你的用户名.gradle\wrapper\dists” 下,最终路径为: “C:\User\你的用户名.gradle\wrapper\dists\gradle-7.4-bin” 和 “C:\User\你的用户名.gradle\wrapper\dists\gradle-8.0-bin”
三、Kotlin
代码(本篇Android项目不会涉及用kotlin创建文件,先先容后续再涉及)
3.1 变量
利用val(value 的简写)声明一个变量时,该变量被视为不可变的,即在初始赋值之后无法重新赋值。这类似于Java
中的final变量。
利用var(variable 的简写)声明一个变量时,该变量被视为可变的,即在初始赋值之后仍旧可以重新赋值。这类似于Java
中的非final变量。
Kotlin
中没有底子数据类型,只有封装的数字类型,你每定义的一个变量,着实 Kotlin
帮你封装了一个对象,这样可以包管不会出现空指针。
- # 显式地声明了变量a为Int类型
- val a: Int = 10
复制代码
3.2 函数
参数的声明格式是“参数名: 参数类型”,此中参数名也是可以随便定义的
- fun main() {
- println(fun1(1, 2))
- }
- fun fun1(num1:Int,num2: Int):Int{
- return num1+num2
- }
复制代码 3.3 条件控制
3.3.1 if条件语句
- var value = 0
- if (num1 > num2) {
- value = num1
- } else {
- value = num2
- }
复制代码 Kotlin
中的if语句相比于Java
有一个额外的功能,它是可以有返回值的
- val result = if (条件表达式) {
- // 如果条件为真,则返回这里的值
- } else {
- // 如果条件为假,则返回这里的值
- }
复制代码 例子
- fun fun1(num1: Int, num2: Int): Int {
- return if (num1 > num2) {
- num1
- } else {
- num2
- }
- }
复制代码- fun fun1(num1: Int, num2: Int) = if (num1 > num2) {
- num1
- } else {
- num2
- }
复制代码 再次
- val max = if (a > b) a else b
- fun fun1(num1: Int, num2: Int)= if (num1 > num2) num1 else num2
复制代码 3.3.2 when条件语句
这种直通式
- when (条件表达式) {
- 值1 -> {
- // 如果条件匹配值1,则执行这里的代码块
- }
- 值2 -> {
- // 如果条件匹配值2,则执行这里的代码块
- }
- else -> {
- // 如果条件都不匹配,则执行这里的代码块
- }
- }
复制代码- is关键字就是类型匹配的核心,相当于Java
- 中的instanceof关键字。
复制代码- when (num) {
- is Int -> println("number is Int")
- is Double -> println("number is Double")
- else -> println("number not support")
- }
复制代码 3.4 for-in循环
kotlin的while和Java
中的while循环没有任何区别
- fun main() {
- val range = 0..10
- for (i in range step 2) {
- println(i)
- }
- }
复制代码 利用step跳过区间内的元素
可以利用until关键字来创建一个左闭右开的区间,
downTo遍历降序区间
3.5 面向对象编程
- class Person {
- var name: String = ""
- var age=0
- fun show(){
- println("Name: $name, Age: $age")
- println(name +"is" + age + " years old.")
- }
- }
- fun main() {
- val p = Person()
- p.name = "Alice"
- p.age = 30
- p.show() // Output: Name: Alice, Age: 30
- }
复制代码 第一个打印语句利用了字符串模板( n a m e 和 name和 name和age),将属性name和age的值插入到输出语句中,打印出"Name: Alice, Age: 30"。
第二个打印语句利用了字符串拼接(name +“is” + age + " years old.“),将属性name、字符串"is”、属性age和字符串" years old.“拼接在一起,打印出"Alice is 30 years old.”。
3.5.1 继承
在Person类的前面加上open关键字就可以了
要让Student类继承Person类
在Java
中继承的关键字是extends,而在Kotlin
中是一个冒号
- open class Person {
- var name: String = ""
- var age=0
- fun show(){
- println("Name: $name, Age: $age")
- println(name +"is" + age + " years old.")
- }
- }
- class Student :Person(){
- var grade:Int=0
- fun shows(){
- println("Name: $name, Age: $age, Grade: $grade")
- }
- }
- fun main() {
- val s=Student()
- s.name="Bob"
- s.age=20
- s.grade=3
- s.shows() //Output: Name: Bob, Age: 20, Grade: 3
- }
复制代码 同样的我们也可以继承于Java
java
- public class cc {
- private String name;
- private int age;
- public cc() {
- }
- public cc(String name, int age) {
- this.name = name;
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- }
复制代码 kotlin
- class Student : cc() {
- var grade: Int = 0
- fun shows() {
- println("Name: $name, Age: $age, Grade: $grade")
- }
- }
- fun main() {
- val s = Student()
- s.name = "Bob"
- s.age = 20
- s.grade = 3
- s.shows() //Output: Name: Bob, Age: 20, Grade: 3
- }
复制代码 Open 继承
- 如果你希望在 Kotlin
- 中继承某个 Java
- 类,
- 需要手动在 Kotlin
- 代码中为该类添加 open 修饰符,
- 以明确表明该类是可继承的。
- 如果一个类不是专门为继承而设计的,
- 那么就应该主动将它加上final声明,禁止它可以被继承。
复制代码 在 Kotlin
中,默认情况下,所有类都是 final 的,即它们不能被继承。相比之下,Java
中的类默认是可以被继承的,除非利用了 final 关键字显式地克制继承。
当你在 Kotlin
中继承一个 Java
类时,Kotlin
并不会隐式地为 Java
类添加 open 修饰符。这是因为 Kotlin
不会假设 Java
类的设计者希望允许继承,因此需要在 Kotlin
中显式地利用 open 关键字来指示类是可继承的。
我们观察一下用Java
和Kotlin
分别创建的安卓项目的主活动
四、活动(本篇以Java
代码,先行先容)
- 活动是安卓应用的主要组件之一,安卓中的活动(Activity)是指用户交互界面的一部分,它通常对应应用程序中的一个屏幕。
复制代码 通过管理活动的生命周期(创建、启动、恢复、暂停、停止和销毁),我们作为开辟者可以控制活动的状态和行为。
- 活动之间可以通过意图(Intent)进行跳转和通信。
复制代码 把各种控件和视图,按钮、文本框、图像等联系起来,启动其他活动或从其他活动返回,用户可以在差别的界面之间进行切换和交互。
总之,活动作为安卓应用程序的一个重要组件,负责用户界面的展示和交互处理,使得用户可以与应用程序进行互动。
4.1 创建活动
在com.example.hellowolrd包下 ->New ->Activity ->Empty Activity
我们的两个活动:
4.1.1 Android Studio 会自动在AndroidManifest文件中注册
我们打开app/src/main/AndroidManifest.xml文件代码如下所示:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools" >
- <application
- android:allowBackup="true"
- android:dataExtractionRules="@xml/data_extraction_rules"
- android:fullBackupContent="@xml/backup_rules"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:roundIcon="@mipmap/ic_launcher_round"
- android:supportsRtl="true"
- android:theme="@style/Theme.MyApplication"
- tools:targetApi="31" >
-
- <activity
- android:name=".OtherActivity"
- android:exported="false" />
-
- <activity
- android:name=".MainActivity"
- android:exported="true" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
-
- </application>
- </manifest>
复制代码 4.1.2 活动中利用Toast
Toast会在屏幕上表现一段时间,用于在应用程序的界面上表现一条简短的消息,然后自动消散。
写法
- // 要显示的消息文本
- String message = "Hello, Toast!";
- // 创建并显示Toast
- Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
复制代码 当调用makeText()方法,并通过链式调用show()方法来创建并表现Toast。getApplicationContext()是一种获取当前活动上下文的方法,可以在活动中利用。
需要留意的是,Toast的 makeText()方法返回的是一个Toast对象,可以通过调用show()方法来表现。
在调用show()方法后,Toast会在屏幕上表现一段时间,然后自动消散。
Java
Kotlin
- val button1: Button = findViewById(R.id.button12)
- button1.setOnClickListener {
- Toast.makeText(this, "Yes", Toast.LENGTH_LONG).show() }
复制代码 LENGTH_SHORT=0
短时间的Toast
LENGTH_LONG = 1
长时间的Toast
4.1.3 销毁活动
延迟销毁
- package com.example.myapplication;
- import androidx.appcompat.app.AppCompatActivity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.view.Menu;
- import android.view.MenuInflater;
- import android.view.MenuItem;
- import android.view.View;
- import android.widget.Button;
- import android.widget.Toast;
- public class OtherActivity extends AppCompatActivity {
- private Button button1;
- private Handler handler = new Handler();
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_other);
- button1 = findViewById(R.id.button1);
- button1.setOnClickListener(v -> {
- Toast.makeText(this, "TestOther", Toast.LENGTH_SHORT).show();
- handler.postDelayed(() -> finish(), 2000);
- });
- }
- }
复制代码
finishmp4
4.2 Intent 跨越活动
4.2.1 表现的Intent
先创建一个新的活动,并在其绑定创建的layout文件之中简朴的放置一个按钮,目的是在跳转的时候直观的有显着的体验
- package com.example.myapplication;
- import androidx.appcompat.app.AppCompatActivity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.os.Handler;
- import android.view.Menu;
- import android.view.MenuInflater;
- import android.view.MenuItem;
- import android.view.View;
- import android.widget.Button;
- import android.widget.Toast;
- public class OtherActivity extends AppCompatActivity {
- private Button button1;
- private Handler handler = new Handler();
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_other);
- button1 = findViewById(R.id.button1);
- button1.setOnClickListener(v -> {
- Toast.makeText(this, "TestOther", Toast.LENGTH_SHORT).show();
- Intent intent = new Intent(OtherActivity.this, SecondActivity.class);
- // 在延迟2秒后执行 finish() 和 startActivity()
- handler.postDelayed(() -> {
- finish();
- startActivity(intent);
- }, 2000);
- });
- }
- }
复制代码
Intent跳转其他活动
4.2.2 隐式Intent
我们在当前文件在指定出来我们可以转向的动作名称
- button1.setOnClickListener(v -> {
- Toast.makeText(this, "TestOther", Toast.LENGTH_SHORT).show();
- Intent intent = new Intent("x111");
- startActivity(intent);
- });
复制代码 我们还可以跳转到其他地方,如网页(这和我们平时的app如出一辙)
- button1.setOnClickListener(v-> {
- Intent intent =new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse("http://www.baidu.com"));
- startActivity(intent);
- });
复制代码 点击按钮后,创建了一个意图(Intent)并设置了其动作(Action)为Intent.ACTION_VIEW,同时指定了要检察的数据是一个URL,即http://www.baidu.com。系统收到这个意图后,会识别出这是一个网页链接,并自动利用默认的Web欣赏器打开百度网站页面。同样地,如果intent指向的是一个电话号码大概一个本地文件(如图片、视频等),则相应程序(拨号器或媒体播放器等)会被唤起以处理这些数据。
4.2.3Action 和 Category
- 在Android中,Action 和 Category 是 Intent 的重要组成部分,
- 它们用于定义和过滤应用程序间交互的行为意图(Intent)。
复制代码 Action 描述了Intent的主要动作或目的。例如,发送一个电子邮件可以利用 ACTION_SEND 动作;打开网页可以利用 ACTION_VIEW 动作等。
Category 为Intent添加了额外的上下文信息,进一步描述了Intent的应用场景或意图所属的种别
一个Intent不但需要定义一个动作(如ACTION_MAIN),还需要至少一个种别(如CATEGORY_LAUNCHER),这样才能正确地匹配到相应的组件并触发相应的行为。在AndroidManifest.xml文件中,开辟者会在 标签内为Activity声明它可以相应哪些动作和种别组合。
4.2.4 通报给下一个活动数据
(1)发送活动方
- // 传递给下一个活动数据
- button1.setOnClickListener(v -> {
- String data = "你会魔法吗✧(≖ ◡ ≖✿)";
- Intent intent = new Intent(OtherActivity.this, SecondActivity.class);
- intent.putExtra("exdata", data);
- startActivity(intent);
- });
复制代码 (2)担当活动方
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_second);
- Intent intent =getIntent();
- String data =intent.getStringExtra("exdata");
- Log.d("Sec",data);
- }
复制代码 (3)打开日志Logcat
4.2.5 返回数据给上一个活动
(1)副活动中
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_second);
- Intent intent =getIntent();
- String data =intent.getStringExtra("exdata");
- Log.d("Sec",data);
- Button buttonxx=findViewById(R.id.buttonxx);
- buttonxx.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent =new Intent();
- intent.putExtra("resdata","hello_你会魔法吗✧(≖ ◡ ≖✿)");
- setResult(RESULT_OK,intent);
- finish();
- }
- });
- }
复制代码 (2)主活动
- // 传递给下一个活动数据
- button1.setOnClickListener(v -> {
- String data = "你会魔法吗✧(≖ ◡ ≖✿)";
- Intent intent = new Intent(OtherActivity.this, SecondActivity.class);
- intent.putExtra("exdata", data);
- startActivityForResult(intent,1);
- });
复制代码 留意 startActivityForResult方法重写
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (requestCode == 1 && resultCode == RESULT_OK) {
- String reData = data.getStringExtra("resdata");
- // 在这里处理接收到的数据 reData
- Log.d("OtherActivity", reData);
- }
- }
复制代码 4.3 安卓 Activity生命周期
返回栈(back stack)是Android系统用于管理Activity的堆栈结构。当您启动一个新的Activity时,它会被放置在返回栈的顶部,并成为当前正在运行的Activity。如果按下返回按钮或调用finish()方法关闭当前Activity,那么前一个Activity将从返回栈中弹出并恢复到前台。
栈是一种后进先出(LIFO)的数据结构,用于管理活动(Activity)在Android应用程序中的顺序。当启动一个新活动时,它会被添加到返回栈的栈顶位置,并成为当前正在运行的活动。而当按下返回按钮或调用finish()方法销毁当前活动时,位于栈顶的活动将从栈中弹出,然后前一个入栈的活动将成为新的栈顶,并重新表现给用户。
4.3.1 概述
Android Activity生命周期的各个状态及其转换关系
- 创建阶段
- onCreate(Bundle savedInstanceState): 活动第一次被创建时调用,进行初始化工作。
- onStart(): 表现活动正在启动,即将变为可见状态。
- onResume(): 活动已开始与用户交互,并处于运行状态。
- 运行阶段
- 在onResume()之后,Activity处于运行状态。
- 暂停阶段
- onPause(): 当有新的Activity启动并覆盖当前Activity或当前Activity不再位于前台时调用。
- 停止阶段
- onStop(): 当Activity完全不可见时调用。
- 恢复/重启阶段
- onRestart(): 如果Activity之前被停止而现在重新回到前台,会先调用此方法,然后经历onStart()和onResume()。
- 销毁阶段
- onDestroy(): 在Activity被系统决定彻底销毁前调用,用于释放资源。
- 其他回调方法:
- onSaveInstanceState(Bundle outState): 保存暂时性数据以备在Activity重修时恢复。
- onRestoreInstanceState(Bundle savedInstanceState): 用于还原之前保存的状态。
4.3.2 过程
留意如果我们启动的时候不是这个想要看的内容,大概和主启动活动有关
我们在
修改
(1)创建活动,并简朴的xml配个botton
(2)主活动
- package com.example.myapplication;
- import androidx.appcompat.app.AppCompatActivity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.View;
- import android.widget.Button;
- import android.widget.Toast;
- public class MainActivity extends AppCompatActivity {
- public static final String TAG = "MainActivity";
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- Button startNormalActivity = findViewById(R.id.ShowActivity);
- Button startDialogActivity = findViewById(R.id.ShowActivity2);
- startNormalActivity.setOnClickListener(v -> {
- Intent intent = new Intent(MainActivity.this, ShowActivity.class);
- startActivity(intent);
- });
- startDialogActivity.setOnClickListener(v -> {
- Intent intent = new Intent(MainActivity.this, ShowActivity2.class);
- startActivity(intent);
- });
- }
- @Override
- protected void onStart() {
- super.onStart();
- Log.d(TAG, "onStart");
- }
- @Override
- protected void onResume() {
- super.onResume();
- Log.d(TAG, "onResume");
- }
- @Override
- protected void onPause() {
- super.onPause();
- Log.d(TAG, "onPause");
- }
- @Override
- protected void onStop() {
- super.onStop();
- Log.d(TAG, "onStop");
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- Log.d(TAG, "onDestroy");
- }
- @Override
- protected void onRestart() {
- super.onRestart();
- Log.d(TAG, "onRestart");
- }
- }
复制代码 (3)启动假造机,看日志Logcat
我们需要点击任意一个按钮,并回退(返回键)
观察日志的内容
4.2.4 在 Android 中,onRestart() 方法和 onDestroy() 方法的调用是由系统根据 Activity 的生命周期状态变化来决定的。
onRestart():
当用户从后台返回到前台时(即通过按“近来应用”按钮或HOME键离开Activity后再次回到该Activity),Activity 会经历 onPause() -> onStop() -> onRestart() 这样的生命周期变化。因此,如果你的日志中没有表现 onRestart(),大概是因为你直接启动了 Activity 而没有先将其推入后台,大概是在后台被系统回收掉了。
onDestroy():
onDestroy() 在 Activity 终止之前调用,通常发生在系统资源告急需要释放 Activity、应用程序自身调用了 finish() 方法大概是整个应用程序进程被终止等情况。
如果你的 Activity 是程序的主入口,并且你没有手动结束它大概系统没有强制结束它,那么在整个应用程序运行期间,onDestroy() 大概不会被调用。
如果你在测试时仅仅是在应用之间切换大概只是简朴地打开并检察 Activity,而没有做进一步的操作导致 Activity 销毁,则 onDestroy() 不会被调用。
对于 onRestart(),先让 Activity 进入后台(如点击 Home 按钮或打开其他应用),然后再重新启动这个 Activity,这时应该能看到日志输出。
对于 onDestroy(),可以通过模仿系统资源告急环境(例如利用开辟者选项中的“不保存活动”功能)大概在代码中显式调用 finish() 来销毁当前 Activity,从而触发 onDestroy() 日志记录
4.4 活动被回收了怎么办(GPT)
在Android中,当系统资源告急时,Activity大概会因内存不足而被回收(destroy)。为应对这种情况并确保应用能够正确恢复用户界面和数据,可以采用以下几种方法:
4.4.1. 保存和恢复数据
在onSaveInstanceState(Bundle outState)方法中保存关键数据,以便在Activity重新创建时通过onCreate(Bundle savedInstanceState)或onRestoreInstanceState(Bundle savedInstanceState)恢复这些数据。
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- // 保存数据到Bundle
- outState.putInt("key", someImportantValue);
- }
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- if (savedInstanceState != null) {
- // 恢复数据
- int importantValue = savedInstanceState.getInt("key");
- // 使用恢复的数据...
- }
- }
-
复制代码 4.4.2. 利用ViewModel
借助Android架构组件中的ViewModel类,可以在配置更改或Activity生命周期变化时保持UI相关数据的长期性。纵然Activity被销毁,ViewModel中的数据也能保存下来。
- public class MyViewModel extends ViewModel {
- private MutableLiveData<Integer> someLiveData;
- public MutableLiveData<Integer> getSomeLiveData() {
- if (someLiveData == null) {
- someLiveData = new MutableLiveData<>();
- // 初始化数据...
- }
- return someLiveData;
- }
- }
- public class MainActivity extends AppCompatActivity {
- private MyViewModel viewModel;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- viewModel = new ViewModelProvider(this).get(MyViewModel.class);
- viewModel.getSomeLiveData().observe(this, value -> {
- // 更新UI...
- });
- }
- }
-
复制代码 4.4.3. 长期化数据
对于需要恒久保存的重要数据,可将其长期化至数据库、SharedPreferences或其他文件存储中。
4.4.4. 处理返回结果
如果Activity是通过startActivityForResult启动的,则需在onActivityResult中处理结果,即便Activity在获取结果前被销毁过。
4.5 启动模式
安卓的启动模式主要有以下几种:
- standard(标准模式):默认的启动模式,每次启动都会创建一个新的实例。
- singleTop(单顶部模式):如果目标Activity已经在任务栈的顶部,则不会创建新的实例,而是调用目标Activity的onNewIntent()方法。
- singleTask(单任务模式):只能存在一个实例,如果该实例已经存在,则将其调至栈顶,并扫除其上方所有Activity。
- singleInstance(单独实例模式):类似于singleTask,但具有更高的隔离性,即该Activity只能与自己在一个任务栈中存在。
这些启动模式可以通过在AndroidManifest.xml文件中利用<activity>标签来指定 android: launchMode。每个Activity可以选择得当自身需求的启动模式。
4.5.1 standard (默认)
standard(标准模式)是Android中默认的启动模式。在该模式下,每次启动Activity都会创建一个新的实例,并将其放入任务栈中。
当我们通过Intent启动一个Activity时,系统会创建该Activity的新实例,并将其放置在当前任务栈的顶部。
如果目标Activity已经存在于任务栈中,则系统会创建一个新的实例并将其放在之前实例之上。
- 在标准模式下,多个相同类型的Activity可以同时存在于同一任务栈中。
- 每个实例都是独立的,并且它们彼此没有直接影响。
复制代码 例如,假设我们有一个应用程序包罗两个Activity:Activity A和Activity B。
当我们从A启动B时,系统会创建一个新的B实例并将其放入任务栈顶部。
如果我们再次从A启动B,则会创建另一个B实例并放在之前实例之上。
standard模式
每次的新实例
4.5.2 singleTop(对于当前非栈顶活动来说启动时会创建出一个新的实例)
singleTop是一种Activity启动模式,它指定一个Activity在栈顶时不会被重复创建,而是复用已存在的实例。如果要启动的Activity已经位于栈顶,则不会创建新的实例,而是调用其onNewIntent()方法进行更新。如果要启动的Activity不在栈顶,则会创建新的实例并将其放置在栈顶。
利用singleTop模式可以避免创建多个相同的Activity实例,提高了应用程序的性能和效率。这种模式得当用于处理独立且相互独立的任务或页面,比如检察文章、打开设置等。
在AndroidManifest.xml中可以通过设置launchMode属性为"singleTop"来指定该Activity的启动模式为singleTop。例如:
- <activity android:name=".YourActivity"
- android:launchMode="singleTop">
- </activity>
复制代码
需要留意的是,在利用singleTop模式时,如果有其他Activity位于目标Activity之上,并且这些中心层级的Activity也是利用了singleTop大概singleTask启动模式,则依然会创建新的实例。因此,在设计应用程序架构时需谨慎选择合适的启动模式以满足需求。
就是在这一个页面上,不会再次创建
singleTop
4.5.3 singleTask
在Android中,singleTask是一种启动模式,它定义了一个Activity的任务栈只能有一个实例。当利用singleTask启动模式时,如果已经存在该Activity的实例,则系统会将该任务栈上位于该Activity之上的其他所有Activity扫除掉,并调用该Activity的onNewIntent()方法来通报新的意图。
具体来说,利用singleTask启动模式时,如果要启动一个Activity:
- 如果当前任务栈中不存在该Activity的实例,则会创建一个新的实例,并将其入栈。
- 如果当前任务栈中存在该Activity的实例,则会销毁该实例之上的所有其他Activity,并调用现有实例的onNewIntent()方法。
这种启动模式常用于作为应用程序的主界面大概入口页面,确保每次打开应用都会进入同一个特定界面。
结构
- package com.example.myapplication;
- import androidx.appcompat.app.AppCompatActivity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- public class FirstActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Log.d("FirstActivity", this.toString());
- setContentView(R.layout.activity_first);
- Button button =findViewById(R.id.button);
- button.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent =new Intent(FirstActivity.this, SecondActivity.class);
- startActivity(intent);
- }
- });
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- Log.d("fir","onfirDestroy");
- }
- }
复制代码 和
- package com.example.myapplication;
- import androidx.appcompat.app.AppCompatActivity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.util.Log;
- import android.widget.Button;
- public class SecondActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Log.d("SecondActivity", this.toString());
- setContentView(R.layout.activity_second);
- Button button=findViewById(R.id.button2);
- button.setOnClickListener(v -> {
- Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
- startActivity(intent);
- });
- }
- @Override
- protected void onRestart() {
- super.onRestart();
- Log.d("sec","onRestart");
- }
- }
复制代码 在xml中
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |