我目前正在开发一个 Android 应用程序,我尝试使用 Retrofit 进行 API 调用并在 RecyclerView 中显示检索到的数据。下面,我包含了 Retrofit 设置、ViewModel 和相关组件的相关代码片段。
interface ApiServices {
@GET("home/banners.php")
suspend fun getBannersList(): Response<ResponseBanner>
}
class ResponseBanner : ArrayList<ResponseBanner.ResponseBannerItem>() {
data class ResponseBannerItem(
@SerializedName("id")
val id: Int?,
@SerializedName("image")
val image: String?,
@SerializedName("link")
val link: String?,
@SerializedName("type")
val type: String?
)
}
class HomeRepository @Inject constructor(private val api: ApiServices) {
suspend fun getBannerList() = api.getBannersList()
}
以下是 HomeIntent 和 HomeState 密封类:
sealed class HomeIntent {
data class LoadBanners(val banner: MutableList<ResponseBanner.ResponseBannerItem>) : HomeIntent()
}
sealed class HomeState {
object Idle : HomeState()
object LoadingProfile : HomeState()
object LoadingBanner : HomeState()
object Empty : HomeState()
data class BannerListItem(val banner: MutableList<ResponseBanner.ResponseBannerItem>) : HomeState()
data class Error(val error: String) : HomeState()
}
5.HomeViewModel类: 负责管理 UI 状态并与存储库交互的 ViewModel 定义如下:
@HiltViewModel
class HomeViewModel @Inject constructor(private val repository: HomeRepository) : ViewModel() {
val intentChannel = Channel<HomeIntent>()
private val _state = MutableStateFlow<HomeState>(HomeState.Idle)
val state: StateFlow<HomeState> get() = _state
init {
handleIntents()
}
private fun handleIntents() = viewModelScope.launch {
intentChannel.consumeAsFlow().collect { intent ->
when (intent) {
is HomeIntent.LoadBanners -> fetchingBanner()
}
}
}
private suspend fun fetchingBanner() {
val response = repository.getBannerList()
when (response.code()) {
in 200..202 -> {
_state.emit(HomeState.BannerListItem(response.body()!!))
}
in 400..499 -> {
_state.emit(HomeState.Error(""))
}
in 500..599 -> {
_state.emit(HomeState.Error(""))
}
}
}
}
.6 HomeFragment类: 这是 HomeFragment 类的一个片段,我在其中观察 ViewModel 的状态以更新 UI:
@AndroidEntryPoint
class HomeFragment : Fragment() {
//Binding
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
@Inject
lateinit var bannerAdapter: AdapterBanner
//other
private val viewModel: HomeViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(layoutInflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//initViews
binding.apply {
//lifecycle
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.state.collect { state ->
when (state) {
is HomeState.Idle -> {}
is HomeState.LoadingBanner -> {}
is HomeState.LoadingProfile -> {}
is HomeState.BannerListItem -> {}
is HomeState.Empty -> {}
is HomeState.Error -> {}
}
}
}
}
}
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
}
我还在“AndroidManifest.xml”文件中添加了必要的互联网访问权限,并包含“android:usesCleartextTraffic=”true”。”
尽管设置了如上所示的代码,但我遇到了一个问题:当我在 ViewModel 中使用断点时,API 调用似乎没有进行。我已经检查了错误并检查了代码,但我无法弄清楚为什么没有进行调用。有人可以帮我找出可能导致此问题的原因吗? '我使用最新版本的 Retrofit 和 Okhttp' 预先感谢您的协助!
我使用断点进行测试,视图模型根本没有被调用,我用来调用横幅的函数。
您从未发送过加载横幅的意图,
在ViewModel中你需要执行以下操作
init{
handleIntents()
onIntent(HomeIntent.LoadBanners)/*I don't know your business requirement,
you may choose to call this from fragment on a button click or from a lifecycle callback.*/
}
fun onIntent(intent:HomeIntent) = viewModelScope.launch {
intentChannel.send(intent)
}