我正在构建具有片段的 Android 应用程序,并且该应用程序使用 MVVM 设计模式。 每个片段代表一个足球联赛标题和图标 这些选项卡根据 API 调用动态添加。
这里是API调用签名调用
@GET("/leagues")
suspend fun getLeague(
@Query("id")
leagueId: Int = Shared.LEAGUES_IDS[0],
@Query("current")
current: String = "true"
): Response<Leagues>
这是用于调用 API 和存储数据的视图模型类
@HiltViewModel
class FootBallViewModel @Inject constructor(
private val app: Application,
private val remoteRepository: RemoteRepository,
private val defaultLocalRepository: DefaultLocalRepository
): ViewModel() {
var apiCounter = 0
val leagues: MutableList<Leagues> = mutableListOf()
private val _leaguesMutableLiveData = MutableLiveData<ResponseState<Leagues>>()
val leaguesMutableLiveData: LiveData<ResponseState<Leagues>> = _leaguesMutableLiveData
init {
viewModelScope.launch(Dispatchers.IO) {
if(Shared.isConnected) {
Shared.LEAGUES_IDS.forEach { leagueId ->
when(val responseState = getLeague(leagueId)) { //here's the call of league API
is ResponseState.Success -> {
if(Shared.isLiveMatches)
responseState.data?.body()?.response?.get(0)?.seasons?.get(0)?.year?.let { season ->
getLeagueMatches(
leagueId,
season,
app.getString(R.string.live_matches)
)
}
else
responseState.data?.body()?.response?.get(0)?.seasons?.get(0)?.year?.let { season ->
getLeagueMatches(
leagueId,
season,
null
)
}
}
is ResponseState.Loading -> {}
is ResponseState.Error -> {}
}
}
}
}
}
suspend fun getLeague(id: Int): ResponseState<Response<Leagues>> = viewModelScope.async(Dispatchers.IO) {
if (Shared.isConnected) {
try {
val response = remoteRepository.getLeague(id)
response?.body()?.let { leagues.add(it) }
_leaguesMutableLiveData.postValue(ResponseState.Success(response?.body()!!))
apiCounter++
Log.i("apiCounter", apiCounter.toString())
return@async ResponseState.Success(response)
} catch (exception: Exception) {
_leaguesMutableLiveData.postValue(ResponseState.Error(app.getString(R.string.unknown_error)))
handleLeaguesException(exception)
return@async ResponseState.Error(app.getString(R.string.unknown_error))
}
}
else {
_leaguesMutableLiveData.postValue(ResponseState.Error(app.getString(R.string.unknown_error)))
return@async ResponseState.Error(app.getString(R.string.unable_to_connect))
}
}.await()
....
} //end of view model class
最后这是我动态添加选项卡的方法
footBallViewModel.leaguesMutableLiveData.observe(viewLifecycleOwner) {
TabItemBinding.inflate(layoutInflater).apply {
this.league = it.data?.response?.get(0)?.league
val tab = tabLayout.newTab().setCustomView(this.root)
tabLayout.addTab(tab)
val animation = AnimationUtils.loadAnimation(context, R.anim.slide_in)
tab.customView?.startAnimation(animation)
}
Log.i("tabsCount", tabLayout.tabCount.toString())
}
问题定义: 现在选项卡已完美添加,但当我旋转设备时问题就出现了,因为
leaguesMutableLiveData
仅保存最后存储的联赛项目,选项卡布局仅从 leaguesMutableLiveData
获取最后一个选项卡
我尝试过的其他解决方案: 我试图让
leaguesMutableLiveData
保持 MutableList<League>
但这不起作用,因为每次我向列表中添加联赛时,观察者总是添加额外的选项卡,因为观察者从第一个元素开始循环联赛列表。
这个想法是在联赛 API 的所有调用完成后发布联赛列表。
在下面的代码片段中请注意
class FootBallViewModel @Inject constructor(
private val app: Application,
private val remoteRepository: RemoteRepository,
private val defaultLocalRepository: DefaultLocalRepository
): ViewModel() {
val leagues: MutableList<League> = mutableListOf()
private val _leaguesMutableLiveData = MutableLiveData<MutableList<League>>()
val leaguesLiveData: LiveData<MutableList<League>> = _leaguesMutableLiveData
init {
viewModelScope.launch(Dispatchers.IO) {
if(Shared.isConnected) {
Shared.LEAGUES_IDS.forEach { leagueId ->
when(val responseState = getLeague(leagueId)) {
is ResponseState.Success -> {
if(Shared.isLiveMatches)
responseState.data?.body()?.response?.get(0)?.seasons?.get(0)?.year?.let { season ->
getLeagueMatches(
leagueId,
season,
app.getString(R.string.live_matches)
)
}
else
responseState.data?.body()?.response?.get(0)?.seasons?.get(0)?.year?.let { season ->
getLeagueMatches(
leagueId,
season,
null
)
}
}
is ResponseState.Loading -> {}
is ResponseState.Error -> {}
}
}
_leaguesMutableLiveData.postValue(leagues)
}
}
}
suspend fun getLeague(id: Int): ResponseState<Response<League>?> = viewModelScope.async(Dispatchers.IO) {
if (Shared.isConnected) {
try {
val response = remoteRepository.getLeague(id)
response?.body()?.let { leagues.add(it) }
return@async ResponseState.Success(response)
} catch (exception: Exception) {
handleLeaguesException(exception)
return@async ResponseState.Error(app.getString(R.string.unknown_error))
}
}
else {
return@async ResponseState.Error(app.getString(R.string.unable_to_connect))
}
}.await()
.....
} //end of view model class
发生什么事了?
我们添加一个列表变量
val leagues: MutableList<League> = mutableListOf()
,它保存从getLeague(id: Int)
返回的所有联赛
我们添加两个实时数据变量来保存我们的联赛列表
//用于封装
私有 val _leaguesMutableLiveData = MutableLiveData
val leaguesLiveData:LiveData
在此函数体内
getLeague(id: Int)
我们通过以下代码行将返回的联赛添加到列表中
val 响应=remoteRepository.getLeague(id) 响应?.body()?.let { leagues.add(it) }
最后,循环联赛 ID 后
Shared.LEAGUES_IDS.forEach { leagueId -> 当(val responseState = getLeague(leagueId))
.... } //for循环结束
然后我们将最终列表添加到我们的可变实时数据对象中,如下所示
_leaguesMutableLiveData.postValue(leagues)