当前位置: 首页 > news >正文

自动化工作流建设指南

🚀 自动化工作流建设指南:CI/CD、Github Actions与自动化测试部署

打造现代化的自动化工作流,提升团队开发效率。今天咱们将深入探讨 CI/CD 最佳实践、Github Actions 实战经验以及自动化测试与部署策略。

📑 目录

  • CI/CD 最佳实践
  • Github Actions 实战
  • 自动化测试与部署

🔄 CI/CD 最佳实践

1. 📋 CI/CD 流程设计与工具链集成

主流 CI/CD 工具对比
工具特点适用场景部署方式
Jenkins插件丰富、自由度高复杂项目、传统应用自托管
Github Actions集成度高、配置简单开源项目、云原生应用云服务
GitLab CI源码集成、容器原生私有部署、完整 DevOps自托管/云服务
CircleCI并行支持好、启动快中小型项目、敏捷开发云服务
工具链整合最佳实践
代码提交
代码检查
单元测试
构建
制品管理
部署
监控
SonarQube
Jest/JUnit
Docker
Artifactory
Kubernetes
Prometheus
持续集成(CI)核心原则
# CI 流程关键步骤
1. 代码提交触发构建
2. 运行自动化测试
3. 代码质量检查
4. 构建制品
5. 生成测试报告
持续部署(CD)最佳实践
# CD 流程关键环节
1. 环境配置管理
2. 部署策略选择
3. 回滚机制
4. 监控告警
5. 审计日志

2. 🛠 Pipeline 设计模式与实践

