Android 开发 - Android 开发引入(APP 运行环境、APP 开发技术路线、APP 内置数据库、工程目录结构...)

一、APP 运行环境

  • APP 是在手机上运行的一类应用软件,而应用软件依附于操作系统,无论电脑还是手机,开机后都会显示桌面,而这个桌面便是操作系统的工作台
  1. 电脑的操作系统主要有微软的 Windows 和苹果的 Mac OS

  2. 手机的操作系统主要安卓手机的 Android 和苹果手机的 iOS

  • 本次讲述的 APP 开发为 Android 上的应用开发,Android 系统基于 Linux 内核,但不等同于 Linux 系统,故而 APP 无法在 Linux 系统上运行

二、APP 开发技术路线

  • 基于安卓系统的 APP 开发主要有两大技术路线,分别是原生开发和混合开发
  1. 原生开发指的是在移动平台上利用官方提供的编程语言(Java、Kotlin 等)、开发工具包(SDK)、开发环境(Android Studio)进行 APP 开发

  2. 混合开发指的是结合原生与 H5 技术开发混合应用,也就是将部分 APP 页面改成内嵌的网页,这样无须升级 APP,只要覆盖服务器上的网页,即可动态更新 APP页面

  • 不管是原生开发还是混合开发,都要求掌握 Android Studio 的开发技能,就原生开发而言,涉及多种编程语言,包括 Java、Kotlin、C / C++、XML 等

三、APP 内置数据库

  • 在 Java 编程时,可以通过连接数据库进行对数据的增删改查,这个数据库可以是 MySQL、Oracle、SQL Server,然而手机应用不能直接操作这几种数据库,因为数据库软件也需要像应用软件那样安装到操作系统上,MySQL、Oracle 数据库无法在手机上安装

  • Android 内置了专门的数据库 SQLite,它遵循关系型数据库的设计理念,语法类似于 MySQL,SQLite 无须单独安装,它内嵌在应用进程当中(嵌入式数据库),APP 无须配置连接即可直接对其进行操作


四、工程目录结构

1、基本介绍
  1. APP 工程分为两个层次,第一个层次是项目,第二个层次是模块

  2. 模块依附于项目,每个项目至少有一个模块,也能拥有多个模块

  3. 一般所言的编译运行 APP,指的是运行某个模块,而非运行某个项目,因为模块才对应着实际的 APP

2、项目目录说明
  • 项目目录有两个分类,分别是 app(模块) 和 Gradle Scripts
(1)app
  • app 下有三个子目录
目录说明
manifests下面只有一个 XML 文件,AndroidManifest.xml,它是 APP 的运行配置文件
java下面有 3 个包(com.my.helloworld)
其中第一个包存放当前模块 Java 代码,其余两个包存放测试用 Java 代码
res存放当前模块的资源文件
  • res 目录下有 4 个子目录
目录说明
drawable存放图形描述文件与图片文件
layout存放 APP 页面的布局文件
mipmap存放 APP 的启动图标
values存放一些常量定义文件
例如字符串常量 strings.xml、像素常量 dimens.xml、颜色常量 colors.xml、样式风格定义 styles.xml 等
(2)Gradle Scripts
  • Gradle Scripts 下主要是工程的编译配置文件
文件说明
build.gradle该文件分为项目级与模块级两种,用于描述 APP 工程的编译规则
proguard-rules.pro该文件用于描述 Java 代码的混淆规则
gradle.properties该文件用于配置编译工程的命令行参数,一般无须改动
settings.gradle该文件配置了需要编译哪些模块,初始内容为 include ‘:app’,表示只编译 app 模块
local.properties项目的本地配置文件,它在工程编译时自动生成
用于描述开发者电脑的环境配置,包括 SDK 的本地路径、NDK 的本地路径等

五、编译配置文件 build.gradle

1、项目级
  • 指定当前项目的总体编译规则
// Top-level build file where you can add configuration options common to all sub-projects/modules.

// 插件
plugins {
    id 'com.android.application' version '7.2.2' apply false
    id 'com.android.library' version '7.2.2' apply false
}

