文章目录
- 一、创建第一个Android项目
- 1.1 准备好Android Studio
- 1.2 运行程序
- 1.3 程序结构是什么
- app下的结构
- res - 子目录(所有图片、布局、字符串等资源)
- AndroidManifest.xml 有四大组件,程序添加权限声明
- Project下的结构
- 二、开发android时,部分库下载异常慢
- 2.1 项目中更换下载仓库
- 2.2 离线模式配置 Gradle
- 三、Kotlin代码(本篇Android项目不会涉及用kotlin创建文件,先介绍后续再涉及)
- 3.1 变量
- 3.2 函数
- 3.3 条件控制
- 3.3.1 if条件语句
- 3.3.2 when条件语句
- 3.4 for-in循环
- 使用step跳过区间内的元素
- 可以使用`until`关键字来创建一个左闭右开的区间,
- downTo遍历降序区间
- 3.5 面向对象编程
- 3.5.1 继承
- 同样的我们也可以继承于Java
- Open 继承
- 我们观察一下用Java和Kotlin分别创建的安卓项目的主活动
- 四、活动(本篇以Java代码,先行介绍)
- 4.1 创建活动
- 4.1.1 Android Studio 会自动在AndroidManifest文件中注册
- 4.1.2 活动中使用Toast
- 写法
- LENGTH_SHORT=0
- LENGTH_LONG = 1
- 4.1.3 销毁活动
- 4.2 Intent 跨越活动
- 4.2.1 显示的Intent
- 4.2.2 隐式Intent
- 我们还可以跳转到其他地方,如网页(这和我们平时的app如出一辙)
- 4.2.3Action 和 Category
- 4.2.4 传递给下一个活动数据
- (1)发送活动方
- (2)接受活动方
- (3)打开日志Logcat
- 4.2.5 返回数据给上一个活动
- (1)副活动中
- (2)主活动
- 4.3 安卓 Activity生命周期
- 4.3.1 概述
- 4.3.2 过程
- (1)创建活动,并简单的xml配个botton
- (2)主活动
- (3)启动虚拟机,看日志Logcat
- 4.4 活动被回收了怎么办(GPT)
- 4.4.1. 保存和恢复数据
- 4.4.2. 使用ViewModel
- 4.4.3. 持久化数据
- 4.4.4. 处理返回结果
- 4.5 启动模式
一、创建第一个Android项目
1.1 准备好Android Studio
选择
写信息
等待构建Gradle
可以选择我们的模拟器,甚至我们可以通过手机屏幕共享的方式,把手机的开发者模式打开等操作,下载到本机手机之中,可以0距离的感受,程序之美。
1.2 运行程序
1.3 程序结构是什么
app下的结构
这种的结构化的项目简洁明了,提高开发效率和代码质量
build - 编译时自动生成的文件
libs - 第三方jar包放在libs目录下
java - 放置所需Java 代码,自动生成了一个MainActivity 文件
res - 子目录(所有图片、布局、字符串等资源)
我们应该创建不同分辨率的目录,如drawable-hdpi、drawable-xhdpi、drawable-xxhdpi等,并在制作程序时提供几个不同分辨率的版本,是为了适应不同设备的屏幕密度和分辨率
打开我们的子目录
这里面就是我们配置的字符串,调用使用,不用全局在中出现相同的多次构建
怎么构建
在XML中通过@string/app_name可以获得该字符串的引用。
最终
点击可以替换
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分别创建的安卓项目的主活动
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
Android 短时间的Toast
LENGTH_LONG = 1
Android 长时间的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生命周期
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.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在获取结果前被销毁过。