404 lines
12 KiB
Plaintext
404 lines
12 KiB
Plaintext
|
|
# 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实现跨页面同步
|
|||
|
|
|