微服务构建流水线示例
# .gitlab-ci.yml
stages:- test- build- deployvariables:DOCKER_REGISTRY: "registry.example.com"APP_NAME: "user-service"# 测试阶段
test:stage: testimage: node:16-alpinecache:paths:- node_modules/before_script:- npm ciscript:- npm run lint- npm run test:coveragecoverage: '/Lines\s*:\s*([0-9.]+)%/'artifacts:reports:coverage_report:coverage_format: coberturapath: coverage/cobertura-coverage.xml# 构建阶段
build:stage: buildservices:- docker:dindvariables:DOCKER_HOST: tcp://docker:2375script:- docker build -t ${DOCKER_REGISTRY}/${APP_NAME}:${CI_COMMIT_SHA} .- docker push ${DOCKER_REGISTRY}/${APP_NAME}:${CI_COMMIT_SHA}only:- main- develop# 部署阶段
.deploy_template: &deploy_templatestage: deployimage: bitnami/kubectl:latestscript:- kubectl set image deployment/${APP_NAME} ${APP_NAME}=${DOCKER_REGISTRY}/${APP_NAME}:${CI_COMMIT_SHA}- kubectl rollout status deployment/${APP_NAME}deploy_staging:<<: *deploy_templateenvironment:name: stagingonly:- developdeploy_production:<<: *deploy_templateenvironment:name: productionwhen: manualonly:- main
单体应用构建模板
# Jenkins Pipeline
pipeline {agent anyenvironment {JAVA_HOME = tool 'JDK11'MAVEN_HOME = tool 'Maven3'PATH = "${JAVA_HOME}/bin:${MAVEN_HOME}/bin:${PATH}"}stages {stage('Checkout') {steps {checkout scm}}stage('Build & Test') {steps {sh 'mvn clean package'}post {always {junit '**/target/surefire-reports/*.xml'jacoco(execPattern: '**/target/*.exec',classPattern: '**/target/classes',sourcePattern: '**/src/main/java')}}}stage('Code Quality') {steps {withSonarQubeEnv('SonarQube') {sh 'mvn sonar:sonar'}timeout(time: 10, unit: 'MINUTES') {waitForQualityGate abortPipeline: true}}}stage('Deploy to Staging') {when { branch 'develop' }steps {sh '''./deploy.sh stagingcurl -X POST -H "Content-Type: application/json" \-d '{"text":"Deployed to staging: ${BUILD_URL}"}' \${SLACK_WEBHOOK_URL}'''}}stage('Deploy to Production') {when { branch 'main'beforeInput true}input {message "Deploy to production?"ok "Yes, deploy it!"}steps {sh './deploy.sh production'}}}post {failure {emailext (subject: "Pipeline Failed: ${currentBuild.fullDisplayName}",body: "Pipeline failed - ${BUILD_URL}",recipientProviders: [[$class: 'DevelopersRecipientProvider']])}}
}#### 多阶段构建
```dockerfile
# 优化的多阶段 Dockerfile
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run buildFROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
缓存策略
# 依赖缓存配置
cache:paths:- node_modules/- .npm/key: ${CI_COMMIT_REF_SLUG}

⚡ Github Actions 实战

1. 🎯 Github Actions 工作流配置与实战技巧

复合工作流配置
# .github/workflows/composite.yml
name: Reusable Workflowon:workflow_call:inputs:environment:required: truetype: stringsecrets:deploy_key:required: truejobs:quality:name: Code Qualityuses: ./.github/workflows/quality.ymlsecurity:name: Security Scanuses: ./.github/workflows/security.ymldeploy:needs: [quality, security]runs-on: ubuntu-latestenvironment: ${{ inputs.environment }}steps:- name: Deployuses: ./.github/actions/deploywith:env: ${{ inputs.environment }}key: ${{ secrets.deploy_key }}
自定义 Action 开发
// action.yml
name: 'Custom Deployment Action'
description: 'Deploy application to different environments'
inputs:env:description: 'Target environment'required: truekey:description: 'Deployment key'required: trueruns:using: 'node16'main: 'dist/index.js'// src/index.ts
import * as core from '@actions/core'
import * as exec from '@actions/exec'async function run(): Promise<void> {try {const env = core.getInput('env')const key = core.getInput('key')// 配置环境await exec.exec('configure-env', [env, key])// 执行部署await exec.exec('deploy-app')// 验证部署const status = await exec.exec('verify-deployment')if (status !== 0) {throw new Error('Deployment verification failed')}core.setOutput('deployment_url', `https://${env}.example.com`)} catch (error) {if (error instanceof Error) core.setFailed(error.message)}
}run()#### 基础工作流模板
```yaml
name: CI/CD Pipelineon:push:branches: [ main, develop ]pull_request:branches: [ main ]jobs:build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v3- name: Setup Node.jsuses: actions/setup-node@v3with:node-version: '16'cache: 'npm'- name: Install dependenciesrun: npm ci- name: Run testsrun: npm test- name: Buildrun: npm run build- name: Deployif: github.ref == 'refs/heads/main'run: |echo "部署到生产环境"

2. 🔧 高级功能应用

矩阵构建
jobs:test:runs-on: ${{ matrix.os }}strategy:matrix:os: [ubuntu-latest, windows-latest]node: [14, 16, 18]steps:- uses: actions/checkout@v3- name: Use Node.js ${{ matrix.node }}uses: actions/setup-node@v3with:node-version: ${{ matrix.node }}- run: npm test
环境机密管理
jobs:deploy:runs-on: ubuntu-latestenvironment: productionsteps:- name: Deploy to AWSenv:AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_KEY }}run: |aws configure set aws_access_key_id $AWS_ACCESS_KEYaws configure set aws_secret_access_key $AWS_SECRET_KEYaws s3 sync ./dist s3://my-bucket/

🧪 自动化测试与部署

1. 📊 全方位测试策略与自动化实践

测试自动化框架选择
测试类型推荐框架适用场景特点
单元测试Jest/JUnit函数/类测试快速、隔离
集成测试Supertest/TestContainersAPI/服务测试真实环境
E2E测试Cypress/SeleniumUI功能测试用户视角
性能测试JMeter/k6负载测试可扩展性
自动化测试最佳实践
// tests/integration/user.service.spec.ts
import { TestContainer } from 'testcontainers';
import { UserService } from '../services/user.service';
import { DatabaseService } from '../services/database.service';describe('UserService Integration Tests', () => {let container;let userService: UserService;let dbService: DatabaseService;beforeAll(async () => {// 启动测试容器container = await new TestContainer("postgres:13").withExposedPorts(5432).withEnv("POSTGRES_DB", "testdb").withEnv("POSTGRES_USER", "test").withEnv("POSTGRES_PASSWORD", "test").start();// 初始化服务const dbConfig = {host: container.getHost(),port: container.getMappedPort(5432),database: "testdb",user: "test",password: "test"};dbService = new DatabaseService(dbConfig);userService = new UserService(dbService);// 运行数据库迁移await dbService.runMigrations();});afterAll(async () => {await container.stop();});beforeEach(async () => {await dbService.cleanDatabase();});it('should create new user with proper roles', async () => {// 准备测试数据const userData = {username: 'testuser',email: 'test@example.com',roles: ['USER', 'ADMIN']};// 执行测试const user = await userService.createUser(userData);// 验证结果expect(user).toBeDefined();expect(user.id).toBeDefined();expect(user.username).toBe(userData.username);expect(user.roles).toEqual(expect.arrayContaining(userData.roles));// 验证数据库状态const dbUser = await dbService.findUserById(user.id);expect(dbUser).toMatchObject(userData);});it('should handle concurrent user creation', async () => {// 准备并发请求const requests = Array(10).fill(null).map((_, i) => ({username: `user${i}`,email: `user${i}@example.com`,roles: ['USER']}));// 执行并发测试const results = await Promise.all(requests.map(data => userService.createUser(data)));// 验证结果expect(results).toHaveLength(10);expect(new Set(results.map(u => u.id))).toHaveLength(10);// 验证数据库一致性const dbUsers = await dbService.findAllUsers();expect(dbUsers).toHaveLength(10);});it('should properly handle user deletion', async () => {// 创建测试用户const user = await userService.createUser({username: 'deletetest',email: 'delete@example.com',roles: ['USER']});// 执行删除await userService.deleteUser(user.id);// 验证删除结果const dbUser = await dbService.findUserById(user.id);expect(dbUser).toBeNull();// 验证关联数据清理const userRoles = await dbService.findUserRoles(user.id);expect(userRoles).toHaveLength(0);});
});#### 测试金字塔实践
```javascript
// 单元测试示例
describe('UserService', () => {test('should create user', async () => {const user = await UserService.create({name: 'Test User',email: 'test@example.com'});expect(user).toBeDefined();expect(user.name).toBe('Test User');});
});// 集成测试示例
describe('User API', () => {test('should register user', async () => {const response = await request(app).post('/api/users').send({name: 'Test User',email: 'test@example.com',password: 'password123'});expect(response.status).toBe(201);expect(response.body.user).toBeDefined();});
});
测试覆盖率监控
# Jest 配置
jest:collectCoverage: truecoverageThreshold:global:branches: 80functions: 80lines: 80statements: 80

