Files
zhini_im/UserInfoActivity地区数据存取方式分析.txt
rw0067680 c01808ac21 first commit
Change-Id: Ib7c2ab10a2562044fcaf9879388a6cbc1db6ac61
2025-12-23 10:00:49 +08:00

404 lines
12 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# UserInfoActivity 地区数据存取方式分析
## 📋 概述
本文档详细说明 `UserInfoActivity` 页面中地区数据(省份、城市、区县)的**存储**和**读取**方式。
---
## 🔄 完整数据流程
```
用户选择地区
AddressPicker三级联动选择器
onAddressPicked回调
数据格式化(省份,城市,区县)
调用updateUserProfile API保存到服务器
服务器存储格式city字段 = "省份,城市,区县"
获取用户信息时,服务器返回三个独立字段
UI显示去重处理省份=城市时,只显示一次)
```
---
## 💾 数据存储方式(保存地区)
### 1. 地区选择器 (`showLocation()`)
```java
// 第249-287行
private void showLocation() {
AddressPicker picker = new AddressPicker(getActivity());
picker.setAddressMode(AddressMode.PROVINCE_CITY_COUNTY); // 三级联动:省-市-县
picker.setOnAddressPickedListener(this); // 设置选择监听器
picker.show();
}
```
**说明**
- 使用 `AddressPicker` 库(`com.github.gzuliyujiang.wheelpicker`
- 模式:`PROVINCE_CITY_COUNTY`(省份-城市-区县三级联动)
- 实现了 `OnAddressPickedListener` 接口,接收选择结果
### 2. 选择结果处理 (`onAddressPicked()`)
```java
// 第289-308行
@Override
public void onAddressPicked(ProvinceEntity province, CityEntity city, CountyEntity county) {
HashMap<String, String> params = new HashMap<String, String>();
// ⚠️ 关键:将三个字段拼接成一个字符串,使用逗号分隔
params.put("city", province.getName() + "," + city.getName() + "," + county.getName());
// 注释掉的代码(说明曾经考虑过分别存储):
// params.put("province", province.getCode()); // 省份代码
// params.put("county", county.getCode()); // 区县代码
// 调用更新接口保存到服务器
updateUserInfo(params, new BooleanCallback() {
@Override
public void onSuccess(boolean result) {
ToastUtils.showToast(getActivity(), "设置成功!");
}
@Override
public void onFail(int code, String msg) {
ToastUtils.showToast(getActivity(), msg);
}
});
}
```
**数据格式**
- **存储格式**`"省份,城市,区县"`(逗号分隔的字符串)
- **示例**`"北京市,北京市,朝阳区"`
- **参数名**`"city"`虽然字段名是city但实际存储的是完整的省市区信息
**注意**
- 省份代码和区县代码已被注释掉,说明目前只存储名称,不存储代码
- 使用逗号分隔的字符串格式可能是为了兼容后端API
### 3. API调用 (`updateUserInfo()`)
```java
// 第912-930行
private void updateUserInfo(HashMap<String, String> params, BooleanCallback callback) {
// 调用更新用户信息API
AppService.Instance().updateUserProfile(params, new SimpleCallback() {
@Override
public void onUiSuccess(Object o) {
if (callback != null) {
callback.onSuccess(true);
// 如果是个人信息页面sourceType == 1刷新用户信息
if (mSourceType == 1) {
getOtherUserInfo(userInfo.uid, "1");
}
}
// 发送用户信息更新事件(通知其他页面刷新)
LiveDataBus.get().with(Constants.USERINFO_UPDATE).postValue("1");
}
@Override
public void onUiFailure(int code, String msg) {
ToastUtils.showToast(getActivity(), msg);
}
});
}
```
**API信息**
- **接口路径**`/api/user/profile``Api.UPDATE_USER_PROFILE`
- **请求方法**POST
- **请求参数**`HashMap<String, String>`,包含 `"city": "省份,城市,区县"`
---
## 📖 数据读取方式(获取地区)
### 1. API调用 (`getOtherUserInfo()`)
```java
// 第834-905行
private void getOtherUserInfo(String user_id, String is_frient) {
// 调用获取用户信息API
AppService.Instance().getUserInfo(user_id, is_frient, new SimpleCallback<GetUserInfoResult>() {
@Override
public void onUiSuccess(GetUserInfoResult infoResult) {
if (infoResult != null) {
GetUserInfoResult data = infoResult.getData();
mUserOwnerInfo = data;
// 如果是个人信息页面sourceType == 1
if (mSourceType == 1) {
// ... 其他字段处理 ...
// 处理地区数据显示
StringBuffer loction = new StringBuffer();
// 1. 添加省份
loction.append(TextUtils.isEmpty(mUserOwnerInfo.getProvince())
? "" : mUserOwnerInfo.getProvince());
// 2. 添加城市(如果省份和城市不同,才添加城市)
if (!TextUtils.isEmpty(mUserOwnerInfo.getProvince())
&& !TextUtils.isEmpty(mUserOwnerInfo.getCity())
&& !mUserOwnerInfo.getProvince().equals(mUserOwnerInfo.getCity())) {
loction.append(TextUtils.isEmpty(mUserOwnerInfo.getCity())
? "" : mUserOwnerInfo.getCity());
}
// 3. 添加区县
loction.append(TextUtils.isEmpty(mUserOwnerInfo.getDistrict())
? "" : mUserOwnerInfo.getDistrict());
// 4. 显示地区信息
aliasLocation.setDesc(TextUtils.isEmpty(loction.toString())
? "" : loction.toString());
}
}
}
});
}
```
**API信息**
- **接口路径**`/api/user/info`(通过 `AppService.getUserInfo()` 调用)
- **请求参数**
- `user_id`用户ID
- `is_frient`:是否好友("1"=是好友,"0"=非好友)
### 2. 返回数据结构 (`GetUserInfoResult`)
```java
// uikit/src/main/java/cn/wildfire/chat/kit/net/model/GetUserInfoResult.java
public class GetUserInfoResult {
private String province; // 省份
private String city; // 城市
private String district; // 区县
// ... 其他字段 ...
}
```
**说明**
- 服务器返回**三个独立字段**`province`, `city`, `district`
- 这与存储时的格式不同(存储时是逗号分隔的字符串)
### 3. UI显示逻辑去重处理
```java
// 第852-859行
StringBuffer loction = new StringBuffer();
// 1. 添加省份(如果存在)
loction.append(TextUtils.isEmpty(mUserOwnerInfo.getProvince())
? "" : mUserOwnerInfo.getProvince());
// 2. 添加城市(智能去重:如果省份和城市相同,不重复显示)
// 例如:"北京市" == "北京市",则只显示一次
if (!TextUtils.isEmpty(mUserOwnerInfo.getProvince())
&& !TextUtils.isEmpty(mUserOwnerInfo.getCity())
&& !mUserOwnerInfo.getProvince().equals(mUserOwnerInfo.getCity())) {
loction.append(TextUtils.isEmpty(mUserOwnerInfo.getCity())
? "" : mUserOwnerInfo.getCity());
}
// 3. 添加区县(如果存在)
loction.append(TextUtils.isEmpty(mUserOwnerInfo.getDistrict())
? "" : mUserOwnerInfo.getDistrict());
// 4. 显示地区信息
aliasLocation.setDesc(loction.toString());
```
**显示逻辑**
- **省份**:如果存在,直接添加
- **城市**:如果存在且与省份不同,才添加(避免"北京市北京市"这样的重复显示)
- **区县**:如果存在,直接添加
- **示例**
- 存储:`"北京市,北京市,朝阳区"`
- 服务器返回:`province="北京市"`, `city="北京市"`, `district="朝阳区"`
- UI显示`"北京市朝阳区"`(城市被去重)
---
## 📊 数据格式对比
### 存储格式(发送到服务器)
```java
HashMap<String, String> params = new HashMap<>();
params.put("city", "北京市,北京市,朝阳区"); // 逗号分隔的字符串
```
### 读取格式(服务器返回)
```java
GetUserInfoResult {
province: "北京市", // 独立字段
city: "北京市", // 独立字段
district: "朝阳区" // 独立字段
}
```
### 显示格式UI展示
```java
"北京市朝阳区" // 去重后的显示(省份=城市时,城市被省略)
```
---
## 🔄 数据同步机制
### 1. 保存后自动刷新
```java
// 在updateUserInfo成功后
if (mSourceType == 1) {
// 如果是个人信息页面,自动刷新用户信息
getOtherUserInfo(userInfo.uid, "1");
}
```
### 2. LiveDataBus事件通知
```java
// 保存成功后,发送用户信息更新事件
LiveDataBus.get().with(Constants.USERINFO_UPDATE).postValue("1");
```
**说明**
- 其他页面(如 `MeFragment`)可以监听此事件,自动刷新用户信息
- 实现跨页面的数据同步
### 3. 监听事件刷新
```java
// UserInfoFragment中监听用户信息更新事件
LiveDataBus.get().with(Constants.USERINFO_UPDATE).observe(getActivity(), new Observer<Object>() {
@Override
public void onChanged(Object o) {
init(); // 重新初始化,刷新用户信息
}
});
```
---
## 🛠️ 技术实现细节
### 1. 地区选择器库
- **库名**`com.github.gzuliyujiang.wheelpicker`
- **功能**:三级联动地址选择器(省份-城市-区县)
- **模式**`AddressMode.PROVINCE_CITY_COUNTY`
### 2. 数据转换
**存储时**(选择器 → 服务器):
```
ProvinceEntity → province.getName()
CityEntity → city.getName()
CountyEntity → county.getName()
拼接格式:"省份,城市,区县"
```
**读取时**(服务器 → UI
```
服务器返回province, city, district三个独立字段
UI显示去重处理拼接显示
```
### 3. API端点
**保存地区**
- 接口:`POST /api/user/profile`
- 参数:`{"city": "省份,城市,区县"}`
**获取地区**
- 接口:`POST /api/user/info`
- 参数:`{"user_id": "用户ID", "is_friend": "1"}`
---
## ⚠️ 注意事项
### 1. 数据格式不一致
- **存储时**:使用 `"city"` 字段,值为逗号分隔的字符串 `"省份,城市,区县"`
- **读取时**:服务器返回三个独立字段 `province`, `city`, `district`
- **说明**这可能是后端API的设计存储时将三个字段合并读取时返回三个独立字段
### 2. 代码字段未使用
```java
// 注释掉的代码
// params.put("province", province.getCode()); // 省份代码
// params.put("county", county.getCode()); // 区县代码
```
- 目前只存储名称,不存储代码
- 如果需要代码需要取消注释并修改API参数
### 3. UI显示去重逻辑
- 如果省份和城市相同(如"北京市"UI显示时会自动去重
- 这样可以避免显示"北京市北京市朝阳区"这样的冗余信息
### 4. 数据为空处理
```java
TextUtils.isEmpty(mUserOwnerInfo.getProvince()) ? "" : mUserOwnerInfo.getProvince()
```
- 所有字段都做了空值检查
- 如果字段为空,返回空字符串
---
## 📝 关键代码位置
### 存储相关
- **地区选择器显示**`UserInfoFragment.java` 第249-287行 (`showLocation()`)
- **选择结果处理**第289-308行 (`onAddressPicked()`)
- **更新用户信息**第912-930行 (`updateUserInfo()`)
### 读取相关
- **获取用户信息**第834-905行 (`getOtherUserInfo()`)
- **地区数据显示**第852-859行地区拼接逻辑
- **数据结构定义**`GetUserInfoResult.java` 第10-13行
---
## 🔍 相关文件
- **Fragment**`uikit/src/main/java/cn/wildfire/chat/kit/user/UserInfoFragment.java`
- **API服务**`uikit/src/main/java/cn/wildfire/chat/kit/net/AppService.java`
- **API定义**`uikit/src/main/java/cn/wildfire/chat/kit/net/Api.java`
- **数据模型**`uikit/src/main/java/cn/wildfire/chat/kit/net/model/GetUserInfoResult.java`
---
## 💡 总结
### 存储流程
1. 用户通过三级联动选择器选择地区
2. 将省份、城市、区县拼接成 `"省份,城市,区县"` 格式
3. 通过 `updateUserProfile` API保存到服务器的 `city` 字段
### 读取流程
1. 通过 `getUserInfo` API获取用户详细信息
2. 服务器返回三个独立字段:`province`, `city`, `district`
3. UI显示时进行去重处理避免重复显示相同的省份和城市
### 关键特点
- ✅ 存储格式:逗号分隔的字符串
- ✅ 读取格式:三个独立字段
- ✅ UI显示智能去重避免冗余信息
- ✅ 数据同步使用LiveDataBus实现跨页面同步