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

打印 上一主题 下一主题

主题 986|帖子 986|积分 2958

可以先行看我的这篇 《安卓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
代码调用 ->
  1. getResources().getDrawable(R.mipmap.ic_launcher);//调用mipmap文件夹中资源文件
  2. getResources().getDrawable(R.drawable,icon); //调用以drawable开头的文件夹中的资源文件
复制代码
[ 2 ] 通过XML布局调用
  1. @mipmap/ic_launcher //调用mipmap文件夹中的资源文件
  2. @drawable/icon //调用以 drawable开头的文件夹中的资源文件
复制代码
  我们应该创建差别分辨率的目次,如drawable-hdpi、drawable-xhdpi、drawable-xxhdpi等,并在制作程序时提供几个差别分辨率的版本,是为了适应差别设备的屏幕密度和分辨率

  打开我们的子目次

这内里就是我们配置的字符串,调用利用,不用全局在中出现相同的多次构建。在res/values/目次中的strings.xml文件中定义字符串

怎么构建
在XML中通过@string/app_name可以获得该字符串的引用。

最终

点击可以替换

主题是包罗一种或多种的格式化属性聚集,可改变窗体的样式,对整个应用或某个Activity存在全局性影响。
在res/values目次下的styles.xml文件中
  1. <resources>
  2.         <!-- Base application theme.-->
  3.         <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
  4.                 <!-- Customize your theme here.-->
  5.                 <item name="colorPrimary">@color/colorPrimary
  6. </item>
  7.                 <item name="colorPrimaryDark">@color/colorPrimary
  8. Dark</item>
  9.                 <item name="colorAccent">@color/colorAccent</item>
  10.         </style>
  11. </resources>
复制代码
在根元素中可以包罗多个标签,每个
标签中也可以包罗多个标签。 (1)在AndroidManifest.xml中设置主题的
  1. <application
  2.         ···
  3.         android:theme ="@style/AppTheme">
  4. </application>
复制代码
(2)在Java
代码中设置主题的

  1. setTheme(R.style.AppTheme);
复制代码
通过改变主题可以改变整个窗体样式,但不能设置View控件的具体样式,因此创建一个样式来美化View控件,放在res/values目次下的styles.xml文件中
  1. <resources>
  2.         <style name="textViewSytle">
  3.                 <item name="android:layout_width">20dp</item>
  4.                 <item name="android:layout_height">20dp</item>
  5.                 <item name="android:background">#f54e39</item>
  6.         </style>
  7. </resources>
复制代码
在布局文件的View控件中通过style属性调用
  1. <TextView
  2.         style="estyle/textViewSytle"/>
复制代码
颜色资源通常定义在res/values/colors.xml文件中
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3.         <color name="colorPrimary">#3F51B5</color>
  4.         <color name="colorPrimaryDark">#303F9F</color>
  5.         <color name="colorAccent">#FF4081</color>
  6. </resources>
复制代码
1.通过Java
代码调用颜色资源文件

  1. getResources().getColor(R.color,colorPrimary);
复制代码
2.在XML布局文件中调用颜色资源文件
  1. @color/colorPrimary
复制代码
颜色值必须以“#”开头,“#”后面表现Alpha-Red-Green-Blue情势的内容。此中,Alpha值可以省略,如果省略,表现颜色默认是完全不透明的。
·#RGB:利用红、绿、蓝三原色的值定义颜色,此中,红、绿、蓝分别利用0~f的十六进制数值表现。
·#ARGB:利用透明度以及红、绿、蓝三原色来定义颜色,此中,透明度、红、绿、蓝分别利用0~f的十六进制数值表现。
尺寸资源通常定义在res/values/dimens.xml文件中
要手动创建dimens创建dimens.xml文件,
  1. <resources>
  2.         <dimen name="activity_horizontal_margin">16dp</dimen>
  3.         <dimen name="activity_vertical_margin">16dp</dimen>
  4. </resources>
