问题:
我正在尝试将 ID 参数传递到对话框屏幕以按 ID 查看所需的数据。尽管响应过程已成功完成(如堆栈跟踪所示),但场所的数据始终返回 NullPointerException。以下几行中使用此 API 的相同步骤与项目的其他部分完美配合。
如图所示,响应状态成功,API 数据已获取,但仍然提供此错误。
如果有人能帮忙的话。
错误:
API响应步骤:
//对话框屏幕
@Composable
fun FetchVenueInfo(
onDismiss: ()-> Unit,
onConfirm:()->Unit,
mainViewModel: MainViewModel = hiltViewModel()
) {
val context = LocalContext.current
LaunchedEffect(key1 = Unit) {
if (!mainViewModel.isVenuesByIdInitialized.value) {
mainViewModel.getVenuesById(mainViewModel.venueId.value)
mainViewModel.isVenuesByIdInitialized.value = true
}
}
when (val state = mainViewModel.venuesByIdState.collectAsState().value) {
is VenuesByIdState.Empty -> { }
is VenuesByIdState.Loading -> { }
is VenuesByIdState.Error -> {
Toast.makeText(context, state.message, Toast.LENGTH_SHORT).show()
}
is VenuesByIdState.Success -> {
CustomDialog(
onDismiss = { onDismiss() },
onConfirm = { onConfirm() },
venuesResponse = state.data.body()!!
)
}
}
}
@Composable
fun CustomDialog(
onDismiss: ()-> Unit,
onConfirm:()->Unit,
venuesResponse: VenuesResponse
) {
val dark = LocalTheme.current.isDark
Dialog(
onDismissRequest = {
onDismiss()
},
properties = DialogProperties(
usePlatformDefaultWidth = false
)
) {
Card(
elevation = CardDefaults.cardElevation(8.dp),
shape = RoundedCornerShape(15.dp),
modifier = Modifier
.fillMaxWidth(0.95f)
.border(
2.dp, color = MaterialTheme.colorScheme.primary,
shape = RoundedCornerShape(15.dp)
)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(15.dp),
verticalArrangement = Arrangement.spacedBy(25.dp)
){
Text(venueResponse.name!!) // <- NullPointerException
Card(
modifier = Modifier
.fillMaxWidth()
) {
AsyncImage(
model = venuesResponse.image, // <- NullPointerException
contentDescription = "Image"
)
}
}
}
}
}
//点击打开对话框
@Composable
fun MainScreen(
matchByIdResponseItem: MatchByIdResponseItem,
mainViewModel: MainViewModel = hiltViewModel()
) {
if (mainViewModel.isDialogShown) {
FetchStadiumInfo(
onDismiss = { mainViewModel.onDismiss() },
onConfirm = {}
)
}
Card(
modifier = Modifier
.fillMaxWidth()
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = ripple(
bounded = true,
color = MaterialTheme.colorScheme.primary
),
onClick = {
mainViewModel.setId(matchByIdResponseItem.fixture!!.venue!!.id!!)
mainViewModel.onDialogOpened()
}
)
.padding(top = 1.dp),
colors = CardDefaults.cardColors(
containerColor = Color.Transparent
)
) {
//...
}
}
//视图模型
@HiltViewModel
class MainViewModel @Inject constructor(private val mainRepository: MainRepository): ViewModel() {
private var _venuesByIdState = MutableStateFlow<VenuesByIdState>(VenuesByIdState.Empty)
val venuesByIdState: StateFlow<VenuesByIdState> = _venuesByIdState
//Call Limit
private var _isVenuesByIdInitialized = mutableStateOf(false)
var isVenuesByIdInitialized: MutableState<Boolean> = _isVenuesByIdInitialized
var isDialogShown by mutableStateOf(false)
private set
private var _venueId = mutableIntStateOf(0)
val venueId: MutableState<Int> = _venueId
fun onDialogOpened(){
isDialogShown = true
}
fun onDismiss() {
isDialogShown = false
}
fun setId(id: Int) {
viewModelScope.launch {
_venueId.intValue = id
}
}
suspend fun getVenuesById(id: Int) {
_venuesByIdState.value = VenuesByIdState.Loading
try {
val venueByIdResponse = mainRepository.getVenuesById(id)
_venuesByIdState.value = VenuesByIdState.Success(data = venueByIdResponse)
Log.d("Tag", "Success")
}
catch (exception: HttpException) {
_venuesByIdState.value = VenuesByIdState.Error("Something went wrong")
}
catch (exception: IOException) {
_venuesByIdState.value = VenuesByIdState.Error("IO Exception")
}
}
}
sealed class VenuesByIdState {
object Empty: VenuesByIdState()
object Loading: VenuesByIdState()
class Success(val data: Response<VenuesResponse>): VenuesByIdState()
class Error(val message: String): VenuesByIdState()
}
class MainRepository @Inject constructor(
private val mainApiService: MainApi
) {
suspend fun getVenuesById(id: Int): Response<VenuesResponse> = mainApiService.getVenuesById(id)
}
interface MainApi {
@Headers("api-key: $API_KEY")
@GET(Constants.GET_VENUES)
suspend fun getVenuesById(
@Query(Constants.VENUE_BY_ID_PARAM) id: Int
): Response<VenuesResponse>
}
您的日志仅显示 API 已成功返回数据。但它并没有给你任何提示:Retrofit/OkHttp/Gson 是否能够成功地将响应数据映射到你的
Response<VenuesResponse>
类上。
您尚未提供
VenuesResponse
类,但如果字段名称或 JSON 响应的层次结构与您的 Kotlin 类不匹配,则可能会发生以下情况:所有字段都将设置为 null
。
我建议您按如下方式更新日志语句:
Log.d("Tag", "Success: $venueByIdResponse ")
并检查此时值是否已经为空。
此外,请确保使用正确的变量名称。这可能只是一个错字,但是
Text(venueResponse.name!!)
甚至不应该编译,因为
venueResponse
不存在,它应该是 venuesResponse
。