2. 📦 自动化部署策略

蓝绿部署
#!/bin/bash# 蓝绿部署脚本
deploy_blue_green() {# 部署新版本(绿)kubectl apply -f green-deployment.yaml# 等待新版本就绪kubectl rollout status deployment/green# 切换流量kubectl patch service main -p '{"spec":{"selector":{"version":"green"}}}'# 清理旧版本(蓝)kubectl delete -f blue-deployment.yaml
}
金丝雀发布
# 金丝雀发布配置
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:name: example-rollout
spec:replicas: 10strategy:canary:steps:- setWeight: 20- pause: {duration: 1h}- setWeight: 40- pause: {duration: 1h}- setWeight: 60- pause: {duration: 1h}- setWeight: 80- pause: {duration: 1h}

📈 监控与反馈

1. 🔍 性能监控

Prometheus 监控配置
global:scrape_interval: 15sscrape_configs:- job_name: 'spring-actuator'metrics_path: '/actuator/prometheus'static_configs:- targets: ['localhost:8080']
Grafana 告警规则
alerting:alert_rules:- name: high_error_rateexpr: rate(http_requests_total{status=~"5.."}[5m]) > 0.1for: 5mlabels:severity: criticalannotations:description: High error rate detected

2. 📊 数据分析与优化

部署成功率统计
def analyze_deployment_metrics():success_rate = (successful_deployments / total_deployments) * 100avg_deployment_time = sum(deployment_times) / len(deployment_times)return {'success_rate': success_rate,'avg_deployment_time': avg_deployment_time,'failed_reasons': count_failure_reasons()}