复制代码
<dimen></dimen>标签用于定义尺寸资源,此中name属性指定尺寸资源的名称。标签中心设置的是尺寸大小。在dimens.xml文件中只能有一个根元素,根元素可以包罗多个<dimen></dimen>标签。
1.通过Java
代码调用尺寸资源

  1. getResources().getDimension(R,dimen.activity_horizontal_margin);
复制代码
2.在XML布局文件中调用尺寸资源
  1. @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应用程序的主要代码和资源目次。
    1. - java 文件夹:包含Java
    2. 源代码文件。
    3. - res 文件夹:包含应用程序所需的资源文件,如布局文件、图像文件、字符串等。
    4. - 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 项目中更换下载仓库

  1. maven { url 'https://maven.aliyun.com/repository/public/' }
  2. maven { url 'https://maven.aliyun.com/repository/google/' }
  3. maven { url 'https://maven.aliyun.com/repository/jcenter/' }
  4. 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
帮你封装了一个对象,这样可以包管不会出现空指针。
  1. # 显式地声明了变量a为Int类型
  2. val a: Int = 10
复制代码

3.2 函数

参数的声明格式是“参数名: 参数类型”,此中参数名也是可以随便定义的
  1. fun main() {
  2.     println(fun1(1, 2))
  3. }
  4. fun fun1(num1:Int,num2: Int):Int{
  5.     return num1+num2
  6. }
复制代码
3.3 条件控制

3.3.1 if条件语句

  1. var value = 0
  2. if (num1 > num2) {
  3. value = num1
  4. } else {
  5. value = num2
  6. }
复制代码
Kotlin
中的if语句相比于Java
有一个额外的功能,它是可以有返回值的
  1. val result = if (条件表达式) {
  2.     // 如果条件为真,则返回这里的值
  3. } else {
  4.     // 如果条件为假,则返回这里的值
  5. }
复制代码
例子
  1. fun fun1(num1: Int, num2: Int): Int {
  2. return if (num1 > num2) {
  3. num1
  4. } else {
  5. num2
  6. }
  7. }
复制代码
  1. fun fun1(num1: Int, num2: Int) = if (num1 > num2) {
  2. num1
  3. } else {
  4. num2
  5. }
复制代码
再次
  1. val max = if (a > b) a else b
  2. fun fun1(num1: Int, num2: Int)= if (num1 > num2) num1 else num2
复制代码
3.3.2 when条件语句

这种直通式
  1. 匹配值 -> { 执行逻辑 }
复制代码
  1. when (条件表达式) {
  2.     值1 -> {
  3.         // 如果条件匹配值1,则执行这里的代码块
  4.     }
  5.     值2 -> {
  6.         // 如果条件匹配值2,则执行这里的代码块
  7.     }
  8.     else -> {
  9.         // 如果条件都不匹配,则执行这里的代码块
  10.     }
  11. }
复制代码
  1. is关键字就是类型匹配的核心,相当于Java
  2. 中的instanceof关键字。
复制代码
  1. when (num) {
  2. is Int -> println("number is Int")
  3. is Double -> println("number is Double")
  4. else -> println("number not support")
  5. }
复制代码
3.4 for-in循环

kotlin的while和Java
中的while循环没有任何区别
  1. fun main() {
  2.     val range = 0..10
  3.     for (i in range step 2) {
  4.         println(i)
  5.     }
  6. }
复制代码
利用step跳过区间内的元素


可以利用until关键字来创建一个左闭右开的区间,


downTo遍历降序区间


3.5 面向对象编程

  1. class Person {
  2.     var name: String = ""
  3.       var age=0
  4.     fun show(){
  5.         println("Name: $name, Age: $age")
  6.         println(name +"is" + age + " years old.")
  7.     }
  8. }
  9. fun main() {
  10.     val p = Person()
  11.     p.name = "Alice"
  12.     p.age = 30
  13.     p.show() // Output: Name: Alice, Age: 30
  14. }
