# 🔧 Termux GUI Rust Demo 重构方案
## 📋 目录
1. [当前状态分析](#当前状态分析)
2. [重构目标](#重构目标)
3. [公共代码提取](#公共代码提取)
4. [库结构设计](#库结构设计)
5. [重构步骤](#重构步骤)
6. [兼容性保证](#兼容性保证)
7. [测试计划](#测试计划)
---
## 📊 当前状态分析
### ✅ 已实现的组件(验证工作的)
| TextView | ✅ 正常 | button_demo.rs, checkbox_demo.rs, etc. | 已验证 |
| EditText | ✅ 正常 | input_demo.rs | 已验证 |
| Button | ✅ 正常 | button_demo.rs | 已验证 |
| Checkbox | ✅ 正常 | checkbox_demo.rs | 已验证 |
| Switch | ✅ 正常 | switch_demo.rs | 已验证 |
| RadioButton | ✅ 正常 | radio_demo.rs | 已验证 |
| RadioGroup | ✅ 正常 | radio_demo.rs | 已验证 |
| Spinner | ⚠️ 需修复 | spinner_demo.rs | 显示问题 |
| LinearLayout | ✅ 正常 | 所有demo | 已验证 |
| NestedScrollView | ✅ 正常 | spinner_demo.rs | 已验证 |
**工作的示例文件:**
- ✅ button_demo.rs - 按钮计数器
- ✅ checkbox_demo.rs - 多选框
- ✅ input_demo.rs - 文本输入
- ✅ radio_demo.rs - 单选按钮
- ✅ switch_demo.rs - 开关
- ⚠️ spinner_demo.rs - 下拉列表(需修复级联更新)
- ✅ test_events.rs - 事件处理
**测试文件(可能不工作):**
- ❓ test_minimal_spinner.rs
- ❓ test_spinner_cascade.rs
- ❓ test_spinner_debug.rs
- ❓ test_spinner_fullscreen.rs
- ❓ test_spinner_simple.rs
### 🔍 代码重复分析
每个示例文件都重复实现了以下函数:
```rust
// 出现 12 次
fn generate_random_address() -> String
// 出现 11 次
fn bind_abstract_socket(name: &str) -> Result<UnixListener, Error>
// 出现 12 次
fn send_message(stream: &mut UnixStream, msg: &Value) -> Result<(), Error>
// 出现 12 次
fn read_message(stream: &mut UnixStream) -> Result<Value, Error>
// 出现 12 次
fn send_and_read(stream: &mut UnixStream, msg: &Value) -> Result<Value, Error>
```
**代码重复量:** 约 40-50 行 × 12 文件 = **480-600 行重复代码**
---
## 🎯 重构目标
### 主要目标
1. **消除代码重复** - 将公共函数提取到 `lib.rs`
2. **提供清晰的 API** - 创建易用的高层接口
3. **保持示例简洁** - 示例专注于展示组件用法
4. **不破坏现有功能** - 保证所有工作的示例继续工作
5. **便于扩展** - 为未来添加组件做准备
### 次要目标
1. 统一错误处理
2. 改进文档
3. 添加单元测试
4. 提供构建器模式(Builder Pattern)
---
## 📦 公共代码提取
### 第一阶段:核心通信层
```rust
// src/lib.rs 或 src/connection.rs
/// 核心通信模块
pub mod connection {
use std::os::unix::net::{UnixListener, UnixStream};
use std::io::{Read, Write, Error};
use serde_json::Value;
/// 生成随机socket地址
pub fn generate_random_address() -> String { ... }
/// 绑定抽象命名空间socket
pub fn bind_abstract_socket(name: &str) -> Result<UnixListener, Error> { ... }
/// 发送消息(不等待响应)
pub fn send_message(stream: &mut UnixStream, msg: &Value) -> Result<(), Error> { ... }
/// 读取消息
pub fn read_message(stream: &mut UnixStream) -> Result<Value, Error> { ... }
/// 发送消息并读取响应
pub fn send_and_read(stream: &mut UnixStream, msg: &Value) -> Result<Value, Error> { ... }
}
```
### 第二阶段:连接管理
```rust
/// 连接管理
pub struct Connection {
main_stream: UnixStream,
event_stream: UnixStream,
}
impl Connection {
/// 创建新连接
pub fn new() -> Result<Self, Error> { ... }
/// 发送消息(不等待响应)
pub fn send(&mut self, msg: &Value) -> Result<(), Error> { ... }
/// 发送并读取响应
pub fn send_read(&mut self, msg: &Value) -> Result<Value, Error> { ... }
/// 获取事件流
pub fn event_stream(&mut self) -> &mut UnixStream { ... }
}
```
### 第三阶段:Activity 管理
```rust
/// Activity 表示一个GUI窗口
pub struct Activity {
conn: Connection,
aid: i64,
dialog: bool,
}
impl Activity {
/// 创建新 Activity
pub fn new(dialog: bool) -> Result<Self, Error> { ... }
/// 获取 Activity ID
pub fn id(&self) -> i64 { ... }
/// 创建 TextView
pub fn create_text_view(&mut self, text: &str, parent: Option<i64>) -> Result<TextView, Error> { ... }
/// 创建 Button
pub fn create_button(&mut self, text: &str, parent: Option<i64>) -> Result<Button, Error> { ... }
// 其他组件创建方法...
}
```
### 第四阶段:组件封装
```rust
/// 组件基类
pub struct View {
activity: *mut Activity, // 或使用 Rc<RefCell<Activity>>
id: i64,
}
impl View {
pub fn id(&self) -> i64 { self.id }
pub fn set_width(&mut self, width: i32) -> Result<(), Error> { ... }
pub fn set_height(&mut self, height: i32) -> Result<(), Error> { ... }
pub fn set_margin(&mut self, margin: i32) -> Result<(), Error> { ... }
}
/// TextView 组件
pub struct TextView {
view: View,
}
impl TextView {
pub fn new(activity: &mut Activity, text: &str, parent: Option<i64>) -> Result<Self, Error> { ... }
pub fn set_text(&mut self, text: &str) -> Result<(), Error> { ... }
pub fn set_text_size(&mut self, size: i32) -> Result<(), Error> { ... }
pub fn set_text_color(&mut self, color: i32) -> Result<(), Error> { ... }
}
/// Button 组件
pub struct Button {
view: View,
}
impl Button {
pub fn new(activity: &mut Activity, text: &str, parent: Option<i64>) -> Result<Self, Error> { ... }
pub fn set_text(&mut self, text: &str) -> Result<(), Error> { ... }
}
// 其他组件...
```
---
## 🏗️ 库结构设计
### 推荐的目录结构
```
termux-gui-rust-demo/
├── Cargo.toml
├── src/
│ ├── lib.rs # 库入口,导出所有公共API
│ ├── connection.rs # 底层连接管理
│ ├── activity.rs # Activity 管理
│ ├── view.rs # View 基类
│ ├── components/ # 各种UI组件
│ │ ├── mod.rs
│ │ ├── text_view.rs
│ │ ├── button.rs
│ │ ├── edit_text.rs
│ │ ├── checkbox.rs
│ │ ├── switch.rs
│ │ ├── radio.rs
│ │ ├── spinner.rs
│ │ └── layout.rs
│ ├── events.rs # 事件处理
│ ├── error.rs # 错误类型定义
│ └── constants.rs # 常量定义
├── examples/ # 示例程序(重构后更简洁)
│ ├── hello.rs # 重命名 main.rs
│ ├── button_demo.rs
│ ├── checkbox_demo.rs
│ ├── input_demo.rs
│ ├── radio_demo.rs
│ ├── spinner_demo.rs
│ └── switch_demo.rs
└── tests/ # 单元测试
└── integration_tests.rs
```
### src/lib.rs 架构
```rust
//! # Termux GUI Rust Bindings
//!
//! 这个库提供了 Termux:GUI 的 Rust 绑定,允许在 Termux 环境中
//! 使用 Rust 创建原生 Android GUI 应用。
//!
//! ## 快速开始
//!
//! ```rust,no_run
//! use termux_gui::{Activity, Button, TextView};
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // 创建 Activity(对话框模式)
//! let mut activity = Activity::new(true)?;
//!
//! // 创建主布局
//! let layout = activity.create_linear_layout(None)?;
//!
//! // 添加标题
//! let mut title = activity.create_text_view("Hello Termux!", Some(layout.id()))?;
//! title.set_text_size(24)?;
//!
//! // 添加按钮
//! let button = activity.create_button("点击我", Some(layout.id()))?;
//!
//! // 事件循环
//! activity.event_loop(|event| {
//! // 处理事件
//! Ok(())
//! })?;
//!
//! Ok(())
//! }
//! ```
// 公共导出
pub mod connection;
pub mod activity;
pub mod view;
pub mod components;
pub mod events;
pub mod error;
pub mod constants;
// 便捷导出
pub use connection::Connection;
pub use activity::Activity;
pub use view::View;
pub use events::{Event, EventType};
pub use error::{GuiError, Result};
// 导出所有组件
pub use components::{
TextView, Button, EditText, Checkbox, Switch,
RadioButton, RadioGroup, Spinner,
LinearLayout, NestedScrollView,
};
// 常量
pub use constants::*;
```
---
## 🔄 重构步骤
### 阶段 1: 创建基础库(不影响现有代码)
**时间估计:** 2-3 小时
1. 创建 `src/lib.rs` 和基础模块文件
2. 从 `button_demo.rs` 复制核心函数到对应模块
3. 编译确保库可以构建:`cargo build --lib`
4. **不修改任何示例文件**
**可交付成果:**
- ✅ `src/lib.rs` - 库入口
- ✅ `src/connection.rs` - 通信函数
- ✅ 编译通过
### 阶段 2: 重构一个示例验证 API
**时间估计:** 1-2 小时
1. 选择最简单的示例(如 `button_demo.rs`)
2. 创建新文件 `examples/button_demo_v2.rs`
3. 使用新库 API 重写
4. 测试确保功能一致
5. **保留原始文件作为备份**
**可交付成果:**
- ✅ 新示例使用库 API
- ✅ 功能验证通过
- ✅ 代码行数减少 50%+
### 阶段 3: Activity 和 View 封装
**时间估计:** 3-4 小时
1. 实现 `Activity` 结构
2. 实现 `View` 基类
3. 实现 `TextView` 组件
4. 实现 `Button` 组件
5. 更新 `button_demo_v2.rs` 使用高层 API
6. 测试验证
**可交付成果:**
- ✅ Activity 管理器
- ✅ View 基类
- ✅ 2个组件封装
- ✅ 更简洁的示例代码
### 阶段 4: 完善所有组件
**时间估计:** 4-6 小时
1. 实现 `EditText`
2. 实现 `Checkbox`
3. 实现 `Switch`
4. 实现 `RadioButton` 和 `RadioGroup`
5. 实现 `Spinner`(修复级联问题)
6. 实现布局组件
7. 为每个组件创建 `_v2` 示例
**可交付成果:**
- ✅ 所有组件封装完成
- ✅ 所有新示例通过测试
### 阶段 5: 迁移所有示例
**时间估计:** 2-3 小时
1. 确认所有 `_v2` 示例工作正常
2. 删除测试文件(test_spinner_*.rs)
3. 用 `_v2` 版本替换原始示例
4. 更新文档
**可交付成果:**
- ✅ 所有示例使用新库
- ✅ 删除重复代码
- ✅ 更新文档
### 阶段 6: 文档和测试
**时间估计:** 2-3 小时
1. 编写 API 文档
2. 添加示例到文档
3. 创建集成测试
4. 更新 README
**可交付成果:**
- ✅ 完整 API 文档
- ✅ 集成测试
- ✅ 更新的 README
---
## 🛡️ 兼容性保证
### 原则
1. **渐进式重构** - 新旧代码并存
2. **充分测试** - 每个阶段都测试
3. **保留备份** - Git 可随时回滚
4. **先加后减** - 先添加新代码,验证后再删除旧代码
### 风险控制
| API 设计不当 | 高 | 先实现一个示例验证 |
| 破坏现有功能 | 高 | 保留原始文件,创建 _v2 版本 |
| 性能下降 | 中 | 基准测试对比 |
| 编译错误 | 低 | 每个阶段都编译测试 |
| Spinner 问题 | 中 | 专门处理,单独测试 |
---
## 🧪 测试计划
### 测试检查清单
**阶段 1 测试:**
- [ ] `cargo build --lib` 成功
- [ ] `cargo doc --lib` 成功
- [ ] 没有编译警告
**阶段 2 测试:**
- [ ] `button_demo_v2` 可以编译
- [ ] 界面显示正常
- [ ] 按钮点击计数正常
- [ ] 退出事件正常
**阶段 3 测试:**
- [ ] Activity 创建成功
- [ ] TextView 显示正常
- [ ] Button 点击正常
- [ ] 代码量减少 > 50%
**阶段 4 测试:**
- [ ] EditText 输入正常
- [ ] Checkbox 状态切换正常
- [ ] Switch 切换正常
- [ ] RadioButton 单选正常
- [ ] Spinner 显示和选择正常(重点测试)
- [ ] 布局正常
**阶段 5 测试:**
- [ ] 所有示例编译通过
- [ ] 所有示例运行正常
- [ ] 没有功能退化
**最终验证:**
- [ ] 编译无警告:`cargo build --all --release`
- [ ] 所有示例测试通过
- [ ] 文档生成:`cargo doc --open`
- [ ] README 指令可用
---
## 📈 预期收益
### 代码质量
- **代码减少:** 480-600 行重复代码 → 0
- **示例简化:** 每个示例减少 40-50 行样板代码
- **可维护性:** 修改一处影响全部
- **可扩展性:** 添加组件更容易
### 开发效率
- **新示例创建时间:** 从 30 分钟 → 10 分钟
- **新组件添加时间:** 从 2 小时 → 1 小时
- **Bug 修复范围:** 从 12 个文件 → 1 个文件
### 用户体验
- **学习曲线:** 更平缓,API 更清晰
- **示例清晰度:** 专注于功能,不是底层细节
- **文档质量:** 统一的 API 文档
---
## 📋 Cargo.toml 更新
```toml
[package]
name = "termux-gui" # 改为更通用的名称
version = "0.2.0" # 重构版本
edition = "2021"
authors = ["Your Name <your@email.com>"]
description = "Rust bindings for Termux:GUI - Build Android GUI apps in Rust"
license = "MIT"
repository = "https://github.com/andelf/termux-gui-rust-demo"
keywords = ["termux", "android", "gui", "ui"]
categories = ["api-bindings", "gui"]
[lib]
name = "termux_gui"
path = "src/lib.rs"
[[bin]]
name = "termux-gui-demo"
path = "src/main.rs"
[dependencies]
serde_json = "1.0"
rand = "0.8"
libc = "0.2"
[dev-dependencies]
# 用于测试
[profile.release]
opt-level = 3
lto = true
[[example]]
name = "hello"
path = "examples/hello.rs"
[[example]]
name = "button"
path = "examples/button_demo.rs"
# ... 其他示例
```
---
## ✅ 决策点
在开始重构前,需要确认:
### 1. 库名称
- [ ] `termux-gui` (推荐,与 Python 库一致)
- [ ] `termux-gui-rust`
- [ ] `termux_gui` (当前)
### 2. API 风格
- [ ] 面向对象风格(推荐)- `activity.create_button()`
- [ ] 函数式风格 - `create_button(&activity)`
- [ ] 混合风格
### 3. 错误处理
- [ ] 自定义 Error 类型(推荐)
- [ ] 使用 `std::io::Error`
- [ ] 使用 `anyhow`
### 4. 所有权模型
- [ ] `Rc<RefCell<>>` 共享所有权
- [ ] 生命周期引用(推荐,零成本)
- [ ] `Arc<Mutex<>>` 线程安全
### 5. 重构范围
- [ ] 完全重构(推荐)
- [ ] 仅提取公共函数
- [ ] 分阶段,先验证
---
## 🚀 开始重构
### 准备工作
```bash
# 1. 创建新分支
git checkout -b refactor/extract-lib
# 2. 备份当前状态
git tag backup-before-refactor
# 3. 确认所有测试通过
cargo build --examples --release
./test_all.sh # 如果有测试脚本
# 4. 创建基础目录结构
mkdir -p src/components
touch src/lib.rs src/connection.rs src/activity.rs src/view.rs
touch src/components/mod.rs
```
### 第一个 PR
**标题:** `🔧 Phase 1: Extract core communication functions to lib.rs`
**变更:**
- 添加 `src/lib.rs` 和 `src/connection.rs`
- 导出核心通信函数
- 不修改任何示例文件
- 更新 `Cargo.toml` 添加 `[lib]` section
**测试:**
- `cargo build --lib` 通过
- `cargo test --lib` 通过(如果有测试)
- `cargo build --examples` 仍然通过
---
## 📝 总结
### 当前问题
1. ✅ 480-600 行重复代码
2. ✅ 示例文件过于复杂
3. ✅ 维护困难
4. ⚠️ Spinner 级联更新问题
5. ✅ 缺少统一 API
### 解决方案
1. 📦 提取公共代码到 `lib.rs`
2. 🏗️ 创建高层 API(Activity, View, Components)
3. 🔄 渐进式重构,保证兼容性
4. 🐛 在重构过程中修复 Spinner 问题
5. 📚 改进文档和示例
### 预期结果
- ✨ 代码量减少 40%+
- 🎯 API 清晰易用
- 🚀 开发效率提升 3倍
- 📖 示例更易理解
- 🔧 易于维护和扩展
### 时间估计
- **总计:** 14-21 小时
- **最小可用版本(阶段 1-3):** 6-9 小时
- **完整版本(阶段 1-6):** 14-21 小时
### 建议
**立即开始阶段 1**,创建基础库但不破坏现有代码。这样可以:
1. 验证架构设计
2. 不影响现有功能
3. 随时可以回滚
4. 为后续工作打基础
---
**准备好开始重构了吗?** 🚀
我建议从**阶段 1**开始,只提取核心函数,完全不修改示例文件,这样风险最小。