// 任务(Groovy 语言)
task clean(type: Delete) {
    delete rootProject.buildDir
}
2、模块级
  • 对应于具体模块,每个模块都有自己的 build.gradle,它指定当前模块的详细编译规则
// 插件
plugins {
    id 'com.android.application'
}

android {

    // 指定编译用的 SDK 版本,比如 30 表示使用 Android 11.0 编译
    compileSdk 32

    defaultConfig {

        // 指定该模块的应用编号,也就是 App 的包名
        applicationId "com.my.helloworld"

        // 指定 App 适合运行的最小 SDK 版本,比如 19 表示至少要在Android 4.4 上运行
        minSdk 21

        // 指定目标设备的 SDK 版本,表示 App 最希望在哪个版本的 Android 上运行
        targetSdk 32

        // 指定 App 的应用版本
        versionCode 1

        // 指定 App 的应用版本名称
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

// 指定 App 编译的依赖信息
dependencies {

    // 指定编译 Android 的高版本支持库,如 AppCompatActivity 必须指定编译 appcompat 库
    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

六、清单文件 AndroidManifest.xml

  • AndroidManifest.xml 指定了 App 的运行配置信息
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.my.helloworld">

    <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.HelloWorld"
        tools:targetApi="31">
        <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>
  • AndroidManifest.xml 的根节点为 manifest ,它的 package 属性指定了该 APP 的包名,manifest 下有 application 节点,它的各属性说明如下
属性说明
allowBackup是否允许应用备份
允许用户备份系统应用和第三方应用的 apk 安装包和应用数据,以便在刷机或者数据丢失后恢复应用
用户可通过 adb backup 和 adb restore 进行数据的备份和恢复,true 表示允许,false 表示不允许
icon指定 APP 在手机屏幕上显示的图标
label指定 APP 在手机屏幕上显示的名称
roundIcon指定 APP 的圆角图标
supportsRtl是否支持阿拉伯语 / 波斯语这种从右往左的文字排列顺序,true 表示支持,false 表示不支持
theme指定 APP 的显示风格
  • application 下还有个 activity 节点,它是活动页面的注册声明,只有在 AndroidManifest.xml 中正确配置了 activity 节点,才能在运行时访问对应的活动页面,初始配置的 MainActivity 正是 APP 的默认主页,之所以说该页面是 APP 主页,是因为它的 activity 节点内部还配置了以下的过滤信息
<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
  • action 节点设置的 android.intent.action.MAIN 表示该页面是 APP 的入口页面,启动 APP 时会最先打开该页面

  • category 节点设置的 android.intent.category.LAUNCHER 决定了是否在手机屏幕上显示 APP 图标,如果同时有两个 activity 节点内部都设置了android.intent.category.LAUNCHER,那么桌面就会显示两个 APP 图标,以上的两种节点规则可能一开始不太好理解,只需记住默认主页必须同时配置这两种过滤规则即可


七、APP 设计规范

1、基本介绍
  • APP 将看得见的界面设计与看不见的代码逻辑区分开,利用 XML 文件描绘应用界面,使用 Java 代码书写程序逻辑

  • 这样形成 APP 前后端分离的设计规约,有利于提高 APP 集成的灵活性

2、界面设计与代码逻辑
  • 手机的功能越来越强大,某种意义上相当于微型电脑,比如打开一个电商 APP,仿佛是在电脑上浏览网站,网站分为用户看得到的网页,以及用户看不到的后台,APP 也分为用户看得到的界面,以及用户看不到的后台,虽然 Android 允许使用 Java 代码描绘界面,但不提倡这么做,推荐的做法是将界面设计从 Java 代码剥离出来,通过单独的 XML 文件定义界面布局,就像网站使用 HTML 文件定义网页那样,把界面设计与代码逻辑分开,参考了网站的前后端分离,还有下列几点好处
  1. 使用 XML 文件描述 APP 界面,可以很方便地在 Android Studio 上预览界面效果,如果 XML 文件修改了内容,立刻就能在预览区域观看最新界面,倘若使用 Java 代码描绘界面,那么必须运行 APP 才能看到界面,无疑费时许多

  2. 一个界面布局可以被多处代码复用,反过来,一段 Java 代码也可能适配多个界面布局


八、APP 设计初体验

1、界面设计
  • activity_main.xml 文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <TextView
        android:id="@+id/hello"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World"/>
</LinearLayout>
2、代码逻辑
  • MainActivity 类
package com.my.androiddevelop;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = findViewById(R.id.hello);
        tv.setText("你好,世界!");
    }
}

九、APP 页面快速入门

1、APP 活动页面
(1)编写 XML 文件
  • 在 layout 目录下创建 activity_my.xml 文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/my_text" />
</LinearLayout>
  • 在 activity_main.xml 文件中创建跳转按钮
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <TextView
        android:id="@+id/hello"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World"/>

    <Button
        android:id="@+id/but"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/but_text" />
</LinearLayout>
  • 在 res/values/strings.xml 中定义字符串常量
<resources>
    <string name="app_name">AndroidDevelop</string>
    <string name="my_text">My Activity</string>
    <string name="but_text">跳转</string>
</resources>
(2)编写 Java 代码
  • MyActivity 类
package com.my.helloworld;

import android.os.Bundle;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

public class MyActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_main);
    }
}
  • MainActivity 类,实现跳转
