Files
zhini_im/UserInfoActivity地区数据存取方式分析.txt

404 lines
12 KiB
Plaintext
Raw Normal View History

# 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实现跨页面同步