372 lines
12 KiB
Plaintext
372 lines
12 KiB
Plaintext
|
|
# PublishActivity 发布帖子页面逻辑分析
|
|||
|
|
|
|||
|
|
## 📋 页面概述
|
|||
|
|
|
|||
|
|
**文件位置**: `uikit/src/main/java/cn/wildfire/chat/kit/user/PublishActivity.java`
|
|||
|
|
**布局文件**: `uikit/src/main/res/layout/activity_publish.xml`
|
|||
|
|
**页面类型**: Activity(继承自 WfcBaseActivity)
|
|||
|
|
**主要功能**: 发布朋友圈动态,支持文字和图片内容发布
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 核心功能模块
|
|||
|
|
|
|||
|
|
### 1. 页面初始化 (`afterViews()`)
|
|||
|
|
|
|||
|
|
#### 1.1 UI组件初始化
|
|||
|
|
```java
|
|||
|
|
mRecyPicItem = findViewById(R.id.rcy_pic_item); // 图片选择RecyclerView
|
|||
|
|
mEdtContent = findViewById(R.id.edt_content); // 内容输入框
|
|||
|
|
oiv_show = findViewById(R.id.oiv_show); // 可见范围设置(默认隐藏)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 1.2 状态栏设置
|
|||
|
|
```java
|
|||
|
|
setTitleBackgroundResource(R.color.white, false); // 白色状态栏,深色图标
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 1.3 初始化操作
|
|||
|
|
- ✅ 获取七牛云Token:`getQnToken()` - 用于图片上传
|
|||
|
|
- ✅ 初始化图片选择器:`initWidget()` - 设置RecyclerView和适配器
|
|||
|
|
- ✅ 设置默认可见范围:`oiv_show.setDesc("公开")` - 默认值为"公开"(`mShowType = "1"`)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2. 图片选择功能 (`initWidget()`)
|
|||
|
|
|
|||
|
|
#### 2.1 RecyclerView配置
|
|||
|
|
```java
|
|||
|
|
// 网格布局:3列,垂直方向
|
|||
|
|
FunctionBackGridLayoutManager manager = new FunctionBackGridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false);
|
|||
|
|
mRecyPicItem.setLayoutManager(manager);
|
|||
|
|
|
|||
|
|
// 适配器配置
|
|||
|
|
adapter = new FunctionBackImageAdapter(this, onAddPicClickListener);
|
|||
|
|
adapter.setList(selectList); // 设置图片列表
|
|||
|
|
adapter.setSelectMax(MAX_SELECT_NUM); // 最大选择数量:9张
|
|||
|
|
mRecyPicItem.setAdapter(adapter);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 2.2 关键常量
|
|||
|
|
- `MAX_SELECT_NUM = 9`:最多选择9张图片
|
|||
|
|
- `MIN_SELECT_NUM = 1`:最少选择1张图片
|
|||
|
|
- `SPAN_COUNT_NUM = 3`:每行显示3张图片
|
|||
|
|
|
|||
|
|
#### 2.3 图片选择回调 (`onAddPicClickListener`)
|
|||
|
|
当用户点击"添加图片"按钮时:
|
|||
|
|
1. 计算可选择的图片数量:`number = MAX_SELECT_NUM - selectList.size()`
|
|||
|
|
2. 显示选择对话框:`CameraSelectDialog` - 提供"拍照"和"从相册选择"两个选项
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3. 图片上传流程
|
|||
|
|
|
|||
|
|
#### 3.1 上传步骤
|
|||
|
|
|
|||
|
|
**步骤1:选择图片**
|
|||
|
|
- **拍照**:`PictureSelector.create().openCamera()` - 调用系统相机
|
|||
|
|
- **相册选择**:`PictureSelector.create().openGallery()` - 打开相册选择
|
|||
|
|
|
|||
|
|
**步骤2:图片压缩**
|
|||
|
|
```java
|
|||
|
|
Luban.with(mContext)
|
|||
|
|
.load(realPath) // 加载原始图片路径
|
|||
|
|
.setCompressListener(...) // 设置压缩监听器
|
|||
|
|
.launch(); // 启动压缩
|
|||
|
|
```
|
|||
|
|
- 使用 `Luban` 库进行图片压缩,减小上传文件大小
|
|||
|
|
|
|||
|
|
**步骤3:上传到七牛云**
|
|||
|
|
```java
|
|||
|
|
QiniuUploadFile.uploadFile(
|
|||
|
|
file.getName(), // 文件名
|
|||
|
|
mQnToken, // 七牛云Token(从服务器获取)
|
|||
|
|
file, // 压缩后的文件
|
|||
|
|
new UploadCallBack() { // 上传回调
|
|||
|
|
@Override
|
|||
|
|
public void result(boolean isSuccess, String address) {
|
|||
|
|
// 上传成功,address为图片URL
|
|||
|
|
// 创建PhotoInfoEntity并添加到列表
|
|||
|
|
PhotoInfoEntity photoInfoEntity = new PhotoInfoEntity()
|
|||
|
|
.setUrl(address) // 完整URL
|
|||
|
|
.setMinUrl(address); // 缩略图URL(当前使用相同URL)
|
|||
|
|
arrayListPhoto.add(photoInfoEntity);
|
|||
|
|
adapter.setList(arrayListPhoto);
|
|||
|
|
adapter.notifyDataSetChanged();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3.2 数据结构
|
|||
|
|
```java
|
|||
|
|
PhotoInfoEntity {
|
|||
|
|
String url; // 图片完整URL
|
|||
|
|
String minUrl; // 图片缩略图URL
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 4. 发布功能 (`setToolbarSave` 点击事件)
|
|||
|
|
|
|||
|
|
#### 4.1 数据收集
|
|||
|
|
```java
|
|||
|
|
String content = mEdtContent.getText().toString().trim(); // 获取文字内容
|
|||
|
|
HashMap<String, String> headMaps = new HashMap<>();
|
|||
|
|
|
|||
|
|
// 1. 添加文字内容
|
|||
|
|
headMaps.put("content", content);
|
|||
|
|
|
|||
|
|
// 2. 添加可见范围(1:公开, 2:仅好友可见)
|
|||
|
|
headMaps.put("ispravite", mShowType);
|
|||
|
|
|
|||
|
|
// 3. 添加图片URL列表(逗号分隔)
|
|||
|
|
if(adapter != null) {
|
|||
|
|
List<PhotoInfoEntity> list = adapter.getList();
|
|||
|
|
StringBuffer listBuffer = new StringBuffer();
|
|||
|
|
for (int i = 0; i < list.size(); i++) {
|
|||
|
|
PhotoInfoEntity photoInfoEntity = list.get(i);
|
|||
|
|
if ((list.size() - 1) == i) {
|
|||
|
|
listBuffer.append(photoInfoEntity.getUrl()); // 最后一张不加逗号
|
|||
|
|
} else {
|
|||
|
|
listBuffer.append(photoInfoEntity.getUrl()).append(","); // 其他加逗号
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
headMaps.put("images", listBuffer.toString()); // 图片URL列表,格式:url1,url2,url3
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 4. 添加定位信息(从本地SharedPreferences读取,如果存在)
|
|||
|
|
String latitude = SharedPreferencesUtils.getString("location_latitude", "");
|
|||
|
|
String longitude = SharedPreferencesUtils.getString("location_longitude", "");
|
|||
|
|
String poi = SharedPreferencesUtils.getString("location_poi", "");
|
|||
|
|
|
|||
|
|
// 5. 添加省市区信息(优先使用定位获取的,如果为空则使用用户手动设置的)
|
|||
|
|
String province = SharedPreferencesUtils.getString("location_province", "");
|
|||
|
|
String city = SharedPreferencesUtils.getString("location_city", "");
|
|||
|
|
String district = SharedPreferencesUtils.getString("location_district", "");
|
|||
|
|
|
|||
|
|
// 如果定位的省市区为空,则使用用户手动设置的省市区
|
|||
|
|
if (TextUtils.isEmpty(province)) {
|
|||
|
|
province = SharedPreferencesUtils.getString("user_province", "");
|
|||
|
|
}
|
|||
|
|
if (TextUtils.isEmpty(city)) {
|
|||
|
|
city = SharedPreferencesUtils.getString("user_city", "");
|
|||
|
|
}
|
|||
|
|
if (TextUtils.isEmpty(district)) {
|
|||
|
|
district = SharedPreferencesUtils.getString("user_district", "");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 添加定位信息(如果存在)
|
|||
|
|
if (!TextUtils.isEmpty(latitude)) {
|
|||
|
|
headMaps.put("lat", latitude);
|
|||
|
|
}
|
|||
|
|
if (!TextUtils.isEmpty(longitude)) {
|
|||
|
|
headMaps.put("lng", longitude);
|
|||
|
|
}
|
|||
|
|
if (!TextUtils.isEmpty(poi)) {
|
|||
|
|
headMaps.put("poi", poi);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 添加省市区信息(如果存在)
|
|||
|
|
if (!TextUtils.isEmpty(province)) {
|
|||
|
|
headMaps.put("province", province);
|
|||
|
|
}
|
|||
|
|
if (!TextUtils.isEmpty(city)) {
|
|||
|
|
headMaps.put("city", city);
|
|||
|
|
}
|
|||
|
|
if (!TextUtils.isEmpty(district)) {
|
|||
|
|
headMaps.put("district", district);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 4.2 数据验证
|
|||
|
|
```java
|
|||
|
|
if (TextUtils.isEmpty(content) && TextUtils.isEmpty(listBuffer.toString())) {
|
|||
|
|
ToastUtils.showToast(PublishActivity.this, "发布内容为空!");
|
|||
|
|
return; // 文字和图片都为空,不允许发布
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 4.3 提交发布请求
|
|||
|
|
```java
|
|||
|
|
AppService.Instance().publishContent(headMaps, new SimpleCallback() {
|
|||
|
|
@Override
|
|||
|
|
public void onUiSuccess(Object o) {
|
|||
|
|
showToast("发布成功");
|
|||
|
|
finish(); // 发布成功,关闭页面
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public void onUiFailure(int code, String msg) {
|
|||
|
|
showToast(msg); // 显示错误信息
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 5. 可见范围设置 (`bindEvents()`)
|
|||
|
|
|
|||
|
|
#### 5.1 可见范围选项
|
|||
|
|
- **"公开"** (`mShowType = "1"`):所有人可见
|
|||
|
|
- **"仅好友可见"** (`mShowType = "2"`):仅好友可见
|
|||
|
|
|
|||
|
|
#### 5.2 交互流程
|
|||
|
|
1. 用户点击 `oiv_show`("谁可以看")
|
|||
|
|
2. 显示对话框:`PublishShowTypeDialog`
|
|||
|
|
3. 用户选择可见范围:
|
|||
|
|
- 点击"公开":`mShowType = "1"`, `oiv_show.setDesc("公开")`
|
|||
|
|
- 点击"仅好友可见":`mShowType = "2"`, `oiv_show.setDesc("仅好友可见")`
|
|||
|
|
4. 关闭对话框
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 6. 七牛云Token获取 (`getQnToken()`)
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
AppService.Instance().getQnToken(new SimpleCallback<GetQnTokenResult>() {
|
|||
|
|
@Override
|
|||
|
|
public void onUiSuccess(GetQnTokenResult getQnTokenResult) {
|
|||
|
|
GetQnTokenResult data = getQnTokenResult.getData();
|
|||
|
|
mQnToken = data.getToken(); // 保存Token,用于后续图片上传
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public void onUiFailure(int code, String msg) {
|
|||
|
|
// Token获取失败(不影响页面显示,但图片无法上传)
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**说明**:
|
|||
|
|
- Token在页面初始化时获取(`afterViews()`)
|
|||
|
|
- Token用于七牛云图片上传认证
|
|||
|
|
- 如果Token获取失败,图片上传功能将无法使用
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔄 完整业务流程
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
用户打开PublishActivity
|
|||
|
|
↓
|
|||
|
|
初始化UI(输入框、图片列表、可见范围)
|
|||
|
|
↓
|
|||
|
|
获取七牛云Token(getQnToken)
|
|||
|
|
↓
|
|||
|
|
用户输入文字内容(可选)
|
|||
|
|
↓
|
|||
|
|
用户选择图片(拍照/相册)
|
|||
|
|
↓
|
|||
|
|
图片压缩(Luban)
|
|||
|
|
↓
|
|||
|
|
上传图片到七牛云(QiniuUploadFile)
|
|||
|
|
↓
|
|||
|
|
图片URL添加到列表(arrayListPhoto)
|
|||
|
|
↓
|
|||
|
|
用户点击"发布"按钮
|
|||
|
|
↓
|
|||
|
|
验证内容(文字或图片至少有一个)
|
|||
|
|
↓
|
|||
|
|
收集数据(content、images、ispravite)
|
|||
|
|
↓
|
|||
|
|
调用发布接口(AppService.publishContent)
|
|||
|
|
↓
|
|||
|
|
发布成功 → 关闭页面
|
|||
|
|
发布失败 → 显示错误信息
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📊 数据结构
|
|||
|
|
|
|||
|
|
### 发布请求参数
|
|||
|
|
```java
|
|||
|
|
HashMap<String, String> {
|
|||
|
|
"content": "文字内容", // 可选,文字内容
|
|||
|
|
"images": "url1,url2,url3", // 可选,图片URL列表(逗号分隔)
|
|||
|
|
"ispravite": "1", // 必填,可见范围(1:公开, 2:仅好友可见)
|
|||
|
|
"province": "省份", // 可选,省份(从定位或用户设置获取)
|
|||
|
|
"city": "城市", // 可选,城市(从定位或用户设置获取)
|
|||
|
|
"district": "区县", // 可选,区县(从定位或用户设置获取)
|
|||
|
|
"lat": "纬度", // 可选,纬度(从定位获取)
|
|||
|
|
"lng": "经度", // 可选,经度(从定位获取)
|
|||
|
|
"poi": "地点" // 可选,地点/详细地址(从定位获取)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 图片实体
|
|||
|
|
```java
|
|||
|
|
PhotoInfoEntity {
|
|||
|
|
String url; // 图片完整URL(从七牛云获取)
|
|||
|
|
String minUrl; // 图片缩略图URL(当前使用相同URL)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🛠️ 技术要点
|
|||
|
|
|
|||
|
|
### 1. 图片选择
|
|||
|
|
- **库**:`PictureSelector` - 强大的图片选择库
|
|||
|
|
- **功能**:支持拍照、相册选择、多选等
|
|||
|
|
|
|||
|
|
### 2. 图片压缩
|
|||
|
|
- **库**:`Luban` - 图片压缩库
|
|||
|
|
- **目的**:减小图片文件大小,提高上传速度
|
|||
|
|
|
|||
|
|
### 3. 图片上传
|
|||
|
|
- **云存储**:七牛云(Qiniu)
|
|||
|
|
- **流程**:本地文件 → 压缩 → 上传到七牛云 → 获取URL
|
|||
|
|
|
|||
|
|
### 4. RecyclerView适配器
|
|||
|
|
- **适配器**:`FunctionBackImageAdapter`
|
|||
|
|
- **布局管理器**:`FunctionBackGridLayoutManager`(自定义,支持3列网格布局)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ⚠️ 注意事项
|
|||
|
|
|
|||
|
|
1. **内容验证**:文字和图片至少需要有一个,否则不允许发布
|
|||
|
|
2. **Token获取**:必须在图片上传前获取Token,否则上传会失败
|
|||
|
|
3. **图片数量限制**:最多选择9张图片
|
|||
|
|
4. **可见范围**:默认为"公开"(`mShowType = "1"`),用户可手动修改为"仅好友可见"
|
|||
|
|
5. **图片上传异步**:图片选择后立即开始压缩和上传,上传成功后自动添加到列表
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔍 相关文件
|
|||
|
|
|
|||
|
|
- **布局文件**:`uikit/src/main/res/layout/activity_publish.xml`
|
|||
|
|
- **网络服务**:`AppService.publishContent()` - 发布接口
|
|||
|
|
- **网络服务**:`AppService.getQnToken()` - 获取七牛云Token
|
|||
|
|
- **图片上传**:`QiniuUploadFile.uploadFile()` - 七牛云上传方法
|
|||
|
|
- **适配器**:`FunctionBackImageAdapter` - 图片列表适配器
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📝 代码关键位置
|
|||
|
|
|
|||
|
|
### 发布按钮点击(第96-134行)
|
|||
|
|
```java
|
|||
|
|
setToolbarSave("发布", new View.OnClickListener() {
|
|||
|
|
// 收集数据并提交发布请求
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 图片选择回调(第204-369行)
|
|||
|
|
```java
|
|||
|
|
private FunctionBackImageAdapter.onAddPicClickListener onAddPicClickListener = new ... {
|
|||
|
|
// 处理图片选择、压缩、上传逻辑
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 可见范围设置(第143-162行)
|
|||
|
|
```java
|
|||
|
|
findViewById(R.id.oiv_show).setOnClickListener(view -> {
|
|||
|
|
// 显示可见范围选择对话框
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|