💡 最佳实践建议

1. 🎯 流程优化

  • 实施团队代码审查机制
  • 建立统一的版本发布流程
  • 规范化配置管理
  • 自动化文档生成
  • 定期进行安全扫描

2. 🛡 安全性考虑

  • 使用凭证管理服务
  • 实施最小权限原则
  • 定期更新依赖
  • 配置安全扫描
  • 审计日志管理

📚 推荐资源

  • Github Actions 官方文档
  • Jenkins 最佳实践指南
  • Kubernetes 部署策略
  • DevOps 工具链

🎉 总结

构建高效的自动化工作流需要注意以下几点:

  1. 🔄 设计合理的 CI/CD 流程,确保代码质量
  2. ⚡ 充分利用 Github Actions 的特性,提高自动化程度
  3. 🧪 实施全面的测试策略,保障系统稳定性
  4. 📊 建立完善的监控体系,及时发现并解决问题

记住:自动化不是目的,而是提高团队效率和产品质量的手段!


💡 提示:本文介绍的实践和策略需要根据具体项目和团队情况进行调整。持续优化和改进是提升自动化效率的关键。

如果你觉得这篇文章有帮助,欢迎点赞转发,也期待在评论区看到你的想法和建议!👇

咱们下一期见!

相关文章:

自动化工作流建设指南

&#x1f680; 自动化工作流建设指南&#xff1a;CI/CD、Github Actions与自动化测试部署 打造现代化的自动化工作流&#xff0c;提升团队开发效率。今天咱们将深入探讨 CI/CD 最佳实践、Github Actions 实战经验以及自动化测试与部署策略。 &#x1f4d1; 目录 CI/CD 最佳实践…...

[免费]SpringBoot+Vue3校园宿舍管理系统(优质版)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue3校园宿舍管理系统(优质版)&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue3校园宿舍管理系统(优质版) Java毕业设计_哔哩哔哩_bilibili 项目介绍 随着信息技术的不断发展&…...

SNK施努卡 - 机器人测温取样系统

机械手测温取样系统 有色行业自动化 机器人&#xff1a;机械手测温取样系统是以工业机器人为平台&#xff0c;技术相对成熟稳定&#xff0c;利用机器人的灵活性&#xff0c;自动往测温取样枪上安装探头&#xff0c;自动将探头伸进高温铜水内进行测温取样&#xff0c;自动拆除废…...

goframe开发一个企业网站 验证码17

Go验证码功能实现详解 目录结构 ├── internal │ ├── controller │ │ └── captcha │ │ └── captcha.go │ ├── logic │ │ └── captcha │ │ └── captcha.go │ └── service │ └── captcha.go1. Serv…...

【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题

目录 1. 单例模式 (1) 饿汉模式 (2) 懒汉模式 1. 单线程版本 2. 多线程版本 2. 解决懒汉模式产生的线程安全问题 (1) 产生线程安全的原因 (2) 解决线程安全问题 1. 通过加锁让读写操作紧密执行 方法一 方法二 2. 处理加锁引入的新问题 问题描述 …...

MySQL电商多级分类表设计方案对比

MySQL电商多级分类表设计方案对比 在电商系统中&#xff0c;多级分类是一个常见的需求&#xff0c;用于组织和管理商品类别&#xff0c;合理的设计可以提高系统的性能和可维护性。本文将详细介绍三种不同的多级分类表设计方案&#xff0c;我们将使用宠物分类作为示例数据&…...

网络安全工程师需要知道哪些IPSec的基本原理?

IPSec是一种端到端的安全协议&#xff0c;为IP数据包提供认证、完整性和加密服务。它通过在IP层实现安全功能&#xff0c;确保数据在传输过程中的机密性、完整性和真实性。IPSec广泛应用于VPN、远程访问和企业内部网络通信等领域&#xff0c;是保护互联网通信安全的重要手段。 …...

leetcode 148. 排序链表 中等

给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5]示例 3&#xff1a; …...

动态规划与贪心算法:核心区别与实例分析

