547 lines
16 KiB
Plaintext
547 lines
16 KiB
Plaintext
# MeFragment 我的页面逻辑分析
|
||
|
||
## 📋 页面概述
|
||
|
||
**文件位置**: `app/src/main/java/com/xunpaisoft/social/im/main/MeFragment.java`
|
||
**布局文件**: `app/src/main/res/layout/main_fragment_me.xml`
|
||
**页面类型**: Fragment
|
||
**主要功能**: "我的"页面,显示用户个人信息、统计数据,提供各种功能入口
|
||
|
||
---
|
||
|
||
## 🎯 核心功能模块
|
||
|
||
### 1. 页面初始化
|
||
|
||
#### 1.1 生命周期方法
|
||
```java
|
||
@Override
|
||
public View onCreateView(...) {
|
||
View view = inflater.inflate(R.layout.main_fragment_me, container, false);
|
||
bindViews(view); // 绑定视图
|
||
bindEvents(view); // 绑定事件
|
||
init(); // 初始化数据
|
||
return view;
|
||
}
|
||
```
|
||
|
||
#### 1.2 数据初始化 (`init()`)
|
||
```java
|
||
// 1. 获取UserViewModel
|
||
userViewModel = ViewModelProviders.of(this).get(UserViewModel.class);
|
||
|
||
// 2. 异步获取用户信息
|
||
userViewModel.getUserInfoAsync(userViewModel.getUserId(), true)
|
||
.observe(getViewLifecycleOwner(), info -> {
|
||
userInfo = info;
|
||
if (userInfo != null) {
|
||
updateUserInfo(userInfo); // 更新UI
|
||
}
|
||
});
|
||
|
||
// 3. 观察用户信息变化(实时更新)
|
||
userViewModel.userInfoLiveData().observeForever(userInfoLiveDataObserver);
|
||
|
||
// 4. 根据服务器类型显示/隐藏文件记录选项
|
||
if (ChatManager.Instance().isCommercialServer()) {
|
||
fileRecordOptionItem.setVisibility(View.VISIBLE);
|
||
} else {
|
||
fileRecordOptionItem.setVisibility(View.GONE);
|
||
}
|
||
|
||
// 5. 监听用户信息更新事件
|
||
LiveDataBus.get().with(Constants.USERINFO_UPDATE).observe(...);
|
||
```
|
||
|
||
---
|
||
|
||
### 2. 用户信息显示 (`updateUserInfo()`)
|
||
|
||
#### 2.1 基本信息显示
|
||
```java
|
||
// 1. 头像显示(使用Glide加载,圆角处理)
|
||
RequestOptions options = new RequestOptions()
|
||
.placeholder(R.mipmap.icon_default_man) // 占位图
|
||
.transforms(new CenterCrop(), new RoundedCorners(30)); // 圆角30px
|
||
Glide.with(this)
|
||
.load(userInfo.portrait)
|
||
.apply(options)
|
||
.into(portraitImageView);
|
||
|
||
// 2. 昵称显示
|
||
nameTextView.setText(userInfo.displayName);
|
||
|
||
// 3. 账号显示
|
||
accountTextView.setText("账号: " + userInfo.name);
|
||
```
|
||
|
||
#### 2.2 统计数据获取
|
||
```java
|
||
// 调用API获取关注、粉丝、点赞数量
|
||
Map<String, String> params = new HashMap<>();
|
||
params.put("user_id", Constants.getUserId());
|
||
AppService.Instance().getFans(params, new SimpleCallback<UserInfoNumberResult>() {
|
||
@Override
|
||
public void onUiSuccess(UserInfoNumberResult result) {
|
||
UserInfoNumberResult data = result.getData();
|
||
tvGunZhu.setText(data.getFollow_c()); // 关注数
|
||
tvFensi.setText(data.getFans_c()); // 粉丝数
|
||
tvDianZan.setText(data.getLikes_c()); // 点赞数
|
||
}
|
||
});
|
||
```
|
||
|
||
#### 2.3 性别显示
|
||
```java
|
||
// 获取其他用户信息(用于获取性别)
|
||
getOtherUserInfo(userInfo.uid, "1");
|
||
|
||
// 在getOtherUserInfo回调中:
|
||
if ("1".equals(data.getGender())) {
|
||
// 女性
|
||
imgSex.setImageDrawable(getActivity().getDrawable(R.mipmap.icon_sex_woman));
|
||
} else {
|
||
// 男性
|
||
imgSex.setImageDrawable(getActivity().getDrawable(R.mipmap.icon_sex_man));
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3. 页面刷新逻辑
|
||
|
||
#### 3.1 Fragment可见性控制
|
||
```java
|
||
@Override
|
||
public void setMenuVisibility(boolean isvisible) {
|
||
super.setMenuVisibility(isvisible);
|
||
this.isVisibleToUser = isvisible; // 记录Fragment是否对用户可见
|
||
}
|
||
```
|
||
|
||
#### 3.2 onResume刷新
|
||
```java
|
||
@Override
|
||
public void onResume() {
|
||
super.onResume();
|
||
if (this.isVisibleToUser && userViewModel != null) {
|
||
// Fragment可见时,刷新用户信息
|
||
userViewModel.getUserInfoAsync(userViewModel.getUserId(), true)
|
||
.observe(getViewLifecycleOwner(), info -> {
|
||
userInfo = info;
|
||
if (userInfo != null) {
|
||
updateUserInfo(userInfo);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 3.3 LiveDataBus监听
|
||
```java
|
||
// 监听用户信息更新事件
|
||
LiveDataBus.get().with(Constants.USERINFO_UPDATE).observe(getActivity(), new Observer<Object>() {
|
||
@Override
|
||
public void onChanged(Object o) {
|
||
// 用户信息更新时,重新获取其他用户信息(更新性别等)
|
||
getOtherUserInfo(userInfo.uid, "1");
|
||
}
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
### 4. 功能入口(事件绑定)
|
||
|
||
#### 4.1 个人信息入口
|
||
```java
|
||
view.findViewById(R.id.meLinearLayout).setOnClickListener(v -> showMyInfo());
|
||
|
||
void showMyInfo() {
|
||
Intent intent = new Intent(getActivity(), UserInfoActivity.class);
|
||
userInfo.setSourceType(1); // 设置来源类型为个人信息页面
|
||
intent.putExtra("userInfo", userInfo);
|
||
startActivity(intent);
|
||
}
|
||
```
|
||
- **功能**:跳转到 `UserInfoActivity` 查看自己的详细信息
|
||
|
||
#### 4.2 关注/粉丝列表
|
||
```java
|
||
// 关注列表
|
||
view.findViewById(R.id.ln_follow).setOnClickListener(new View.OnClickListener() {
|
||
@Override
|
||
public void onClick(View view) {
|
||
Intent intent = new Intent(getActivity(), FollowFansActivity.class);
|
||
intent.putExtra("mType", "2"); // 2=关注列表
|
||
intent.putExtra("user_id", userInfo.getUserId());
|
||
startActivity(intent);
|
||
}
|
||
});
|
||
|
||
// 粉丝列表
|
||
view.findViewById(R.id.ln_fans).setOnClickListener(new View.OnClickListener() {
|
||
@Override
|
||
public void onClick(View view) {
|
||
Intent intent = new Intent(getActivity(), FollowFansActivity.class);
|
||
intent.putExtra("mType", "1"); // 1=粉丝列表
|
||
intent.putExtra("user_id", userInfo.getUserId());
|
||
startActivity(intent);
|
||
}
|
||
});
|
||
```
|
||
- **功能**:跳转到 `FollowFansActivity` 查看关注/粉丝列表
|
||
- **参数说明**:
|
||
- `mType = "1"`:粉丝列表
|
||
- `mType = "2"`:关注列表
|
||
|
||
#### 4.3 相册入口
|
||
```java
|
||
view.findViewById(R.id.accountPhoto).setOnClickListener(view1 ->
|
||
startActivity(new Intent(getActivity(), UserAlbumManageActivity.class))
|
||
);
|
||
```
|
||
- **功能**:跳转到 `UserAlbumManageActivity` 管理相册
|
||
|
||
#### 4.4 其他功能入口
|
||
|
||
| 功能 | ID | 跳转页面 | 说明 |
|
||
|------|-----|---------|------|
|
||
| 收藏 | `favOptionItemView` | `FavoriteListActivity` | 收藏列表 |
|
||
| 账号与安全 | `accountOptionItemView` | `AccountActivity` | 账号安全管理(已隐藏) |
|
||
| 文件记录 | `fileRecordOptionItemView` | `FileRecordListActivity` | 文件记录(仅商业服务器) |
|
||
| 主题 | `themeOptionItemView` | 主题选择对话框 | 切换深色/浅色主题 |
|
||
| 设置 | `settingOptionItemView` | `SettingActivity` | 设置页面 |
|
||
| 消息通知 | `notificationOptionItemView` | `MessageNotifySettingActivity` | 消息通知设置 |
|
||
| 联系我们 | `accountAbout` | `ConversationActivity` | 客服对话(单聊ID:"47") |
|
||
|
||
#### 4.5 VIP功能
|
||
```java
|
||
view.findViewById(R.id.rl_vip).setOnClickListener(new View.OnClickListener() {
|
||
@Override
|
||
public void onClick(View view) {
|
||
// 跳转到WebView页面(邀请好友页面)
|
||
WfcWebViewActivity.loadUrl(getActivity(), "", "https://xingyao.xunpaisoft.com");
|
||
}
|
||
});
|
||
```
|
||
- **功能**:点击VIP区域跳转到邀请好友页面(WebView)
|
||
|
||
---
|
||
|
||
### 5. 主题切换功能 (`theme()`)
|
||
|
||
```java
|
||
void theme() {
|
||
SharedPreferences sp = getActivity().getSharedPreferences("wfc_kit_config", Context.MODE_PRIVATE);
|
||
boolean darkTheme = sp.getBoolean("darkTheme", true); // 获取当前主题
|
||
|
||
// 显示主题选择对话框
|
||
new MaterialDialog.Builder(getContext())
|
||
.items(R.array.themes) // 主题列表:深色/浅色
|
||
.itemsCallback(new MaterialDialog.ListCallback() {
|
||
@Override
|
||
public void onSelection(MaterialDialog dialog, View v, int position, CharSequence text) {
|
||
if (position == 0 && darkTheme) {
|
||
// 选择浅色主题,当前是深色
|
||
sp.edit().putBoolean("darkTheme", false).apply();
|
||
restart(); // 重启应用使主题生效
|
||
}
|
||
if (position == 1 && !darkTheme) {
|
||
// 选择深色主题,当前是浅色
|
||
sp.edit().putBoolean("darkTheme", true).apply();
|
||
restart();
|
||
}
|
||
}
|
||
}).show();
|
||
}
|
||
|
||
private void restart() {
|
||
// 重启应用
|
||
Intent i = getActivity().getApplicationContext().getPackageManager()
|
||
.getLaunchIntentForPackage(getActivity().getApplicationContext().getPackageName());
|
||
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||
startActivity(i);
|
||
}
|
||
```
|
||
|
||
**说明**:
|
||
- 主题保存在 `SharedPreferences` 中,key为 `"darkTheme"`
|
||
- 切换主题后需要重启应用才能生效
|
||
- 使用 `FLAG_ACTIVITY_CLEAR_TOP` 清除Activity栈,确保应用完全重启
|
||
|
||
---
|
||
|
||
### 6. 其他用户信息获取 (`getOtherUserInfo()`)
|
||
|
||
```java
|
||
private void getOtherUserInfo(String user_id, String is_frient) {
|
||
AppService.Instance().getUserInfo(user_id, is_frient, new SimpleCallback<GetUserInfoResult>() {
|
||
@Override
|
||
public void onUiSuccess(GetUserInfoResult infoResult) {
|
||
if (getActivity() == null || isDetached() || isRemoving()) {
|
||
return; // Fragment已销毁,不更新UI
|
||
}
|
||
|
||
if (infoResult != null) {
|
||
GetUserInfoResult data = infoResult.getData();
|
||
// 根据性别显示性别图标
|
||
if (!TextUtils.isEmpty(data.getGender())) {
|
||
if ("1".equals(data.getGender())) {
|
||
// 女性
|
||
imgSex.setImageDrawable(getActivity().getDrawable(R.mipmap.icon_sex_woman));
|
||
} else {
|
||
// 男性
|
||
imgSex.setImageDrawable(getActivity().getDrawable(R.mipmap.icon_sex_man));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
});
|
||
}
|
||
```
|
||
|
||
**功能**:
|
||
- 获取用户的详细信息(性别等)
|
||
- 主要用于显示性别图标
|
||
- 参数说明:
|
||
- `user_id`:用户ID
|
||
- `is_frient`:是否好友("1"=是好友,"0"=非好友)
|
||
|
||
---
|
||
|
||
### 7. 观察者模式 - 用户信息实时更新
|
||
|
||
```java
|
||
private Observer<List<UserInfo>> userInfoLiveDataObserver = new Observer<List<UserInfo>>() {
|
||
@Override
|
||
public void onChanged(@Nullable List<UserInfo> userInfos) {
|
||
if (userInfos == null) {
|
||
return;
|
||
}
|
||
// 遍历用户信息列表,找到自己的信息
|
||
for (UserInfo info : userInfos) {
|
||
if (info.uid.equals(userViewModel.getUserId())) {
|
||
userInfo = info;
|
||
updateUserInfo(userInfo); // 更新UI
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
};
|
||
```
|
||
|
||
**说明**:
|
||
- 观察 `userViewModel.userInfoLiveData()`,当用户信息发生变化时自动更新UI
|
||
- 在 `onDestroyView()` 中需要移除观察者,避免内存泄漏
|
||
|
||
---
|
||
|
||
## 🔄 完整业务流程
|
||
|
||
### 场景1:页面初始化
|
||
```
|
||
Fragment创建(onCreateView)
|
||
↓
|
||
绑定视图(bindViews)
|
||
↓
|
||
绑定事件(bindEvents)
|
||
↓
|
||
初始化数据(init)
|
||
↓
|
||
获取用户信息(UserViewModel.getUserInfoAsync)
|
||
↓
|
||
更新UI(updateUserInfo)
|
||
↓
|
||
获取统计数据(getFans API)
|
||
↓
|
||
获取其他用户信息(getOtherUserInfo API)
|
||
↓
|
||
显示用户信息、统计数据、性别图标
|
||
```
|
||
|
||
### 场景2:页面刷新(Fragment可见时)
|
||
```
|
||
Fragment可见(setMenuVisibility(true))
|
||
↓
|
||
onResume触发
|
||
↓
|
||
检查Fragment是否可见(isVisibleToUser)
|
||
↓
|
||
重新获取用户信息
|
||
↓
|
||
更新UI
|
||
```
|
||
|
||
### 场景3:用户信息更新(从其他页面返回)
|
||
```
|
||
其他页面修改用户信息
|
||
↓
|
||
发送LiveDataBus事件(Constants.USERINFO_UPDATE)
|
||
↓
|
||
MeFragment监听到事件
|
||
↓
|
||
重新获取其他用户信息(getOtherUserInfo)
|
||
↓
|
||
更新性别图标等UI
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 数据结构
|
||
|
||
### API返回数据结构
|
||
|
||
#### 1. getFans API (`UserInfoNumberResult`)
|
||
```java
|
||
UserInfoNumberResult {
|
||
String follow_c; // 关注数
|
||
String fans_c; // 粉丝数
|
||
String likes_c; // 点赞数
|
||
}
|
||
```
|
||
|
||
#### 2. getUserInfo API (`GetUserInfoResult`)
|
||
```java
|
||
GetUserInfoResult {
|
||
String id;
|
||
String nickname;
|
||
String avatar;
|
||
String gender; // 性别("1"=女性,"0"或其他=男性)
|
||
String province;
|
||
String city;
|
||
String district;
|
||
String[] photos; // 相册照片数组
|
||
// ... 其他字段
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🛠️ 技术要点
|
||
|
||
### 1. ViewModel + LiveData
|
||
- 使用 `UserViewModel` 管理用户信息
|
||
- 使用 `LiveData` 观察用户信息变化
|
||
- 自动更新UI,无需手动刷新
|
||
|
||
### 2. Fragment生命周期管理
|
||
- 使用 `getViewLifecycleOwner()` 确保观察者生命周期与Fragment绑定
|
||
- 在 `onDestroyView()` 中移除观察者,避免内存泄漏
|
||
- 检查Fragment状态(`isDetached()`, `isRemoving()`)避免更新已销毁的Fragment
|
||
|
||
### 3. Glide图片加载
|
||
- 使用Glide加载用户头像
|
||
- 自定义RequestOptions:占位图、圆角处理(30px)
|
||
|
||
### 4. LiveDataBus事件总线
|
||
- 使用 `LiveDataBus` 监听用户信息更新事件
|
||
- 实现跨页面数据同步
|
||
|
||
### 5. 主题切换
|
||
- 使用 `SharedPreferences` 保存主题设置
|
||
- 切换主题后重启应用使主题生效
|
||
|
||
---
|
||
|
||
## ⚠️ 注意事项
|
||
|
||
1. **Fragment生命周期**:
|
||
- 在异步回调中检查Fragment状态,避免更新已销毁的Fragment
|
||
- 使用 `getViewLifecycleOwner()` 确保观察者自动移除
|
||
|
||
2. **观察者移除**:
|
||
- `observeForever` 需要在 `onDestroyView()` 中手动移除
|
||
- `observe` 会在Fragment销毁时自动移除
|
||
|
||
3. **统计数据更新**:
|
||
- 关注、粉丝、点赞数通过API获取,不在用户信息中
|
||
- 需要单独调用 `getFans` API获取
|
||
|
||
4. **性别显示**:
|
||
- 性别信息不在 `UserInfo` 中,需要通过 `getOtherUserInfo` API获取
|
||
- 性别值为 `"1"` 表示女性,其他值表示男性
|
||
|
||
5. **功能入口可见性**:
|
||
- `fileRecordOptionItem` 仅在商业服务器时显示
|
||
- `accountOptionItemView` 当前已隐藏(`visibility="gone"`)
|
||
- `favOptionItemView`、`themeOptionItemView` 等部分功能已隐藏
|
||
|
||
6. **客服对话**:
|
||
- "联系我们"功能跳转到与用户ID为 `"47"` 的单聊会话
|
||
- 这是一个系统用户(客服)
|
||
|
||
---
|
||
|
||
## 🔍 相关文件
|
||
|
||
- **布局文件**:`app/src/main/res/layout/main_fragment_me.xml`
|
||
- **ViewModel**:`UserViewModel` - 用户信息管理
|
||
- **相关页面**:
|
||
- `UserInfoActivity` - 个人信息详情
|
||
- `FollowFansActivity` - 关注/粉丝列表
|
||
- `UserAlbumManageActivity` - 相册管理
|
||
- `AccountActivity` - 账号安全
|
||
- `SettingActivity` - 设置
|
||
- `FavoriteListActivity` - 收藏列表
|
||
- `FileRecordListActivity` - 文件记录
|
||
- `MessageNotifySettingActivity` - 消息通知设置
|
||
|
||
---
|
||
|
||
## 📝 代码关键位置
|
||
|
||
### 初始化(第252-275行)
|
||
```java
|
||
private void init() {
|
||
// 获取UserViewModel
|
||
// 获取用户信息
|
||
// 观察用户信息变化
|
||
// 监听用户信息更新事件
|
||
}
|
||
```
|
||
|
||
### 更新用户信息(第204-250行)
|
||
```java
|
||
private void updateUserInfo(UserInfo userInfo) {
|
||
// 显示头像、昵称、账号
|
||
// 获取统计数据
|
||
// 获取其他用户信息(性别)
|
||
}
|
||
```
|
||
|
||
### 事件绑定(第140-186行)
|
||
```java
|
||
private void bindEvents(View view) {
|
||
// 绑定各种功能入口的点击事件
|
||
}
|
||
```
|
||
|
||
### 用户信息观察者(第92-107行)
|
||
```java
|
||
private Observer<List<UserInfo>> userInfoLiveDataObserver = new Observer<List<UserInfo>>() {
|
||
// 观察用户信息列表,找到自己的信息并更新UI
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## 🐛 潜在问题
|
||
|
||
1. **性别图标显示**:
|
||
- 性别信息通过单独的API获取,可能存在延迟
|
||
- 如果API失败,性别图标不会显示
|
||
|
||
2. **统计数据更新**:
|
||
- 统计数据需要单独API调用,可能与用户信息不同步
|
||
- 如果API失败,统计数据显示为默认值(可能为空)
|
||
|
||
3. **主题切换**:
|
||
- 切换主题需要重启应用,用户体验不够流畅
|
||
- 可以考虑使用动态主题,无需重启
|
||
|
||
4. **功能入口隐藏**:
|
||
- 部分功能入口已隐藏(`accountOptionItemView`、`favOptionItemView`等)
|
||
- 可能是功能未完成或暂时隐藏
|
||
|