package com.my.androiddevelop;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = findViewById(R.id.hello);
        tv.setText("你好,世界!");

        // 实现跳转
        Button button  = findViewById(R.id.but);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.setClass(MainActivity.this, MyActivity.class);
                startActivity(intent);
            }
        });
    }
}
(3)注册页面
  • AndroidManifest.xml 文件
<activity android:name=".MyActivity" />
2、快速生成页面
  • 右击包名 -> 【Activity】 -> 【Empty Activity】 -> 填写相关信息 -> 【Finish】
(1)XML 文件
  • activity_new.xml 文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".NewActivity">

</androidx.constraintlayout.widget.ConstraintLayout>
(2)Java 代码
  • NewActivity
package com.my.androiddevelop;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class NewActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_new);
    }
}
(3)页面注册
  • AndroidManifest.xml 文件
<activity android:name=".NewActivity" android:exported="false" />

十、消息框

1、基本介绍
  • 消息框可以在一个小型弹出式窗口中提供与操作有关的简单反馈,它只会填充消息所需的空间大小,超时后,消息框会自动消失,它有如下常用方法
  1. Toast.makeText(Context context, @StringRes int resId, @Duration int duration):该方法用于实例化 Toast 对象,它接收以下参数:activity Context、应向用户显示的文本 / 字符串资源的资源 ID、消息框应在屏幕上停留的时长

  2. show():该方法用于显示消息框

  3. setGravity(int gravity, int xOffset, int yOffset):该方法用于设置消息框在屏幕上的垂直和水平对齐方式,它接收以下参数:对齐方式、水平方向上的偏移量(向左,以像素为单位)、在垂直方向上的偏移量(向上,以像素为单位)

  • 消息框基本使用为默认位置显示文本内容,高级使用为自定义显示位置,自定义显示内容
2、基本使用
(1)XML 文件
  • activity_toast_test.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_toast1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TOAST 1"/>

    <Button
        android:id="@+id/btn_toast2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TOAST 2"/>

    <Button
        android:id="@+id/btn_toast3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TOAST 3"/>
</LinearLayout>
(2)Java 代码
  • ToastTestActivity.java
package com.my.androiddevelop;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.my.androiddevelop.utils.ToastUtils;

public class ToastTestActivity extends AppCompatActivity implements View.OnClickListener {