复制代码
第一个打印语句利用了字符串模板(                                   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
中是一个冒号
  1. open class Person {
  2.     var name: String = ""
  3.       var age=0
  4.     fun show(){
  5.         println("Name: $name, Age: $age")
  6.         println(name +"is" + age + " years old.")
  7.     }
  8. }
  9. class Student :Person(){
  10.     var grade:Int=0
  11.     fun shows(){
  12.         println("Name: $name, Age: $age, Grade: $grade")
  13.          }
  14. }
  15. fun main() {
  16.     val s=Student()
  17.     s.name="Bob"
  18.     s.age=20
  19.     s.grade=3
  20.     s.shows() //Output: Name: Bob, Age: 20, Grade: 3
  21. }
复制代码
同样的我们也可以继承于Java



java
  1. public class cc {
  2.     private String name;
  3.     private  int age;
  4.     public cc() {
  5.     }
  6.     public cc(String name, int age) {
  7.         this.name = name;
  8.         this.age = age;
  9.     }
  10.     public String getName() {
  11.         return name;
  12.     }
  13.     public void setName(String name) {
  14.         this.name = name;
  15.     }
  16.     public int getAge() {
  17.         return age;
  18.     }
  19.     public void setAge(int age) {
  20.         this.age = age;
  21.     }
  22. }
复制代码
kotlin
  1. class Student : cc() {
  2.     var grade: Int = 0
  3.     fun shows() {
  4.         println("Name: $name, Age: $age, Grade: $grade")
  5.     }
  6. }
  7. fun main() {
  8.     val s = Student()
  9.     s.name = "Bob"
  10.     s.age = 20
  11.     s.grade = 3
  12.     s.shows() //Output: Name: Bob, Age: 20, Grade: 3
  13. }
复制代码
Open 继承

  1. 如果你希望在 Kotlin
  2. 中继承某个 Java
  3. 类,
  4.         需要手动在 Kotlin
  5. 代码中为该类添加 open 修饰符,
  6.         以明确表明该类是可继承的。
  7. 如果一个类不是专门为继承而设计的,
  8.         那么就应该主动将它加上final声明,禁止它可以被继承。
复制代码
在 Kotlin
中,默认情况下,所有类都是 final 的,即它们不能被继承。相比之下,Java
中的类默认是可以被继承的,除非利用了 final 关键字显式地克制继承。
当你在 Kotlin
中继承一个 Java
类时,Kotlin
并不会隐式地为 Java
类添加 open 修饰符。这是因为 Kotlin
不会假设 Java
类的设计者希望允许继承,因此需要在 Kotlin
中显式地利用 open 关键字来指示类是可继承的。
我们观察一下用Java
和Kotlin
分别创建的安卓项目的主活动


  1. Kotlin
复制代码

  1. Java
复制代码

四、活动(本篇以Java
代码,先行先容)


  1. 活动是安卓应用的主要组件之一,安卓中的活动(Activity)是指用户交互界面的一部分,它通常对应应用程序中的一个屏幕。
复制代码
通过管理活动的生命周期(创建、启动、恢复、暂停、停止和销毁),我们作为开辟者可以控制活动的状态和行为。
  1. 活动之间可以通过意图(Intent)进行跳转和通信。
复制代码
把各种控件和视图,按钮、文本框、图像等联系起来,启动其他活动或从其他活动返回,用户可以在差别的界面之间进行切换和交互。
总之,活动作为安卓应用程序的一个重要组件,负责用户界面的展示和交互处理,使得用户可以与应用程序进行互动。
4.1 创建活动

在com.example.hellowolrd包下 ->New ->Activity ->Empty Activity

我们的两个活动:

4.1.1 Android Studio 会自动在AndroidManifest文件中注册

我们打开app/src/main/AndroidManifest.xml文件代码如下所示:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3.     xmlns:tools="http://schemas.android.com/tools" >
  4.     <application
  5.         android:allowBackup="true"
  6.         android:dataExtractionRules="@xml/data_extraction_rules"
  7.         android:fullBackupContent="@xml/backup_rules"
  8.         android:icon="@mipmap/ic_launcher"
  9.         android:label="@string/app_name"
  10.         android:roundIcon="@mipmap/ic_launcher_round"
  11.         android:supportsRtl="true"
  12.         android:theme="@style/Theme.MyApplication"
  13.         tools:targetApi="31" >
  14.         
  15.         <activity
  16.             android:name=".OtherActivity"
  17.             android:exported="false" />
  18.             
  19.         <activity
  20.             android:name=".MainActivity"
  21.             android:exported="true" >
  22.             <intent-filter>
  23.                 <action android:name="android.intent.action.MAIN" />
  24.                 <category android:name="android.intent.category.LAUNCHER" />
  25.             </intent-filter>
  26.         </activity>
  27.         
  28.     </application>
  29. </manifest>
复制代码
4.1.2 活动中利用Toast

Toast会在屏幕上表现一段时间,用于在应用程序的界面上表现一条简短的消息,然后自动消散。
写法

  1. // 要显示的消息文本
  2. String message = "Hello, Toast!";
  3. // 创建并显示Toast
  4. Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
复制代码
当调用makeText()方法,并通过链式调用show()方法来创建并表现Toast。getApplicationContext()是一种获取当前活动上下文的方法,可以在活动中利用。
需要留意的是,Toast的 makeText()方法返回的是一个Toast对象,可以通过调用show()方法来表现。
在调用show()方法后,Toast会在屏幕上表现一段时间,然后自动消散。
   Java


    Kotlin


  1. val button1: Button = findViewById(R.id.button12)
  2. button1.setOnClickListener {
  3.     Toast.makeText(this, "Yes", Toast.LENGTH_LONG).show() }
复制代码
LENGTH_SHORT=0


     短时间的Toast
  
LENGTH_LONG = 1


     长时间的Toast
  
4.1.3 销毁活动

  1. Activity类提供了一个finish()
复制代码
延迟销毁
  1. package com.example.myapplication;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.os.Handler;
  5. import android.view.Menu;
  6. import android.view.MenuInflater;
  7. import android.view.MenuItem;
  8. import android.view.View;
  9. import android.widget.Button;
  10. import android.widget.Toast;
  11. public class OtherActivity extends AppCompatActivity {
  12.     private Button button1;
  13.     private Handler handler = new Handler();
  14.     @Override
  15.     protected void onCreate(Bundle savedInstanceState) {
  16.         super.onCreate(savedInstanceState);
  17.         setContentView(R.layout.activity_other);
  18.         button1 = findViewById(R.id.button1);
  19.         button1.setOnClickListener(v -> {
  20.             Toast.makeText(this, "TestOther", Toast.LENGTH_SHORT).show();
  21.             handler.postDelayed(() -> finish(), 2000);
  22.         });
  23.     }
  24. }
复制代码

     finishmp4
  
4.2 Intent 跨越活动

4.2.1 表现的Intent

先创建一个新的活动,并在其绑定创建的layout文件之中简朴的放置一个按钮,目的是在跳转的时候直观的有显着的体验
  1. package com.example.myapplication;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.content.Intent;
  4. import android.os.Bundle;
  5. import android.os.Handler;
  6. import android.view.Menu;
  7. import android.view.MenuInflater;
  8. import android.view.MenuItem;
  9. import android.view.View;
  10. import android.widget.Button;
  11. import android.widget.Toast;
  12. public class OtherActivity extends AppCompatActivity {
  13.     private Button button1;
  14.     private Handler handler = new Handler();
  15.     @Override
  16.     protected void onCreate(Bundle savedInstanceState) {
  17.         super.onCreate(savedInstanceState);
  18.         setContentView(R.layout.activity_other);
  19.         button1 = findViewById(R.id.button1);
  20.         button1.setOnClickListener(v -> {
  21.             Toast.makeText(this, "TestOther", Toast.LENGTH_SHORT).show();
  22.             Intent intent = new Intent(OtherActivity.this, SecondActivity.class);
  23.             // 在延迟2秒后执行 finish() 和 startActivity()
  24.             handler.postDelayed(() -> {
  25.                 finish();
  26.                 startActivity(intent);
  27.             }, 2000);
  28.         });
  29.     }
  30. }
复制代码

     Intent跳转其他活动
  
4.2.2 隐式Intent

我们在当前文件在指定出来我们可以转向的动作名称

  1. button1.setOnClickListener(v -> {
  2.    Toast.makeText(this, "TestOther", Toast.LENGTH_SHORT).show();
  3.    Intent intent = new Intent("x111");
  4.    startActivity(intent);
  5.         });
复制代码
我们还可以跳转到其他地方,如网页(这和我们平时的app如出一辙)

  1. button1.setOnClickListener(v-> {
  2.    Intent intent =new Intent(Intent.ACTION_VIEW);
  3.    intent.setData(Uri.parse("http://www.baidu.com"));
  4.    startActivity(intent);
  5.         });
复制代码
点击按钮后,创建了一个意图(Intent)并设置了其动作(Action)为Intent.ACTION_VIEW,同时指定了要检察的数据是一个URL,即http://www.baidu.com。系统收到这个意图后,会识别出这是一个网页链接,并自动利用默认的Web欣赏器打开百度网站页面。同样地,如果intent指向的是一个电话号码大概一个本地文件(如图片、视频等),则相应程序(拨号器或媒体播放器等)会被唤起以处理这些数据。


4.2.3Action 和 Category

  1. 在Android中,Action 和 Category 是 Intent 的重要组成部分,
  2.         它们用于定义和过滤应用程序间交互的行为意图(Intent)。
复制代码
Action 描述了Intent的主要动作或目的。例如,发送一个电子邮件可以利用 ACTION_SEND 动作;打开网页可以利用 ACTION_VIEW 动作等。
Category 为Intent添加了额外的上下文信息,进一步描述了Intent的应用场景或意图所属的种别

一个Intent不但需要定义一个动作(如ACTION_MAIN),还需要至少一个种别(如CATEGORY_LAUNCHER),这样才能正确地匹配到相应的组件并触发相应的行为。在AndroidManifest.xml文件中,开辟者会在 标签内为Activity声明它可以相应哪些动作和种别组合。
4.2.4 通报给下一个活动数据

(1)发送活动方

  1. //  传递给下一个活动数据
  2. button1.setOnClickListener(v -> {
  3.              String data = "你会魔法吗✧(≖ ◡ ≖✿)";
  4.           Intent intent = new Intent(OtherActivity.this, SecondActivity.class);
  5.           intent.putExtra("exdata", data);
  6.           startActivity(intent);
  7. });
复制代码
(2)担当活动方

  1. @Override
  2.     protected void onCreate(Bundle savedInstanceState) {
  3.         super.onCreate(savedInstanceState);
  4.         setContentView(R.layout.activity_second);
  5.         Intent intent =getIntent();
  6.         String data =intent.getStringExtra("exdata");
  7.         Log.d("Sec",data);
  8.     }
复制代码
(3)打开日志Logcat


4.2.5 返回数据给上一个活动


(1)副活动中

  1.   @Override
  2.     protected void onCreate(Bundle savedInstanceState) {
  3.         super.onCreate(savedInstanceState);
  4.         setContentView(R.layout.activity_second);
  5.         Intent intent =getIntent();
  6.         String data =intent.getStringExtra("exdata");
  7.         Log.d("Sec",data);
  8.         Button buttonxx=findViewById(R.id.buttonxx);
  9.         buttonxx.setOnClickListener(new View.OnClickListener() {
  10.             @Override
  11.             public void onClick(View v) {
  12.                 Intent intent =new Intent();
  13.                 intent.putExtra("resdata","hello_你会魔法吗✧(≖ ◡ ≖✿)");
  14.                 setResult(RESULT_OK,intent);
  15.                 finish();
  16.             }
  17.         });
  18.     }
复制代码
(2)主活动

  1. //  传递给下一个活动数据
  2. button1.setOnClickListener(v -> {
  3.     String data = "你会魔法吗✧(≖ ◡ ≖✿)";
  4.     Intent intent = new Intent(OtherActivity.this, SecondActivity.class);
  5.     intent.putExtra("exdata", data);
  6.     startActivityForResult(intent,1);
  7. });
复制代码
留意 startActivityForResult方法重写
  1. @Override
  2. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  3.    super.onActivityResult(requestCode, resultCode, data);
  4.     if (requestCode == 1 && resultCode == RESULT_OK) {
  5.        String reData = data.getStringExtra("resdata");
  6.        // 在这里处理接收到的数据 reData
  7.        Log.d("OtherActivity", reData);
  8.     }
  9. }
