feat: 国内进港移库 ui
This commit is contained in:
501
CLAUDE.md
501
CLAUDE.md
@@ -2509,3 +2509,504 @@ PictureSelector.create(this)
|
||||
- ✅ 使用DataBinding简化代码
|
||||
- ✅ 利用扩展函数处理通用逻辑
|
||||
- ✅ 不重复造轮子,保持架构一致性
|
||||
|
||||
---
|
||||
|
||||
## 常见编译错误及解决方案
|
||||
|
||||
### 1. DataBinding错误:Cannot resolve type 'DetailsPageType'
|
||||
|
||||
**错误信息**:
|
||||
```
|
||||
ERROR: Cannot resolve type 'DetailsPageType' file://app/src/main/res/layout/activity_xxx.xml Line:XX
|
||||
```
|
||||
|
||||
**错误原因**:
|
||||
在XML布局文件中import的包名错误。
|
||||
|
||||
**错误示例**:
|
||||
```xml
|
||||
<import type="com.lukouguoji.module_base.constant.DetailsPageType" />
|
||||
```
|
||||
|
||||
**正确写法**:
|
||||
```xml
|
||||
<import type="com.lukouguoji.module_base.common.DetailsPageType" />
|
||||
```
|
||||
|
||||
**注意**: `DetailsPageType`位于`common`包,不是`constant`包!
|
||||
|
||||
---
|
||||
|
||||
### 2. DataBinding错误:Could not find accessor DataLayoutType.INTEGER
|
||||
|
||||
**错误信息**:
|
||||
```
|
||||
ERROR: Could not find accessor com.lukouguoji.module_base.ui.weight.data.layout.DataLayoutType.INTEGER
|
||||
```
|
||||
|
||||
**错误原因**:
|
||||
`DataLayoutType`枚举中不存在`INTEGER`类型。
|
||||
|
||||
**错误示例**:
|
||||
```xml
|
||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
||||
type="@{DataLayoutType.INTEGER}"
|
||||
value='@={viewModel.bean.count}' />
|
||||
```
|
||||
|
||||
**正确写法**:
|
||||
```xml
|
||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
||||
type="@{DataLayoutType.INPUT}"
|
||||
value='@={viewModel.bean.count}' />
|
||||
```
|
||||
|
||||
**可用类型**:
|
||||
- `DataLayoutType.INPUT` - 文本输入(可输入数字)
|
||||
- `DataLayoutType.SPINNER` - 下拉选择
|
||||
- `DataLayoutType.DATE` - 日期选择
|
||||
|
||||
---
|
||||
|
||||
### 3. Kotlin编译错误:Unresolved reference: PAGE_TYPE
|
||||
|
||||
**错误信息**:
|
||||
```
|
||||
e: Unresolved reference: PAGE_TYPE
|
||||
```
|
||||
|
||||
**错误原因**:
|
||||
`Constant.Key`对象中缺少`PAGE_TYPE`常量。
|
||||
|
||||
**解决方案**:
|
||||
在`module_base/src/main/java/com/lukouguoji/module_base/common/Constant.kt`中添加:
|
||||
|
||||
```kotlin
|
||||
object Key {
|
||||
// ... 其他常量
|
||||
|
||||
// ID
|
||||
const val ID = "id"
|
||||
|
||||
// 页面类型
|
||||
const val PAGE_TYPE = "pageType"
|
||||
|
||||
// ... 其他常量
|
||||
}
|
||||
```
|
||||
|
||||
**使用示例**:
|
||||
```kotlin
|
||||
val starter = Intent(context, XxxActivity::class.java)
|
||||
.putExtra(Constant.Key.PAGE_TYPE, DetailsPageType.Add.name)
|
||||
.putExtra(Constant.Key.ID, id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. Kotlin编译错误:Unresolved reference: Edit
|
||||
|
||||
**错误信息**:
|
||||
```
|
||||
e: Unresolved reference: Edit
|
||||
```
|
||||
|
||||
**错误原因**:
|
||||
`DetailsPageType`枚举中不存在`Edit`值。
|
||||
|
||||
**错误示例**:
|
||||
```kotlin
|
||||
when (viewModel.pageType) {
|
||||
DetailsPageType.Add -> setBackArrow("新增")
|
||||
DetailsPageType.Edit -> setBackArrow("编辑") // ❌ 错误
|
||||
DetailsPageType.Details -> setBackArrow("详情")
|
||||
}
|
||||
```
|
||||
|
||||
**正确写法**:
|
||||
```kotlin
|
||||
when (viewModel.pageType) {
|
||||
DetailsPageType.Add -> setBackArrow("新增")
|
||||
DetailsPageType.Modify -> setBackArrow("编辑") // ✅ 正确
|
||||
DetailsPageType.Details -> setBackArrow("详情")
|
||||
}
|
||||
```
|
||||
|
||||
**DetailsPageType枚举值**:
|
||||
```kotlin
|
||||
enum class DetailsPageType(val title: String) {
|
||||
Add("新增"), // 新增页面
|
||||
Modify("编辑"), // 编辑页面(注意:不是Edit!)
|
||||
Details("详情") // 详情页面
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. Kotlin编译错误:Unresolved reference: IOnItemClickListener
|
||||
|
||||
**错误信息**:
|
||||
```
|
||||
e: Unresolved reference: IOnItemClickListener
|
||||
```
|
||||
|
||||
**错误原因**:
|
||||
import的包名错误,`IOnItemClickListener`在`interfaces`包,不是`impl`包。
|
||||
|
||||
**错误示例**:
|
||||
```kotlin
|
||||
import com.lukouguoji.module_base.impl.IOnItemClickListener // ❌ 错误
|
||||
```
|
||||
|
||||
**正确写法**:
|
||||
```kotlin
|
||||
import com.lukouguoji.module_base.interfaces.IOnItemClickListener // ✅ 正确
|
||||
```
|
||||
|
||||
**使用场景**:
|
||||
```kotlin
|
||||
class XxxViewModel : BaseViewModel(), IOnItemClickListener {
|
||||
override fun onItemClick(position: Int, type: Int) {
|
||||
// 处理点击事件
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. FlowBus使用错误
|
||||
|
||||
#### 错误A:Unresolved reference: observe
|
||||
|
||||
**错误信息**:
|
||||
```
|
||||
e: Unresolved reference: observe
|
||||
```
|
||||
|
||||
**错误原因**:
|
||||
缺少`observe`扩展函数的import。
|
||||
|
||||
**解决方案**:
|
||||
```kotlin
|
||||
import com.lukouguoji.module_base.impl.FlowBus
|
||||
import com.lukouguoji.module_base.impl.observe // ✅ 添加这一行
|
||||
|
||||
// 在Activity中使用
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH_LIST).observe(this) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
```
|
||||
|
||||
#### 错误B:Suspend function 'emit' should be called only from a coroutine
|
||||
|
||||
**错误信息**:
|
||||
```
|
||||
e: Suspend function 'emit' should be called only from a coroutine or another suspend function
|
||||
```
|
||||
|
||||
**错误原因**:
|
||||
`emit()`是suspend函数,需要在协程中调用。
|
||||
|
||||
**错误示例**:
|
||||
```kotlin
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH_LIST).emit("refresh") // ❌ 错误
|
||||
```
|
||||
|
||||
**正确写法**:
|
||||
```kotlin
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
// 在ViewModel中
|
||||
viewModelScope.launch {
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH_LIST).emit("refresh") // ✅ 正确
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7. 图片上传字段错误
|
||||
|
||||
**错误信息**:
|
||||
```
|
||||
e: Unresolved reference: url
|
||||
```
|
||||
|
||||
**错误原因**:
|
||||
`UploadBean`返回的字段名是`newName`,不是`url`。
|
||||
|
||||
**UploadBean结构**:
|
||||
```kotlin
|
||||
class UploadBean {
|
||||
var newName: String = "" // ✅ 正确字段名
|
||||
var zipFileName: String = ""
|
||||
}
|
||||
```
|
||||
|
||||
**错误示例**:
|
||||
```kotlin
|
||||
val result = UploadUtil.upload(filePath)
|
||||
if (result.verifySuccess()) {
|
||||
val imageUrl = result.data?.url ?: "" // ❌ 错误:没有url字段
|
||||
}
|
||||
```
|
||||
|
||||
**正确写法**:
|
||||
```kotlin
|
||||
val result = UploadUtil.upload(filePath)
|
||||
if (result.verifySuccess()) {
|
||||
val imageUrl = result.data?.newName ?: "" // ✅ 正确:使用newName
|
||||
}
|
||||
```
|
||||
|
||||
**完整上传示例**:
|
||||
```kotlin
|
||||
launchLoadingCollect({
|
||||
val uploadedUrls = mutableListOf<String>()
|
||||
imageList.forEach { fileBean ->
|
||||
if (fileBean.path.startsWith("http")) {
|
||||
// 已上传的图片,直接使用URL
|
||||
uploadedUrls.add(fileBean.path)
|
||||
} else {
|
||||
// 本地图片,需要上传
|
||||
val result = UploadUtil.upload(fileBean.path)
|
||||
if (result.verifySuccess()) {
|
||||
uploadedUrls.add(result.data?.newName ?: "") // 使用newName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 提交时将图片URL列表用逗号拼接
|
||||
val params = mapOf(
|
||||
"images" to uploadedUrls.joinToString(",")
|
||||
).toRequestBody()
|
||||
|
||||
NetApply.api.saveData(params)
|
||||
}) {
|
||||
onSuccess = {
|
||||
showToast("保存成功")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8. RecyclerView DataBinding items属性问题
|
||||
|
||||
**问题现象**:
|
||||
在DataBinding中使用`items`属性绑定数据会导致编译错误。
|
||||
|
||||
**错误示例**:
|
||||
```xml
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rvImages"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
items="@{viewModel.imageList}" ❌ 这个属性会导致编译错误
|
||||
itemLayoutId="@{viewModel.imageItemLayoutId}"
|
||||
viewHolder="@{viewModel.imageItemViewHolder}" />
|
||||
```
|
||||
|
||||
**正确做法**:
|
||||
移除`items`属性,在Activity中手动更新adapter。
|
||||
|
||||
**XML布局**:
|
||||
```xml
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rvImages"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
itemLayoutId="@{viewModel.imageItemLayoutId}"
|
||||
viewHolder="@{viewModel.imageItemViewHolder}"
|
||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||
app:spanCount="3" />
|
||||
```
|
||||
|
||||
**Activity代码**:
|
||||
```kotlin
|
||||
import com.lukouguoji.module_base.ktx.commonAdapter
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("页面标题")
|
||||
binding.viewModel = viewModel
|
||||
|
||||
// 监听数据变化并手动更新adapter
|
||||
viewModel.imageList.observe(this) { images ->
|
||||
binding.rvImages.commonAdapter()?.refresh(images)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 9. pageType在DataBinding中的正确使用
|
||||
|
||||
**问题**:
|
||||
如果`pageType`声明为普通变量,DataBinding无法正确绑定。
|
||||
|
||||
**错误示例**:
|
||||
```kotlin
|
||||
class XxxViewModel : BaseViewModel() {
|
||||
var pageType: DetailsPageType = DetailsPageType.Add // ❌ 普通变量
|
||||
}
|
||||
```
|
||||
|
||||
**正确写法**:
|
||||
```kotlin
|
||||
class XxxViewModel : BaseViewModel() {
|
||||
val pageType = MutableLiveData(DetailsPageType.Add) // ✅ 使用LiveData
|
||||
}
|
||||
```
|
||||
|
||||
**ViewModel中访问**:
|
||||
```kotlin
|
||||
fun initOnCreated(intent: Intent) {
|
||||
pageType.value = DetailsPageType.valueOf(
|
||||
intent.getStringExtra(Constant.Key.PAGE_TYPE) ?: DetailsPageType.Add.name
|
||||
)
|
||||
|
||||
if (pageType.value != DetailsPageType.Add) {
|
||||
loadData()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Activity中访问**:
|
||||
```kotlin
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
viewModel.initOnCreated(intent)
|
||||
|
||||
when (viewModel.pageType.value) {
|
||||
DetailsPageType.Add -> setBackArrow("新增")
|
||||
DetailsPageType.Modify -> setBackArrow("编辑")
|
||||
DetailsPageType.Details -> setBackArrow("详情")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**XML中使用**:
|
||||
```xml
|
||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
||||
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||
required="@{viewModel.pageType != DetailsPageType.Details}"
|
||||
title='@{"运单号:"}'
|
||||
value='@={viewModel.bean.waybillNo}' />
|
||||
```
|
||||
|
||||
**注意**: 在XML的DataBinding表达式中,直接使用`viewModel.pageType`即可,不需要`.value`。
|
||||
|
||||
---
|
||||
|
||||
## 错误排查流程
|
||||
|
||||
当遇到编译错误时,按以下顺序排查:
|
||||
|
||||
### 第1步:检查DataBinding错误
|
||||
|
||||
如果看到`android.databinding.tool.util.LoggedErrorException`:
|
||||
|
||||
1. **检查import语句的包名**
|
||||
- ✅ `com.lukouguoji.module_base.common.DetailsPageType`
|
||||
- ❌ `com.lukouguoji.module_base.constant.DetailsPageType`
|
||||
|
||||
2. **检查枚举值是否正确**
|
||||
- ✅ `DataLayoutType.INPUT`、`SPINNER`、`DATE`
|
||||
- ❌ `DataLayoutType.INTEGER`(不存在)
|
||||
- ✅ `DetailsPageType.Modify`(编辑)
|
||||
- ❌ `DetailsPageType.Edit`(不存在)
|
||||
|
||||
3. **移除不支持的属性**
|
||||
- 移除RecyclerView的`items`属性
|
||||
- 改为在Activity中手动更新adapter
|
||||
|
||||
### 第2步:检查Kotlin编译错误
|
||||
|
||||
如果看到`Unresolved reference`:
|
||||
|
||||
1. **检查import语句**
|
||||
- `IOnItemClickListener` → `com.lukouguoji.module_base.interfaces.IOnItemClickListener`
|
||||
- `observe` → `com.lukouguoji.module_base.impl.observe`
|
||||
|
||||
2. **检查常量是否存在**
|
||||
- 确认`Constant.Key.PAGE_TYPE`已定义
|
||||
- 确认`Constant.Key.ID`已定义
|
||||
|
||||
3. **检查字段名称**
|
||||
- `UploadBean`使用`newName`,不是`url`
|
||||
|
||||
### 第3步:检查协程相关错误
|
||||
|
||||
如果看到suspend function相关错误:
|
||||
|
||||
1. **添加必要的import**
|
||||
```kotlin
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.launch
|
||||
```
|
||||
|
||||
2. **在协程中调用emit**
|
||||
```kotlin
|
||||
viewModelScope.launch {
|
||||
FlowBus.with<String>(event).emit(data)
|
||||
}
|
||||
```
|
||||
|
||||
### 第4步:清理并重新构建
|
||||
|
||||
如果上述都检查过,仍有问题:
|
||||
|
||||
```bash
|
||||
# 清理项目
|
||||
./gradlew clean
|
||||
|
||||
# 重新构建
|
||||
./gradlew assembleDebug
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践建议
|
||||
|
||||
### 1. 开发前检查清单
|
||||
|
||||
- [ ] 确认`DetailsPageType`在`common`包
|
||||
- [ ] 确认`IOnItemClickListener`在`interfaces`包
|
||||
- [ ] 确认`Constant.Key.PAGE_TYPE`常量已定义
|
||||
- [ ] 熟悉`DataLayoutType`和`DetailsPageType`的枚举值
|
||||
|
||||
### 2. 代码编写规范
|
||||
|
||||
- ✅ 使用`MutableLiveData`声明`pageType`,不用普通变量
|
||||
- ✅ RecyclerView不使用`items`属性,改用手动更新adapter
|
||||
- ✅ FlowBus的`emit()`必须在`viewModelScope.launch`中调用
|
||||
- ✅ `observe`扩展函数需要单独import
|
||||
- ✅ 图片上传使用`UploadBean.newName`字段
|
||||
|
||||
### 3. 参考已有代码
|
||||
|
||||
遇到问题时,优先参考项目中已有的类似实现:
|
||||
|
||||
- 查看`AccidentVisaDetailsViewModel`了解`pageType`的LiveData用法
|
||||
- 查看`GncShouYunListActivity`了解FlowBus的正确使用
|
||||
- 查看现有的编辑页面了解图片上传的完整流程
|
||||
|
||||
---
|
||||
|
||||
## 快速修复命令
|
||||
|
||||
```bash
|
||||
# 查找DetailsPageType的正确包名
|
||||
grep -r "enum class DetailsPageType" module_base/src --include="*.kt"
|
||||
|
||||
# 查找IOnItemClickListener的正确包名
|
||||
find module_base/src -name "IOnItemClickListener.kt"
|
||||
|
||||
# 查找DataLayoutType的枚举值
|
||||
grep -A 5 "enum class DataLayoutType" module_base/src --include="*.kt"
|
||||
|
||||
# 查找UploadBean的字段定义
|
||||
grep -A 10 "class UploadBean" module_base/src --include="*.kt"
|
||||
```
|
||||
|
||||
通过遵循这些规范和检查清单,可以避免大部分常见的编译错误。
|
||||
Reference in New Issue
Block a user