安卓Android ·移动应用开辟 创建第一个Android项目
可以先行看我的这篇 《安卓Android入门》一、创建第一个Android项目
1.1 准备Android Studio
https://i-blog.csdnimg.cn/blog_migrate/03b69742cc5a4124004df1ddca1ce535.png
选择
https://i-blog.csdnimg.cn/blog_migrate/b33cc1641157f03ff7f45d11730eb76c.png
写信息
https://i-blog.csdnimg.cn/blog_migrate/e0092df011679eb77296a9cc1394b99e.png
等待构建Gradle
https://i-blog.csdnimg.cn/blog_migrate/56baf58affed85f4cace2ddea5b53c72.png
可以选择我们的模仿器,甚至我们可以通过手机屏幕共享的方式,把手机的开辟者模式打开等操作,下载到本机手机之中,可以0隔断的感受,程序之美。
https://i-blog.csdnimg.cn/blog_migrate/ebd24e89cda872bed1c26215459d98f0.png
https://i-blog.csdnimg.cn/blog_migrate/8ab11191061a37c1fbbcf7ddaef2b82a.png
https://i-blog.csdnimg.cn/blog_migrate/87c13a5d84f2738e9c8d79751428738f.png
1.2 运行程序
https://i-blog.csdnimg.cn/blog_migrate/2ad2fa91d232eac734fd6631b80c088d.png
1.3 程序结构是什么
app下的结构
这种的结构化的项目简便明了,提高开辟效率和代码质量
https://i-blog.csdnimg.cn/blog_migrate/82af7bfa073c456f84324a3382dd7ab5.png
build - 编译时自动天生的文件
libs - 第三方jar包放在libs目次下
java - 放置所需Java
代码,自动天生了一个MainActivity 文件
1.3.2 res - 子目次(所有图片、布局、字符串等资源)
https://i-blog.csdnimg.cn/blog_migrate/21b675ed7778e3fa3c45917c60c13d79.png
调用方式:
[ 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等,并在制作程序时提供几个差别分辨率的版本,是为了适应差别设备的屏幕密度和分辨率
https://i-blog.csdnimg.cn/blog_migrate/c4fafac2a7d7184976812dd0dafc8c24.png
打开我们的子目次
https://i-blog.csdnimg.cn/blog_migrate/1c8ac21adc1727a98eb409362730f4a1.png
这内里就是我们配置的字符串,调用利用,不用全局在中出现相同的多次构建。在res/values/目次中的strings.xml文件中定义字符串
https://i-blog.csdnimg.cn/blog_migrate/323eb063d9e12e615dd042409c4f02cf.png
怎么构建
在XML中通过@string/app_name可以获得该字符串的引用。
https://i-blog.csdnimg.cn/blog_migrate/d9a35ad2824f2dde5fc6bedad31886f8.png
最终
https://i-blog.csdnimg.cn/blog_migrate/2dc5e7e9f567ce08787f5034313f774e.png
点击可以替换
https://i-blog.csdnimg.cn/blog_migrate/b2d64c6d850b07027e3dd36acdea3d2d.png
主题是包罗一种或多种的格式化属性聚集,可改变窗体的样式,对整个应用或某个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布局文件中调用颜色资源文件
@color/colorPrimary
颜色值必须以“#”开头,“#”后面表现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 有四大组件,程序添加权限声明
https://i-blog.csdnimg.cn/blog_migrate/0f73b01ba6375e350f43356609368fc9.png
MainActivity
https://i-blog.csdnimg.cn/blog_migrate/a8e89f2b81c3c984f2aaf2a04980b9ec.png
res/layout 目次下的activity_main.xml
https://i-blog.csdnimg.cn/blog_migrate/33ab1e584985ca02847acde2e5056faf.png
Project下的结构
https://i-blog.csdnimg.cn/blog_migrate/cc735aded385d24e8c38ec7d91349790.png
[*] .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/' }
https://i-blog.csdnimg.cn/blog_migrate/40d748746ebd4e6221d22c5ca86bd726.png
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创建文件,先先容后续再涉及)
https://i-blog.csdnimg.cn/blog_migrate/200546cbcdf2251a8946f7fbb7ce251e.png
https://i-blog.csdnimg.cn/blog_migrate/4b3fcd8b0cffca4c3793bee058430c7f.png
3.1 变量
利用val(value 的简写)声明一个变量时,该变量被视为不可变的,即在初始赋值之后无法重新赋值。这类似于Java
中的final变量。
利用var(variable 的简写)声明一个变量时,该变量被视为可变的,即在初始赋值之后仍旧可以重新赋值。这类似于Java
中的非final变量。
Kotlin
中没有底子数据类型,只有封装的数字类型,你每定义的一个变量,着实 Kotlin
帮你封装了一个对象,这样可以包管不会出现空指针。
# 显式地声明了变量a为Int类型
val a: Int = 10
https://i-blog.csdnimg.cn/blog_migrate/0de4ca14afc7342c2225690e44bdbe06.png
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跳过区间内的元素
https://i-blog.csdnimg.cn/blog_migrate/fe2a59fbba81dcf335fee4252600ffdc.png
可以利用until关键字来创建一个左闭右开的区间,
https://i-blog.csdnimg.cn/blog_migrate/45ed7c27b09a0e9505b5587e1d79c606.png
downTo遍历降序区间
https://i-blog.csdnimg.cn/blog_migrate/c8a3453a0804f6e5ce98411bc2803469.png
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
https://i-blog.csdnimg.cn/blog_migrate/f24727738f55d66f21923827580e7482.png
java
public class cc {
private String name;
privateint 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
分别创建的安卓项目的主活动
Kotlin
https://i-blog.csdnimg.cn/blog_migrate/7e2843d2d0daa9f19944f302d2dbd8bd.png
Java
https://i-blog.csdnimg.cn/blog_migrate/74fd6052c3966d2e6c70696c3214457d.png
四、活动(本篇以Java
代码,先行先容)
活动是安卓应用的主要组件之一,安卓中的活动(Activity)是指用户交互界面的一部分,它通常对应应用程序中的一个屏幕。
通过管理活动的生命周期(创建、启动、恢复、暂停、停止和销毁),我们作为开辟者可以控制活动的状态和行为。
活动之间可以通过意图(Intent)进行跳转和通信。
把各种控件和视图,按钮、文本框、图像等联系起来,启动其他活动或从其他活动返回,用户可以在差别的界面之间进行切换和交互。
总之,活动作为安卓应用程序的一个重要组件,负责用户界面的展示和交互处理,使得用户可以与应用程序进行互动。
4.1 创建活动
在com.example.hellowolrd包下 ->New ->Activity ->Empty Activity
https://i-blog.csdnimg.cn/blog_migrate/3fa741049b437bcb05e305a9d241e53c.png
我们的两个活动:
https://i-blog.csdnimg.cn/blog_migrate/b5b2a2fc9c8acd7668b24792ec17d487.png
4.1.1 Android Studio 会自动在AndroidManifest文件中注册
我们打开app/src/main/AndroidManifest.xml文件代码如下所示:
https://i-blog.csdnimg.cn/blog_migrate/46fabc3caa826a26dc4cd54b2c483f7b.png
<?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
https://i-blog.csdnimg.cn/blog_migrate/21c132dbb6ed86c23630f3566396b733.png
Kotlin
https://i-blog.csdnimg.cn/blog_migrate/7b82af1d11739f0e044d497c100331ad.png
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 销毁活动
Activity类提供了一个finish()
延迟销毁
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
我们在当前文件在指定出来我们可以转向的动作名称
https://i-blog.csdnimg.cn/blog_migrate/7ec4fdfc418ec85132171931dbeee846.png
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指向的是一个电话号码大概一个本地文件(如图片、视频等),则相应程序(拨号器或媒体播放器等)会被唤起以处理这些数据。
https://i-blog.csdnimg.cn/blog_migrate/78f68ffb13095f6a8b124c9031b563a2.png
https://i-blog.csdnimg.cn/blog_migrate/5fee373a444aa7595a218862928d0c1d.png
4.2.3Action 和 Category
在Android中,Action 和 Category 是 Intent 的重要组成部分,
它们用于定义和过滤应用程序间交互的行为意图(Intent)。
Action 描述了Intent的主要动作或目的。例如,发送一个电子邮件可以利用 ACTION_SEND 动作;打开网页可以利用 ACTION_VIEW 动作等。
Category 为Intent添加了额外的上下文信息,进一步描述了Intent的应用场景或意图所属的种别
https://i-blog.csdnimg.cn/blog_migrate/a12011590f6809ecf3156b7db0c11206.png
一个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
https://i-blog.csdnimg.cn/blog_migrate/67f0a3ccb596873e47ad82d701fa1450.png
4.2.5 返回数据给上一个活动
https://i-blog.csdnimg.cn/blog_migrate/b3122761c6411960560464d2ad439f1e.png
(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 概述
https://i-blog.csdnimg.cn/blog_migrate/7ecb9b76f0577f557aa89949e4f76506.png
Android Activity生命周期的各个状态及其转换关系
https://i-blog.csdnimg.cn/blog_migrate/660c8fd8764e92115671e73be6fbcd25.png
[*] 创建阶段
[*]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 过程
留意如果我们启动的时候不是这个想要看的内容,大概和主启动活动有关
我们在https://i-blog.csdnimg.cn/blog_migrate/fbbd1546e50f72f02874823e4d203f78.png
修改
https://i-blog.csdnimg.cn/blog_migrate/33981e18976ee559dc756bd9048c1fed.png
(1)创建活动,并简朴的xml配个botton
https://i-blog.csdnimg.cn/blog_migrate/c1d28a13fefc9e997d9ec60cde8ea7fb.png
(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
我们需要点击任意一个按钮,并回退(返回键)
观察日志的内容
https://i-blog.csdnimg.cn/blog_migrate/c0a72bf55001d8ec0c8dfd2ebf01c951.png
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 回收与恢复策略
在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模式
https://i-blog.csdnimg.cn/blog_migrate/c2f4cf631167d97ff859cfd036c14277.png
每次的新实例
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>
https://i-blog.csdnimg.cn/blog_migrate/1abb513a22d7fb4f67fec100529db046.png
需要留意的是,在利用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()方法。
这种启动模式常用于作为应用程序的主界面大概入口页面,确保每次打开应用都会进入同一个特定界面。
结构
https://i-blog.csdnimg.cn/blog_migrate/bc87bb683330104c49d683b396a1abc2.png
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中
https://i-blog.csdnimg.cn/blog_migrate/633a3cca100cd591e4cd088e5edb3946.png
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]