复制代码
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)主活动

  1. package com.example.myapplication;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.content.Intent;
  4. import android.os.Bundle;
  5. import android.util.Log;
  6. import android.view.Menu;
  7. import android.view.MenuItem;
  8. import android.view.View;
  9. import android.widget.Button;
  10. import android.widget.Toast;
  11. public class MainActivity extends AppCompatActivity {
  12.     public static final String TAG = "MainActivity";
  13.     @Override
  14.     protected void onCreate(Bundle savedInstanceState) {
  15.         super.onCreate(savedInstanceState);
  16.         setContentView(R.layout.activity_main);
  17.         Button startNormalActivity = findViewById(R.id.ShowActivity);
  18.         Button startDialogActivity = findViewById(R.id.ShowActivity2);
  19.         startNormalActivity.setOnClickListener(v -> {
  20.             Intent intent = new Intent(MainActivity.this, ShowActivity.class);
  21.             startActivity(intent);
  22.         });
  23.         startDialogActivity.setOnClickListener(v -> {
  24.             Intent intent = new Intent(MainActivity.this, ShowActivity2.class);
  25.             startActivity(intent);
  26.         });
  27.     }
  28.     @Override
  29.     protected void onStart() {
  30.         super.onStart();
  31.         Log.d(TAG, "onStart");
  32.     }
  33.     @Override
  34.     protected void onResume() {
  35.         super.onResume();
  36.         Log.d(TAG, "onResume");
  37.     }
  38.     @Override
  39.     protected void onPause() {
  40.         super.onPause();
  41.         Log.d(TAG, "onPause");
  42.     }
  43.     @Override
  44.     protected void onStop() {
  45.         super.onStop();
  46.         Log.d(TAG, "onStop");
  47.     }
  48.     @Override
  49.     protected void onDestroy() {
  50.         super.onDestroy();
  51.         Log.d(TAG, "onDestroy");
  52.     }
  53.     @Override
  54.     protected void onRestart() {
  55.         super.onRestart();
  56.         Log.d(TAG, "onRestart");
  57.     }
  58. }