动态规划与贪心算法&#xff1a;核心区别与实例分析 动态规划和贪心算法是计算机科学中用于解决优化问题的两种著名方法。它们各自的思路和应用场景有显著的区别&#xff0c;理解这些区别对解决相关问题至关重要。本文将详细探讨这两种算法的最优子结构、解法策略、适用场景&a…...

.NET 公共语言运行时(Common Language Runtime,CLR)

.NET 的公共语言运行时&#xff08;Common Language Runtime&#xff0c;CLR&#xff09;是 .NET Framework 和 .NET Core 的核心组件&#xff0c;负责运行和管理 .NET 程序。CLR 提供了一个高效、安全和稳定的执行环境&#xff0c;支持多种编程语言并处理各种系统级的任务。下…...

SpringBoot使用TraceId日志链路追踪

项目场景&#xff1a; 有时候一个业务调用链场景&#xff0c;很长&#xff0c;调了各种各样的方法&#xff0c;看日志的时候&#xff0c;各个接口的日志穿插&#xff0c;确实让人头大。为了解决这个痛点&#xff0c;就使用了TraceId&#xff0c;根据TraceId关键字进入服务器查询…...

YOLO11 旋转目标检测 | OBB定向检测 | ONNX模型推理 | 旋转NMS

本文分享YOLO11中&#xff0c;从xxx.pt权重文件转为.onnx文件&#xff0c;然后使用.onnx文件&#xff0c;进行旋转目标检测任务的模型推理。 用ONNX模型推理&#xff0c;便于算法到开发板或芯片的部署。 本文提供源代码&#xff0c;支持不同尺寸图片输入、支持旋转NMS过滤重复…...

