安卓Android ·移动应用开发 创建第一个Android项目

文章目录


可以先行看我的这篇 《安卓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/colorPrimaryDark</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 有四大组件,程序添加权限声明

在这里插入图片描述
MainActivity
在这里插入图片描述
res/layout 目录下的activity_main.xml
在这里插入图片描述

Project下的结构

在这里插入图片描述

  1. .gradle 文件夹:包含Gradle构建系统生成的缓存文件和临时文件。

  2. .idea 文件夹:包含项目相关的IDE配置文件,如编译器设置、运行配置等。

  3. app 文件夹:是Android应用程序的主要代码和资源目录。

  4.  - java 文件夹:包含Java源代码文件。
    
     - res 文件夹:包含应用程序所需的资源文件,如布局文件、图像文件、字符串等。
    
     - AndroidManifest.xml 文件:包含应用程序的清单文件,定义了应用程序的基本信息、权限、组件、界面等。
    
    • test 文件夹:包含单元测试的源代码和资源文件。

    • androidTest 文件夹:包含Android测试的源代码和资源文件。

    • build.gradle 文件:定义了应用程序的构建配置,包括依赖项、版本号等。

    • proguard-rules.pro 文件:定义了混淆规则,用于在发布时压缩、优化和混淆应用程序的代码。

  5. build 文件夹:包含构建生成的输出文件,如APK文件、中间文件等。

  6. gradle 文件夹:包含Gradle构建系统的配置文件和插件。

    • wrapper 文件夹:包含Gradle的包装器文件,用于自动下载和管理Gradle的版本。

    • .gitignore 版本控制

    • build.gradle 文件:定义了项目级别的构建配置,如Gradle版本、插件等。

    • gradle.properties 文件:包含Gradle属性的配置文件。

    • gradlew 和 gradlew.bat 文件:Gradle的命令行构建脚本,可在命令行界面中使用。

  7. 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和 nameage),将属性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分别创建的安卓项目的主活动
Kotlin

在这里插入图片描述

Java

在这里插入图片描述

四、活动(本篇以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 销毁活动

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

我们在当前文件在指定出来我们可以转向的动作名称
在这里插入图片描述

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生命周期的各个状态及其转换关系
在这里插入图片描述

  1. 创建阶段

    • onCreate(Bundle savedInstanceState): 活动第一次被创建时调用,进行初始化工作。
    • onStart(): 表示活动正在启动,即将变为可见状态。
    • onResume(): 活动已开始与用户交互,并处于运行状态。
  2. 运行阶段

    • onResume()之后,Activity处于运行状态。
  3. 暂停阶段

    • onPause(): 当有新的Activity启动并覆盖当前Activity或当前Activity不再位于前台时调用。
  4. 停止阶段

    • onStop(): 当Activity完全不可见时调用。
  5. 恢复/重启阶段

    • onRestart(): 如果Activity之前被停止而现在重新回到前台,会先调用此方法,然后经历onStart()onResume()
  6. 销毁阶段

    • onDestroy(): 在Activity被系统决定彻底销毁前调用,用于释放资源。
  7. 其他回调方法:

    • 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 回收与恢复策略

在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 启动模式

安卓的启动模式主要有以下几种:

  1. standard(标准模式):默认的启动模式,每次启动都会创建一个新的实例。
  2. singleTop(单顶部模式):如果目标Activity已经在任务栈的顶部,则不会创建新的实例,而是调用目标Activity的onNewIntent()方法。
  3. singleTask(单任务模式):只能存在一个实例,如果该实例已经存在,则将其调至栈顶,并清除其上方所有Activity。
  4. 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:

  1. 如果当前任务栈中不存在该Activity的实例,则会创建一个新的实例,并将其入栈。
  2. 如果当前任务栈中存在该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中
在这里插入图片描述

  • 26
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Android Studio 是一款由谷歌开发的集成开发环境(IDE),用于开发 Android 应用程序。在 Android Studio 中,界面跳转和数据传输是移动应用开发中两个重要的方面。 界面跳转: 1. 使用 Intent:在 Android 中,Intent 是一个非常重要的类,用于启动一个 Activity。通过使用 Intent,你可以从一个 Activity 跳转到另一个 Activity。Intent 包含一个动作(action)和一个或多个数据(data),这决定了 Activity 的类型和需要的数据。 2. 使用导航架构:Android 支持多种导航架构,如 Tab 组件、Drawer、ViewPager 等,可以让你轻松地实现页面间的跳转。例如,你可以创建一个 Drawer 组件,其中包含多个选项,用户可以通过点击这些选项在不同的页面之间进行跳转。 3. 使用 Fragment:Fragment 是 Android 中的一个重要组件,用于构建应用程序的界面。Fragment 可以与多个视图组件(如 ViewPager 或 ListView)关联,允许你以更灵活的方式创建和管理界面。你可以将 Fragment 添加到 Activity 中,并在需要时进行跳转。 数据传输: 1. 使用 Intent extras:Intent 提供了一个机制,可以将数据从一个 Activity 或 Service 传递到另一个。你可以使用 Intent 的 extras 字段来传递数据,例如使用 Bundle 类来存储键值对。 2. 使用 SharedPreferences:SharedPreferences 是 Android 提供的一种轻量级存储机制,用于保存应用程序的短期配置和数据。SharedPreferences 可以用于保存简单的数据类型,如字符串、布尔值或整数值。 3. 使用网络通信:如果你的应用程序需要与服务器进行数据交互,你可能需要使用网络通信技术。Android 支持多种网络通信方式,如 HTTP、HTTPS 和蓝牙通信等。你可以使用 Java 的 HttpURLConnection 类或第三方库(如 OkHttp)来实现网络通信。 4. 使用数据库:如果你的应用程序需要存储大量数据,你可能需要使用数据库。Android 支持 SQLite 数据库,它是一种轻量级的关系型数据库,可以用于存储和检索应用程序的数据。 总的来说,Android Studio 提供了一些强大的工具和功能,可以帮助你实现移动应用开发中的界面跳转和数据传输。你可以根据具体的需求和场景选择合适的技术和方法来实现这些功能。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你会魔法吗✧(≖ ◡ ≖✿)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值