复制代码
(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)

  1. Android Activity 回收与恢复策略
复制代码
在Android中,当系统资源告急时,Activity大概会因内存不足而被回收(destroy)。为应对这种情况并确保应用能够正确恢复用户界面和数据,可以采用以下几种方法:
4.4.1. 保存和恢复数据

在onSaveInstanceState(Bundle outState)方法中保存关键数据,以便在Activity重新创建时通过onCreate(Bundle savedInstanceState)或onRestoreInstanceState(Bundle savedInstanceState)恢复这些数据。
  1.    @Override
  2.    protected void onSaveInstanceState(Bundle outState) {
  3.        super.onSaveInstanceState(outState);
  4.        // 保存数据到Bundle
  5.        outState.putInt("key", someImportantValue);
  6.    }
  7.    @Override
  8.    protected void onCreate(Bundle savedInstanceState) {
  9.        super.onCreate(savedInstanceState);
  10.        setContentView(R.layout.activity_main);
  11.        if (savedInstanceState != null) {
  12.            // 恢复数据
  13.            int importantValue = savedInstanceState.getInt("key");
  14.            // 使用恢复的数据...
  15.        }
  16.    }
  17.    
复制代码
4.4.2. 利用ViewModel

借助Android架构组件中的ViewModel类,可以在配置更改或Activity生命周期变化时保持UI相关数据的长期性。纵然Activity被销毁,ViewModel中的数据也能保存下来。
  1.    public class MyViewModel extends ViewModel {
  2.        private MutableLiveData<Integer> someLiveData;
  3.        public MutableLiveData<Integer> getSomeLiveData() {
  4.            if (someLiveData == null) {
  5.                someLiveData = new MutableLiveData<>();
  6.                // 初始化数据...
  7.            }
  8.            return someLiveData;
  9.        }
  10.    }
  11.    public class MainActivity extends AppCompatActivity {
  12.        private MyViewModel viewModel;
  13.        @Override
  14.        protected void onCreate(Bundle savedInstanceState) {
  15.            super.onCreate(savedInstanceState);
  16.            setContentView(R.layout.activity_main);
  17.            viewModel = new ViewModelProvider(this).get(MyViewModel.class);
  18.            viewModel.getSomeLiveData().observe(this, value -> {
  19.                // 更新UI...
  20.            });
  21.        }
  22.    }
  23.    