PCL 点云拟合 拟合空间直线

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 设置RANSAC算法参数 2.1.2拟合直线模型 2.1.3 提取拟合直线内点 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接: PCL点云算法与项目实战案例汇总(长期更…...

我的创作纪念日-20241112-感谢困难

我的创作纪念日-20241112-感谢困难 一、机缘二、收获1、积累2、感谢困难 三、日常四、成就五、憧憬 一、机缘 我之前有一个自己的私人博客&#xff0c;但是后来发现CSDN的功能更强大&#xff0c;更专业&#xff0c;所以我就把自己博客内容转到CSDN上面来了。 二、收获 1、积累…...

苍穹外卖05-Redis相关知识点

目录 什么是Redis&#xff1f; redis中的一些常用指令 value的5种常用数据类型 各种数据类型的特点 Redis中数据操作的常用命令 字符串类型常用命令&#xff1a; 哈希类型常用命令 列表操作命令 集合操作命令 有序集合操作命令 通用命令 在java中操作Redis 环境…...

unity 玩家和炸弹切线计算方式

脚本挂在炸弹上&#xff01; using System.Collections; using System.Collections.Generic; using UnityEngine;public class TargetDetaction : MonoBehaviour {private Transform PlayerTF;private Transform bomb;private float radius;private string Player "Play…...

【MySQL】MySQL中的函数之REGEXP_LIKE

在 MySQL 中&#xff0c;REGEXP_LIKE() 函数用于检查一个字符串是否与正则表达式匹配。不过需要注意的是&#xff0c;REGEXP_LIKE() 并不是所有版本的 MySQL 都支持的函数。这个函数是在 MySQL 8.0 版本中引入的。 基本语法 REGEXP_LIKE(str, pat [, match_type ])str: 要测试…...

跟着尚硅谷学vue2—进阶版4.0—Vuex1.0

5. Vuex 1. 理解 Vuex 1. 多组件共享数据-全局事件总线实现 红线是读&#xff0c;绿线是写 2. 多组件共享数据-vuex实现 vuex 不属于任何组件 3. 求和案例-纯vue版 核心代码 1.Count.vue <template><div><h1>当前求和为&#xff1a;{{ sum }}</h1&…...

深度学习服务器租赁AutoDL

省钱绝招 #AutoDL #GPU #租显卡...

excel常用技能

1.基础技能 1.1 下拉框设置 a. 选中需要设置的列或单元格&#xff0c;数据 ---》 数据验证 b.验证条件 ---> 序列&#xff08;多个值逗号隔开&#xff09; 1.2 进度条百分比显示设置 开始 ---> 条件格式 --->新建规则--->编辑规则 1.3 相对引用和绝对引用…...

并行硬件环境及并行编程

文章目录 A1. (并行编程 基于的)硬件环境 的 基本模型A2. 特定的硬件实现B1. 并行编程基本模型与编程技术✅ 并行编程的一般流程**第一阶段&#xff1a;基于“编程直觉模型”设计程序****第二阶段&#xff1a;程序编译并部署到实际硬件** B2.特定的 硬件环境下的 并行编程 A1. …...

【Linux】awk 命令详解及使用示例:结构化文本数据处理工具

【Linux】awk 命令详解及使用示例&#xff1a;结构化文本数据处理工具 引言 awk 是一种强大的文本处理工具和编程语言&#xff0c;专为处理结构化文本数据而设计。它的名称来源于其三位创始人的姓氏首字母&#xff1a;Alfred Aho、Peter Weinberger 和 Brian Kernighan。 基…...

gRPC 的四种通信模式完整示例

gRPC 的四种基本通信模式&#xff0c;包括完整的 .proto 文件定义和 Go 语言实现代码&#xff1a; 1. 简单 RPC (Unary RPC) - 请求/响应模式 客户端发送单个请求&#xff0c;服务端返回单个响应 calculator.proto protobuf syntax "proto3";package calculato…...

使用Conda管理服务器多版本Python环境的完整指南

在服务器环境中管理多个Python版本是开发者和系统管理员常见的需求&#xff0c;尤其是当不同项目依赖特定版本的Python时。本文将重点介绍如何通过Conda实现多版本Python的隔离与管理&#xff0c;确保服务器环境的稳定性和灵活性。 为什么需要多版本Python管理&#xff1f; 服…...

JavaScript 中的单例内置对象:Global 与 Math 的深度解析

JavaScript 中的单例内置对象&#xff1a;Global 与 Math 的深度解析 在 JavaScript 的世界中&#xff0c;单例内置对象是开发者必须了解的核心概念之一。它们是语言规范中预定义的对象&#xff0c;无需显式创建即可直接使用。本文将深入解析 JavaScript 中最重要的两个单例内…...

MySQL体系架构解析(二):MySQL目录与启动配置全解析

MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录&#xff0c;这个目录下存放着许多可执行文件。与其他系统的可执行文件类似&#xff0c;这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中&#xff0c;用…...

飞牛使用Docker部署Tailscale 内网穿透教程

之前发过使用docker部署Tailscale的教程&#xff0c;不过是一年前的事情了&#xff0c;今天再重新发表一遍&#xff0c;这次使用compose部署更加方便&#xff0c;教程也会更加详细一点&#xff0c;希望对有需要的朋友有所帮助&#xff01; 对于大部分用户来说&#xff0c;白嫖 …...

2025服装收银系统推荐:智能管理助力服装商家高效经营

在服装批发零售行业&#xff0c;一套高效的收银系统不仅能简化日常经营流程&#xff0c;还能通过数据分析帮助商家优化库存、提升销售。随着AI技术的普及&#xff0c;现代收银系统已不再局限于简单的记账功能&#xff0c;而是能提供智能选品、库存预警、精准营销等进阶服务。 …...

入门AJAX——XMLHttpRequest(Post)

一、前言 在上篇文章中&#xff0c;我们已经介绍了 HMLHttpRequest 的GET 请求的基本用法&#xff0c;并基于我提供的接口练习了两个简单的例子。如果你还没有看过第一篇文章&#xff0c;强烈建议你在学习完上篇文章后再学习本篇文章&#xff1a; &#x1f517;入门AJAX——XM…...

【Android基础回顾】二:handler消息机制

Android 的 Handler 机制 是 Android 应用中实现线程间通信、任务调度、消息分发的核心机制之一&#xff0c;它基于 消息队列&#xff08;MessageQueue&#xff09; 消息循环&#xff08;Looper&#xff09; 消息处理器&#xff08;Handler&#xff09; 组成。 1 handler的使用…...