android - 改造第一次调用会冻结 UI
问题描述
我在我的 Android 应用程序中使用 Retrofit 和 TMDB API。改造第一次调用会冻结 UI。我几乎尝试了所有方法,但没有奏效。(我试图将所有动作都放在协程中)它在第一次调用时一直冻结。非常感谢您的帮助。请检查我的代码:
TmdbService.kt
object TmdbService {
fun getClient(): TmdbApi {
val requestInterceptor = Interceptor {
val url = it.request()
.url()
.newBuilder()
.addQueryParameter("api_key", API_KEY)
.build()
val request = it.request()
.newBuilder()
.url(url)
.build()
return@Interceptor it.proceed(request)
}
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(requestInterceptor)
.connectTimeout(60, TimeUnit.SECONDS)
.build()
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
return Retrofit.Builder()
.client(okHttpClient)
.baseUrl(BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
.create(TmdbApi::class.java)
}
}
TmdbAPI.kt
interface TmdbApi {
@GET("search/movie")
suspend fun getMovie(
@Query("query") query: String,
@Query("page") page: Int
): Response<MovieResult>
@GET("search/tv")
suspend fun getSeries(
@Query("query") query: String,
@Query("page") page: Int
): Response<SeriesResult>
}
电影列表视图模型.kt
class MovieListViewModel : ViewModel() {
//########## TMDB API
private val api: MutableLiveData<TmdbApi> by lazy { MutableLiveData<TmdbApi>() }
//########## Progress MaterialTextView text
private var _progressMTVText = MutableLiveData<String>()
val progressMTVText: LiveData<String>
get() = _progressMTVText
fun setProgressMTVText(text: String) {
_progressMTVText.value = text
}
//########## Progress LinearLayout gone
private var _progressLLGone = MutableLiveData<Boolean>()
val progressLLGone: LiveData<Boolean>
get() = _progressLLGone
fun isProgressLLGone(gone: Boolean) {
_progressLLGone.value = gone
}
//########## Get data
fun getData(query: String, adapter: MovieListAdapter) {
val listData = Pager(PagingConfig(pageSize = PAGE_SIZE)) {
MovieDataSource(query, api.value!!)
}.flow.cachedIn(viewModelScope)
viewModelScope.launch {
listData.collect {
adapter.submitData(it)
}
}
}
init {
viewModelScope.launch {
api.value = TmdbService.getClient()
}
}
}
电影数据源.kt
class MovieDataSource(private val query: String, private val api: TmdbApi) :
PagingSource<Int, Movie>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Movie> {
return try {
val currentLoadingPageKey = params.key ?: 1
val responseData = mutableListOf<Movie>()
responseData.addAll(
api.getMovie(query, currentLoadingPageKey).body()?.results ?: emptyList()
)
LoadResult.Page(
data = responseData,
prevKey = if (currentLoadingPageKey == 1) null else currentLoadingPageKey - 1,
nextKey = currentLoadingPageKey.plus(1)
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
override fun getRefreshKey(state: PagingState<Int, Movie>): Int? {
return state.anchorPosition
}
}
电影列表片段.kt
class MovieListFragment : Fragment(), MovieListAdapter.ItemClickListener {
private lateinit var viewModel: MovieListViewModel
private lateinit var binding: FragmentMovieListBinding
private lateinit var adapter: MovieListAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
viewModel = ViewModelProviders.of(this).get(MovieListViewModel::class.java)
binding =
DataBindingUtil.inflate(inflater, R.layout.fragment_movie_list, container, false)
binding.let {
it.viewModel = viewModel
it.lifecycleOwner = viewLifecycleOwner
}
observe()
setRecyclerView()
viewModel.isProgressLLGone(true)
return binding.root
}
private fun observe() {
searchResult.observe(viewLifecycleOwner, {
if (networkAvailable) {
if (!it.isNullOrEmpty()) {
with(viewModel) {
setProgressMTVText("${getString(R.string.searching_for)}
\"${searchResult.value}\" ...")
isProgressLLGone(false)
}
CoroutineScope(Dispatchers.Main).launch {
delay(500)
viewModel.getData(it, adapter)
}
}
} else R.string.no_internet_connection.showToast(requireContext())
})
}
private fun setRecyclerView() {
adapter = MovieListAdapter(this)
binding.fragmentMovieListMainRV.let {
it.layoutManager = LinearLayoutManager(context)
it.adapter = adapter
}
CoroutineScope(Dispatchers.Main).launch {
adapter.loadStateFlow.collectLatest {
with(viewModel) {
when (it.append) {
is LoadState.Loading -> {
setProgressMTVText("${getString(R.string.searching_for)}
\"${searchResult.value}\" ...")
isProgressLLGone(false)
}
is LoadState.NotLoading -> {
setProgressMTVText("")
isProgressLLGone(true)
}
is LoadState.Error -> {
setProgressMTVText("")
isProgressLLGone(true)
if (!networkAvailable) R.string.no_internet_connection.showToast(
requireContext()
)
}
}
}
}
}
}
override fun onItemClick(movie: Movie) {
startActivity(Intent(context, MovieDetailActivity::class.java).putExtra("movie", movie))
}
}
解决方案
推荐阅读
- laravel - Laravel 使用 lat 和 long 值查找 10KM 内的商店
- regex - 正则表达式提取文件名信息的问题
- c# - CustomControl 中文本框的事件 PreviewTextInput 。请帮我
- github-actions - GitHub Actions:如果问题已经在项目中,请不要运行作业
- java - 如何从 Oracle 中的列中匹配逗号分隔值?
- javascript - JavaScript 正则表达式:删除括号、方括号和西里尔字符之间的文本
- html - 图表不显示
- php - 在 Cpanel 上部署之前混淆 php 代码?
- javascript - WebRTC - 创建 RTC 数据通道的正确方法是什么?
- angular - 角度继承组件