复制代码
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 (默认)

  1. 创建新实例、栈顶、默认的启动方式
复制代码
standard(标准模式)是Android中默认的启动模式。在该模式下,每次启动Activity都会创建一个新的实例,并将其放入任务栈中。
当我们通过Intent启动一个Activity时,系统会创建该Activity的新实例,并将其放置在当前任务栈的顶部。
如果目标Activity已经存在于任务栈中,则系统会创建一个新的实例并将其放在之前实例之上。
  1. 在标准模式下,多个相同类型的Activity可以同时存在于同一任务栈中。
  2. 每个实例都是独立的,并且它们彼此没有直接影响。
复制代码
  例如,假设我们有一个应用程序包罗两个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。例如:
  1. <activity android:name=".YourActivity"
  2.     android:launchMode="singleTop">
  3. </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()方法。
这种启动模式常用于作为应用程序的主界面大概入口页面,确保每次打开应用都会进入同一个特定界面。
   结构

  1. package com.example.myapplication;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.content.Intent;
  4. import android.os.Bundle;
  5. import android.util.Log;
  6. import android.view.View;
  7. import android.widget.Button;
  8. public class FirstActivity extends AppCompatActivity {
  9.     @Override
  10.     protected void onCreate(Bundle savedInstanceState) {
  11.         super.onCreate(savedInstanceState);
  12.         Log.d("FirstActivity", this.toString());
  13.         setContentView(R.layout.activity_first);
  14.         Button button =findViewById(R.id.button);
  15.         button.setOnClickListener(new View.OnClickListener() {
  16.             @Override
  17.             public void onClick(View v) {
  18.                 Intent intent =new Intent(FirstActivity.this, SecondActivity.class);
  19.                 startActivity(intent);
  20.             }
  21.         });
  22.     }
  23.     @Override
  24.     protected void onDestroy() {
  25.         super.onDestroy();
  26.         Log.d("fir","onfirDestroy");
  27.     }
  28. }
复制代码

  1. package com.example.myapplication;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.content.Intent;
  4. import android.os.Bundle;
  5. import android.util.Log;
  6. import android.widget.Button;
  7. public class SecondActivity extends AppCompatActivity {
  8.     @Override
  9.     protected void onCreate(Bundle savedInstanceState) {
  10.         super.onCreate(savedInstanceState);
  11.         Log.d("SecondActivity", this.toString());
  12.         setContentView(R.layout.activity_second);
  13.         Button button=findViewById(R.id.button2);
  14.         button.setOnClickListener(v -> {
  15.             Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
  16.             startActivity(intent);
  17.         });
  18.     }
  19.     @Override
  20.     protected void onRestart() {
  21.         super.onRestart();
  22.         Log.d("sec","onRestart");
  23.     }
  24. }
复制代码
在xml中


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

耶耶耶耶耶

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表