    private Button btn_toast1;
    private Button btn_toast2;
    private Button btn_toast3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_toast_test);

        btn_toast1 = findViewById(R.id.btn_toast1);
        btn_toast2 = findViewById(R.id.btn_toast2);
        btn_toast3 = findViewById(R.id.btn_toast3);

        btn_toast1.setOnClickListener(this);
        btn_toast2.setOnClickListener(this);
        btn_toast3.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn_toast1) {
            Toast toast = Toast.makeText(this, "Hello Toast LONG", Toast.LENGTH_LONG);
            toast.show();
            return;
        }
        if (v.getId() == R.id.btn_toast2) {
//            Toast.makeText(this, "Hello Toast SHORT", Toast.LENGTH_SHORT).show();

            ToastUtils.toast(this, R.string.toast_str);
            return;
        }
        if (v.getId() == R.id.btn_toast3) {
            Toast toast = Toast.makeText(this, "Hello Toast LONG", Toast.LENGTH_LONG);
            toast.setGravity(Gravity.BOTTOM | Gravity.CENTER, 150, 300);
            toast.show();
            return;
        }
    }
}
3、高级使用
(1)XML 文件
  • activity_toast_content.xml,自定义显示内容
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toast_content"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:orientation="vertical">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher_background"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="自定义 ToastView"/>

</LinearLayout>
(2)Java 代码
  • CustomToastActivity.java
package com.my.androiddevelop;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.my.androiddevelop.utils.ToastUtils;

public class CustomToastActivity extends AppCompatActivity implements View.OnClickListener {

    private Button btn_show_toast1;
    private Button btn_show_toast2;
    private Context context;
    private Toast toast;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom_toast);

        initView();
    }

    private void initView() {
        btn_show_toast1 = findViewById(R.id.btn_show_toast1);
        btn_show_toast2 = findViewById(R.id.btn_show_toast2);

        context = getApplicationContext();
        LayoutInflater layoutInflater = getLayoutInflater();

        // 使用布局解析器来解析一个布局
        View view = layoutInflater.inflate(R.layout.activity_toast_content, null);

        toast = new Toast(context);
        toast.setGravity(Gravity.TOP, 0, 800);
        toast.setDuration(Toast.LENGTH_SHORT);
        toast.setView(view);

        btn_show_toast1.setOnClickListener(this);
        btn_show_toast2.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_show_toast1:
                ToastUtils.toast(context, "Hello Toast");
                break;
            case R.id.btn_show_toast2:
                toast.show();
                break;
        }
    }
}
4、实例实操
(1)基本介绍
  1. 对 Android 原生的 Toast 类进行简单封装实现 Toast 工具类

  2. 对 Android 原生的 Toast 类进行自定义封装实现自定义 Toast 工具类

(2)具体实现
  • ToastUtils.java
package com.my.androiddevelop.utils;

import android.content.Context;
import android.widget.Toast;

/**
 * Toast 工具类
 * @author my
 */
public class ToastUtils {

    /**
     * 显示 Toast
     * @param context 上下文对象
     * @param text 文本
     */
    public static void toast(Context context, CharSequence text) {
        Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
    }

    /**
     * 显示 Toast
     * @param context 上下文对象
     * @param resId 字符串资源的资源 ID
     */
    public static void toast(Context context, int resId) {
        Toast.makeText(context, resId, Toast.LENGTH_SHORT).show();
    }

    /**
     * 长时间显示 Toast
     * @param context 上下文对象
     * @param text 文本
     */
    public static void toastLong(Context context, CharSequence text) {
        Toast.makeText(context, text, Toast.LENGTH_LONG).show();
    }

    /**
     * 长时间显示 Toast
     * @param context 上下文对象
     * @param resId 字符串资源的资源 ID
     */
    public static void toastLong(Context context, int resId) {
        Toast.makeText(context, resId, Toast.LENGTH_LONG).show();
    }
}
  • CustomToastUtils.java
package com.my.androiddevelop.utils;

import android.content.Context;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.my.androiddevelop.R;

import java.util.Timer;
import java.util.TimerTask;

public class CustomToastUtils {

    // 定时器
    public static void controlToastTime(Toast toast, int duration) {
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                toast.cancel();
            }
        }, duration);
    }

    // 自定义位置弹出消息
    public static void show(Context context, String s) {
        View view = LayoutInflater.from(context).inflate(R.layout.activity_toast_content, null);
        TextView tv_msg = view.findViewById(R.id.tv_toast_text);
        tv_msg.setText(s);

        Toast toast = new Toast(context);
        controlToastTime(toast, 500);
        toast.setGravity(Gravity.CENTER, 0, 0);
        toast.setView(view);
        toast.show();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值