Android离线点餐系统:SQLite+ContentProvider轻量架构实战
简介本资源是一份面向计算机专业本科生及移动应用开发初学者的Android智能点餐系统课程设计文档聚焦餐饮场景下的移动端Web端协同开发实践解决传统点餐流程效率低、信息同步难、管理粗放等实际问题。文档完整呈现了基于EclipseJavaTomcatMySQL的技术栈选型依据、MVC分层架构设计逻辑、WebService跨平台数据交互实现方案以及用户注册登录、供/点餐信息发布、购物车、订单管理、顾客反馈等核心功能模块的设计与测试过程。资源为单个PDF文件1.4MB内容涵盖开发工具配置、关键技术原理JDBC数据库访问、HTTP通信机制、客户端Activity交互设计、C/S架构部署示意图及系统功能测试用例图文结合结构清晰便于理解前后端协同逻辑。目前已有152人学习下载适合开展课程设计、毕业设计参考或AndroidWeb全栈开发入门实践。1. 一个跑在安卓手机上的点餐系统为什么不能只靠“做个App”就完事你手里的外卖App背后是千万级并发的云服务、实时库存校验、支付风控和骑手调度算法而校园食堂、社区小餐馆、连锁茶饮店的智能点餐系统恰恰相反——它必须在无稳定Wi-Fi、低配安卓设备、离线可操作、老板自己会改菜单的前提下把“扫码→选品→下单→打印小票”闭环跑通。这不是炫技的Demo而是每天早八点排队高峰时扫码枪扫不出、菜品图片加载失败、订单卡在“提交中”就直接导致顾客转身离开的真实战场。本篇讲的就是如何用Android原生能力不依赖第三方SDK或云端中间件构建一个可离线运行、菜单热更新、本地打印支持、权限精简可控的轻量级智能点餐系统。面向的是中小餐饮场景的技术负责人、高职院校电子系统设计课程学生以及需要交付可维护、可审计、无黑盒依赖的嵌入式软件工程师——它不追求高并发但必须每一步都可追溯、可调试、可降级。2. 用Android Studio构建最小可行点餐架构Activity SQLite ContentProvider 的三支柱设计2.1 为什么放弃Room和Jetpack Compose从部署现场倒推技术选型在社区老年食堂部署时我们遇到过三类典型设备2018年款红米Note5Android 8.1、2020年款华为畅享20Android 10、2022年款vivo Y33sAndroid 12。它们共性是系统WebView老旧、Google Play Services缺失、后台进程被厂商强杀。此时若采用Room数据库其编译期注解处理器在低版本AGPAndroid Gradle Plugin下易报annotationProcessor冲突若用Compose需强制升级到AndroidX Activity 1.8而旧设备上androidx.activity:activity-compose的rememberLauncherForActivityResult在Android 8.1上会触发NoSuchMethodError。因此本系统采用原生SQLiteOpenHelper 手动Cursor管理 ContentProvider封装数据访问层——它不依赖任何Jetpack组件API Level 14Android 4.0起即完全兼容且所有SQL语句可直接在ADB shell中验证adb shell sqlite3 /data/data/com.example.smartorder/databases/order.db .tables SELECT name FROM sqlite_master WHERE typetable;提示ContentProvider在此并非为跨应用共享数据而是为统一约束CRUD入口、避免多Activity直接操作SQLiteDatabase实例导致的线程锁死。即使单进程它也提供了query()方法的CancellationSignal支持防止列表滚动时查询阻塞UI线程。2.2 数据库表结构设计兼顾离线一致性与菜单动态扩展核心表仅两张menu_items菜品主表和orders订单主表无外键约束SQLite外键默认关闭且影响写入性能通过应用层逻辑保证一致性表名字段类型说明menu_items_idINTEGER PRIMARY KEY AUTOINCREMENT自增主键非业务IDitem_codeTEXT UNIQUE NOT NULL业务唯一码如TEA-001用于扫码匹配nameTEXT NOT NULL菜品名称UTF-8支持中文priceREAL NOT NULL DEFAULT 0.0单价REAL类型避免浮点精度问题categoryTEXT DEFAULT default分类标签用于RecyclerView分组image_pathTEXT本地文件路径如/storage/emulated/0/SmartOrder/images/tea001.jpgis_availableINTEGER DEFAULT 10下架1上架控制前台可见性orders_idINTEGER PRIMARY KEY AUTOINCREMENT订单自增IDorder_noTEXT UNIQUE NOT NULL业务订单号格式YYYYMMDDHHmmSS-XXXXXstatusTEXT CHECK(status IN (draft,submitted,printed,cancelled))状态机避免非法流转created_atINTEGER NOT NULL时间戳毫秒用于排序和超时判断items_jsonTEXT NOT NULLJSON字符串存储菜品明细含item_code、quantity、notes2.2.1 关键设计决策说明item_code而非_id作为扫码匹配字段扫码枪输出为纯文本若用自增ID每次APP重装后ID重置导致历史菜单无法关联而item_code由运营人员在后台Excel中维护导出CSV后由ContentProvider批量导入。items_json字段替代关联表避免多表JOIN在低端机上卡顿JSON解析用org.json.JSONObjectAPI Level 1起内置不引入Gson或Jackson增加包体积订单详情页用TextView.setText()直接渲染JSON格式化字符串省去RecyclerView嵌套。is_available字段实现软下架前端ListView的Adapter.getView()中过滤is_available0项无需删除数据保留销售统计依据。2.3 ContentProvider实现暴露安全的数据访问接口在AndroidManifest.xml中声明Provider禁用android:exportedtrueAndroid 12强制要求provider android:name.data.MenuContentProvider android:authoritiescom.example.smartorder.menu android:exportedfalse android:permissioncom.example.smartorder.permission.MENU_ACCESS /MenuContentProvider.java中query()方法严格校验projection只允许返回指定字段和selection禁止11注入Override public Cursor query(NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db dbHelper.getReadableDatabase(); // 白名单校验projection ListString allowedColumns Arrays.asList(_id, item_code, name, price, category, is_available); if (projection ! null) { for (String col : projection) { if (!allowedColumns.contains(col)) { throw new IllegalArgumentException(Invalid column: col); } } } // 防注入selectionArgs必须非空且selection中?占位符数等于args长度 if (selection ! null (selectionArgs null || selectionArgs.length 0)) { throw new IllegalArgumentException(Selection requires arguments); } return db.query(menu_items, projection, selection, selectionArgs, null, null, sortOrder); }注意selectionArgs参数必须使用这是SQLite防SQL注入的唯一可靠方式。曾有团队直接拼接name LIKE % keyword %导致输入% OR 11 --即可绕过所有条件。3. 扫码与本地打印不依赖厂商SDK的硬件交互落地方案3.1 通用扫码集成用Intent Filter捕获USB/蓝牙扫码枪输入多数商用扫码枪工作在HID Keyboard模式——即插即用无需驱动。其原理是将扫描结果模拟为键盘输入因此无需申请CAMERA权限也不用调用CameraX API。只需在MainActivity中重写onKeyDown()捕获连续输入的字符流private StringBuilder scanBuffer new StringBuilder(); private long lastInputTime 0; Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (event.getAction() KeyEvent.ACTION_DOWN) { if (keyCode KeyEvent.KEYCODE_0 keyCode KeyEvent.KEYCODE_9) { scanBuffer.append((char) (0 keyCode - KeyEvent.KEYCODE_0)); } else if (keyCode KeyEvent.KEYCODE_ENTER) { String scannedCode scanBuffer.toString().trim(); if (!scannedCode.isEmpty()) { handleScannedItem(scannedCode); // 查找菜品并加入购物车 } scanBuffer.setLength(0); // 清空缓冲区 return true; } else if (keyCode KeyEvent.KEYCODE_DEL) { if (scanBuffer.length() 0) scanBuffer.deleteCharAt(scanBuffer.length() - 1); } } return super.onKeyDown(keyCode, event); } private void handleScannedItem(String code) { Cursor cursor getContentResolver().query( Uri.parse(content://com.example.smartorder.menu/menu_items), new String[]{_id, name, price}, item_code ? AND is_available 1, new String[]{code}, null ); if (cursor ! null cursor.moveToFirst()) { String name cursor.getString(cursor.getColumnIndexOrThrow(name)); double price cursor.getDouble(cursor.getColumnIndexOrThrow(price)); addToCart(name, price, code); cursor.close(); } else { Toast.makeText(this, 未找到商品 code, Toast.LENGTH_SHORT).show(); } }3.1.1 适配不同扫码枪的回车键差异部分扫码枪发送KEYCODE_NUMPAD_ENTER数字小键盘回车需在onKeyDown()中补充判断} else if (keyCode KeyEvent.KEYCODE_NUMPAD_ENTER) { // 同KEYCODE_ENTER处理逻辑 }提示测试时用adb shell input keyevent KEYCODE_0模拟按键比反复插拔扫码枪更高效。若扫码后无反应先检查Logcat中是否输出onKeyDown日志确认焦点在Activity上非Dialog或EditText获取了焦点。3.2 本地热敏打印机驱动用BluetoothSocket直连ESC/POS指令避开厂商SDK如Bixolon、Star的闭源jar包采用标准蓝牙SPP协议发送ESC/POS指令。关键步骤3.2.1 获取已配对蓝牙设备列表BluetoothAdapter adapter BluetoothAdapter.getDefaultAdapter(); SetBluetoothDevice pairedDevices adapter.getBondedDevices(); for (BluetoothDevice device : pairedDevices) { if (device.getName().toLowerCase().contains(printer)) { // 按名称模糊匹配 connectPrinter(device); break; } }3.2.2 发送打印指令以打印小票为例private void printReceipt(String orderNo, ListOrderItem items, double total) { try { OutputStream os bluetoothSocket.getOutputStream(); // 初始化打印机 os.write(new byte[]{0x1B, 0x40}); // 设置居中对齐 os.write(new byte[]{0x1B, 0x61, 0x01}); os.write(【智能点餐】\n.getBytes(StandardCharsets.UTF_8)); os.write((订单号 orderNo \n).getBytes(StandardCharsets.UTF_8)); os.write(----------------------------\n.getBytes(StandardCharsets.UTF_8)); for (OrderItem item : items) { String line String.format(%-12s %dx %.2f\n, item.name, item.quantity, item.price * item.quantity); os.write(line.getBytes(StandardCharsets.UTF_8)); } os.write((总计¥ String.format(%.2f, total) \n).getBytes(StandardCharsets.UTF_8)); os.write(----------------------------\n.getBytes(StandardCharsets.UTF_8)); os.write(谢谢惠顾\n.getBytes(StandardCharsets.UTF_8)); // 切纸指令部分机型需 os.write(new byte[]{0x1D, 0x56, 0x01}); os.flush(); } catch (IOException e) { Log.e(Printer, Print failed, e); Toast.makeText(this, 打印失败 e.getMessage(), Toast.LENGTH_LONG).show(); } }3.2.3 权限与Android 12适配要点AndroidManifest.xml中声明uses-permission android:nameandroid.permission.BLUETOOTH / uses-permission android:nameandroid.permission.BLUETOOTH_ADMIN / uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION / !-- Android 12扫描必需 --Android 12需在build.gradle中添加android { compileSdk 33 defaultConfig { targetSdk 33 } }运行时请求ACCESS_FINE_LOCATION仅用于发现蓝牙设备不要请求BLUETOOTH_CONNECT该权限需用户手动在设置中开启体验极差。4. 菜单热更新与离线优先策略用Asset目录版本号控制实现零停机更新4.1 菜单数据源设计CSV文件托管于assets目录APP启动时自动加载将menu.csv放入app/src/main/assets/目录格式如下item_code,name,price,category,image_filename,is_available COFFEE-001,美式咖啡,18.0,饮品,coffee001.jpg,1 TEA-002,茉莉花茶,12.0,饮品,tea002.jpg,1 SNACK-003,薯条,8.0,小吃,snack003.jpg,0首次安装或版本升级时Application.onCreate()中执行private void loadMenuFromAssets() { try { InputStream is getAssets().open(menu.csv); BufferedReader reader new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); String line; ContentValues values new ContentValues(); while ((line reader.readLine()) ! null) { String[] cols line.split(,); if (cols.length 6) continue; // 跳过标题行或格式错误行 values.clear(); values.put(item_code, cols[0].trim()); values.put(name, cols[1].trim()); values.put(price, Double.parseDouble(cols[2].trim())); values.put(category, cols[3].trim()); values.put(image_path, /assets/images/ cols[4].trim()); // 统一前缀 values.put(is_available, Integer.parseInt(cols[5].trim())); getContentResolver().insert( Uri.parse(content://com.example.smartorder.menu/menu_items), values ); } reader.close(); } catch (IOException | NumberFormatException e) { Log.e(MenuLoader, Load menu failed, e); } }4.2 版本控制机制用SharedPreferences记录当前菜单版本号在assets/menu.csv同级放置menu_version.txt内容仅为纯数字如20231015。APP启动时对比本地版本与assets中版本private boolean isMenuOutdated() { SharedPreferences prefs getSharedPreferences(config, MODE_PRIVATE); String currentVersion prefs.getString(menu_version, 0); try { InputStream is getAssets().open(menu_version.txt); BufferedReader reader new BufferedReader(new InputStreamReader(is)); String latestVersion reader.readLine().trim(); reader.close(); return !currentVersion.equals(latestVersion); } catch (IOException e) { return false; } } private void updateMenu() { // 先清空旧数据 getContentResolver().delete( Uri.parse(content://com.example.smartorder.menu/menu_items), null, null ); // 再加载新CSV loadMenuFromAssets(); // 更新版本号 SharedPreferences prefs getSharedPreferences(config, MODE_PRIVATE); prefs.edit().putString(menu_version, getCurrentVersionFromAssets()).apply(); }提示此方案规避了网络请求失败导致的菜单空白风险——即使服务器宕机APP仍能加载assets中上一版菜单。运营人员只需替换APK中的assets文件重新签名发布即可完成菜单更新无需后台系统。5. 实战排错从Logcat定位5类高频崩溃与ANR根源5.1 数据库事务未关闭导致的ANRApplication Not Responding现象点击“提交订单”后界面卡死10秒弹出ANR对话框。根因ContentProvider.insert()中开启了db.beginTransaction()但未调用db.setTransactionSuccessful()和db.endTransaction()。修复代码模板Override public Uri insert(NonNull Uri uri, Nullable ContentValues values) { SQLiteDatabase db dbHelper.getWritableDatabase(); db.beginTransaction(); try { long id db.insert(orders, null, values); if (id -1) throw new SQLException(Failed to insert order); db.setTransactionSuccessful(); // 必须在endTransaction前调用 return ContentUris.withAppendedId(uri, id); } finally { db.endTransaction(); // 必须在finally中确保执行 } }5.2 图片加载OOMBitmapFactory.Options.inSampleSize计算失误现象打开菜单页闪退Logcat显示java.lang.OutOfMemoryError: Failed to allocate a 12582924 byte allocation。根因直接BitmapFactory.decodeFile(path)加载全尺寸图未按ImageView尺寸缩放。正确做法在ListView.Adapter.getView()中private Bitmap decodeSampledBitmapFromPath(String path, int reqWidth, int reqHeight) { final BitmapFactory.Options options new BitmapFactory.Options(); options.inJustDecodeBounds true; // 先读取尺寸不分配内存 BitmapFactory.decodeFile(path, options); options.inSampleSize calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds false; return BitmapFactory.decodeFile(path, options); } private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height options.outHeight; final int width options.outWidth; int inSampleSize 1; if (height reqHeight || width reqWidth) { final int halfHeight height / 2; final int halfWidth width / 2; while ((halfHeight / inSampleSize) reqHeight (halfWidth / inSampleSize) reqWidth) { inSampleSize * 2; } } return inSampleSize; }5.3 蓝牙连接超时Socket连接未设timeout现象点击“连接打印机”后无响应Logcat无错误日志。根因bluetoothSocket.connect()默认无限等待需显式设置// 创建Socket后connect前 bluetoothSocket device.createRfcommSocketToServiceRecord(MY_UUID); // 设置10秒超时 bluetoothSocket.connect(); // 此处可能阻塞应改为Method m device.getClass().getMethod(createRfcommSocket, int.class); bluetoothSocket (BluetoothSocket) m.invoke(device, 1); // 使用反射调用带timeout的connectAndroid 10原生支持 if (Build.VERSION.SDK_INT Build.VERSION_CODES.Q) { bluetoothSocket.connect(10000); // 10秒超时 } else { // 旧版本用线程Handler模拟超时 new Thread(() - { try { bluetoothSocket.connect(); handler.sendEmptyMessage(0); // 连接成功 } catch (IOException e) { handler.sendEmptyMessage(1); // 连接失败 } }).start(); }5.4 权限拒绝后功能不可用未检查Permission Granted状态现象Android 12设备上首次启动点击扫码无反应。根因未在onResume()中检查BLUETOOTH_CONNECT权限虽不推荐请求但需兼容。检测逻辑private boolean isBluetoothPermissionGranted() { if (Build.VERSION.SDK_INT Build.VERSION_CODES.S) { return ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) PackageManager.PERMISSION_GRANTED; } return true; // Android 11及以下无需此权限 }5.5 ContentProvider URI匹配失败authority拼写错误现象getContentResolver().query()返回nullLogcat提示java.lang.IllegalArgumentException: Unknown URL。根因Uri.parse(content://com.example.smartorder.menu/menu_items)中的authority与AndroidManifest.xml中provider android:authorities...不一致。验证命令adb shell dumpsys package com.example.smartorder | grep authorities # 输出应包含authoritiescom.example.smartorder.menu若不一致修改Manifest中android:authorities值并同步更新所有URI字符串。6. 进阶技巧用ADB命令快速验证系统状态与数据一致性6.1 一键导出SQLite数据库供离线分析当用户报告“订单提交后消失”需确认数据是否真正写入。在开发机上执行# 进入设备shell adb shell # 切换到APP数据目录需root或debuggable APK cd /data/data/com.example.smartorder/databases/ # 将数据库复制到sdcard无需root cp order.db /sdcard/order_debug.db exit # 拉取到本地 adb pull /sdcard/order_debug.db ./order_debug.db然后用DB Browser for SQLite打开order_debug.db执行SQL验证-- 检查最新5条订单 SELECT order_no, status, created_at, items_json FROM orders ORDER BY _id DESC LIMIT 5; -- 检查是否存在未提交的草稿订单 SELECT COUNT(*) FROM orders WHERE status draft; -- 检查菜品表数据完整性 SELECT COUNT(*) FROM menu_items WHERE item_code IS NULL OR name IS NULL;6.2 模拟弱网环境测试离线能力用ADB禁用网络验证菜单加载与下单流程# 禁用所有网络 adb shell settings put global airplane_mode_on 1 adb shell am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true # 执行点餐操作扫码、加购、提交 # ... 操作完成后恢复网络 adb shell settings put global airplane_mode_on 0 adb shell am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false若订单在恢复网络后自动同步本系统不自动同步需手动触发则说明设计符合离线优先原则。6.3 打印指令调试用串口助手发送原始字节当热敏打印机不响应时跳过APP直接发送ESC/POS指令验证硬件# 将打印机通过USB转串口连接电脑 # 用Serial Port UtilityWindows或screenmacOS/Linux连接 # 发送十六进制指令1B 40 初始化 echo -ne \x1B\x40 /dev/ttyUSB0 # 发送1B 61 01 居中 echo -ne \x1B\x61\x01 /dev/ttyUSB0 # 发送文字UTF-8编码 echo -e 测试打印\n /dev/ttyUSB0若硬件正常打印则问题在APP的BluetoothSocket数据流若不打印则检查打印机波特率通常9600、协议模式SPP及电源状态。提示所有ADB命令均需在android.app.Application子类的onCreate()中启用android:debuggabletrue生产APK发布前必须设为false。本文还有配套的精品资源点击获取

相关新闻

带式输送机PLC控制系统设计:从张力计算到软起动参数整定

带式输送机PLC控制系统设计:从张力计算到软起动参数整定

简介:带式输送机的PLC控制设计说明文档,面向矿山、选矿、港口等工业场景中的连续运输设备,系统梳理了带式输送机的基本概念、国外动态分析研究现状、国内技术差距以及未来大型化、高带速、大运量等发展方向,并着重说明了PLC控制系…

2026/9/20 16:14:07 阅读更多 →
OpenAI 6/14 后 MCP 生产部署,模型侧 Base URL 走 TaoToken

OpenAI 6/14 后 MCP 生产部署,模型侧 Base URL 走 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/19 12:35:37 阅读更多 →
Excel单元格拆分全攻略:分列、智能填充、公式与VBA实战

Excel单元格拆分全攻略:分列、智能填充、公式与VBA实战

你从系统里导出一张流水表,打开一看差点没反应过来——姓名、部门、手机号全挤在一个单元格里,中间用逗号连着;日期和时间凑在一起;地址里直接扛着好几层省市区。这种数据,不拆分根本没法筛选,更谈不上做透…

2026/9/19 12:35:37 阅读更多 →

最新新闻

深入解析 Preact Table 的 AppHeaderContext 类型别名:表头上下文与预绑定 Header 组件机制

深入解析 Preact Table 的 AppHeaderContext 类型别名:表头上下文与预绑定 Header 组件机制

前端UI组件 【免费下载链接】table 🤖 Headless UI for building powerful tables & datagrids for TS/JS - React-Table, Vue-Table, Solid-Table, Svelte-Table 项目地址: https://gitcode.com/gh_mirrors/ta/table 点击查看 免费下载 AppHeaderC…

2026/9/20 17:02:23 阅读更多 →
交通科技大赛备赛指南:选题策略、方案设计与答辩技巧

交通科技大赛备赛指南:选题策略、方案设计与答辩技巧

简介:这份《交通科技大赛历届参赛作品.docx》系统整理了前三届全国大学生交通科技大赛的获奖与优秀作品目录及项目概述,面向交通类专业学生、竞赛指导老师及科研入门者。内容覆盖交通规划与管理、智能交通、交通安全、轨道与道路设计、物流与仿真等方向&…

2026/9/20 17:02:23 阅读更多 →
红外小目标检测:DASI与MDCR模块如何提升U-Net跳层连接性能

红外小目标检测:DASI与MDCR模块如何提升U-Net跳层连接性能

红外小目标检测这个方向,做过的人都知道那种痛。一张红外图像里,目标可能就几个像素大,背景还全是云层、地物、热噪声,信噪比低得让人想砸键盘。大多数方案都是拿U-Net做骨架,编码器一路下采样,解码器再一路…

2026/9/20 17:02:23 阅读更多 →
GitHub Copilot完全指南:从安装配置到进阶实战技巧

GitHub Copilot完全指南:从安装配置到进阶实战技巧

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 17:02:23 阅读更多 →
腾讯广告实战手册解读:从账户结构到素材优化的投放指南

腾讯广告实战手册解读:从账户结构到素材优化的投放指南

简介:这份PDF文件是腾讯公司推出的广告产品解决方案手册,面向广告主、媒体采购人员及数字营销从业者,旨在系统解答腾讯广告产品是什么、如何分类、有何优势,以及投放设置与常见问题应对。手册内容涵盖腾讯广告产品的图文、视频、移…

2026/9/20 17:02:23 阅读更多 →
2025保密教育知识题库高效备考指南:避开误区吃透核心考点

2025保密教育知识题库高效备考指南:避开误区吃透核心考点

简介:这份2025最新保密教育知识题库与答案文档,面向机关单位保密干部、涉密人员及参加保密教育培训的学员,用于系统复习保密法律法规、国家安全教育和密码安全知识。内容以选择题与判断题为主,覆盖全民国家安全教育日、涉密会议管…

2026/9/20 17:01:23 阅读更多 →

日新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →