我的Android应用程序是使用Jetpack Compose和MVVM架构编写的。这是一个基本的电影列表应用程序利用TMDB API。
该应用程序使用带有两列磁贴的LazyVerticalGrid
显示项目列表。用户将滚动列表并单击其中一个,此时将导航到详细信息页面。我用的是NavController
。这是一个独立的屏幕,而不是一个底表对话(虽然我正在考虑改变到这一点)。
导航是通过MainActivity
处理的,每个屏幕都是一个单独的Screen
文件,适当时使用viewModel和存储库。
用户滚动,假设他向下滚动了三对行并点击了第7项。当用户完成详细信息屏幕时,他/她将返回到前一个屏幕,即列表。我遇到的问题是这个屏幕被重绘,这意味着它会向云重新发送一个请求并重绘,用户被返回到列表的顶部。
我看不出这是什么原因,但我=。任何想法,请就如何解决这个问题,或者是我唯一的选择,记住最后滚动到索引,然后重新滚动到它?
这是MovieListScreen
@Composable
fun MovieListScreen(movieDetailsNavigationCallback: (Int) -> Unit) {
val viewModel: MovieListViewModel = hiltViewModel()
val movieDataList = viewModel.getMovieListPage().collectAsLazyPagingItems()
Box(
modifier = Modifier
.fillMaxSize()
.background(
brush = Brush.verticalGradient(
colors = listOf(
SplashGradientStart,
SplashGradientEnd
)
)
),
contentAlignment = Alignment.TopCenter
) {
VerticalGridButtons(movieDataList = movieDataList, movieDetailsNavigationCallback)
}
}
@Composable
fun VerticalGridButtons(
movieDataList: LazyPagingItems<MovieData>,
navigationCallback: (Int) -> Unit,
) {
LazyVerticalGrid(
columns = GridCells.Fixed(2),
contentPadding = PaddingValues(
start = 8.dp,
end = 8.dp,
bottom = 8.dp,
top = 100.dp
),
) {
items(
movieDataList.itemCount
) { index ->
movieDataList[index]?.let { MenuItemTile(it, navigationCallback) }
}
}
// TODO: Add error handling
}
@Composable
fun MenuItemTile(movieData: MovieData, navigationCallback: (Int) -> Unit) {
Card(
Modifier
.padding(8.dp)
.background(Color.Black.copy(alpha = 0.4f)),
shape = RoundedCornerShape(8.dp),
elevation = CardDefaults.cardElevation(
defaultElevation = 8.dp
),
colors = CardDefaults.cardColors(containerColor = Color.White)
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.padding(4.dp)
.background(color = Color.Black.copy(alpha = 1.0f))
.fillMaxWidth(),
) {
AsyncImage(
model = BASE_URL + movieData.posterPath,
contentDescription = "Menu Thumbnail",
contentScale = ContentScale.FillBounds,
modifier = Modifier
.size(250.dp)
.padding(top = 0.dp)
.align(Alignment.CenterHorizontally)
.clickable(onClick = {
Timber.d("onClick event for movie ID == " + movieData.id)
navigationCallback(movieData.id)
}
)
)
Spacer(modifier = Modifier.height(height = 15.dp))
val movieTitleScroll = rememberScrollState(0)
Text(modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(bottom = 10.dp)
.horizontalScroll(movieTitleScroll),
text = movieData.originalTitle,
style = MaterialTheme.typography.displaySmall,
color = Color.White,
maxLines = 1
)
}
}
}
@Preview(showBackground = true)
@Composable
fun MovieListScreenPreview() {
DisneyMoviesTheme() {
MovieListScreen({})
}
}
字符串
这是MovieListViewModel
@HiltViewModel
class MovieListViewModel @Inject constructor(private val repository: MoviesListRepository) : ViewModel() {
init {
viewModelScope.launch(Dispatchers.IO) {
}
}
fun getMovieListPage(): Flow<PagingData<MovieData>> = repository.getDiscoverMoviesPage().cachedIn(viewModelScope)
}
型MainActivity
个
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val stringResourceProvider: StringResourceProviderImpl = StringResourceProviderImpl(resources)
setContent {
DMoviesTheme {
DMDBApp(stringResourceProvider)
}
}
}
}
@Composable
private fun DMDBApp(stringResourceProvider: StringResourceProviderImpl) {
val navController = rememberNavController()
NavHost(navController, startDestination = "splash_screen") {
composable(route = "splash_screen") {
SplashScreen {
navController.navigate("movie_list_screen")
}
}
composable(route = "movie_list_screen") {
MovieListScreen() { id ->
navController.navigate("destination_movie_details_screen/${id}")
}
}
composable(
route = "destination_movie_details_screen/{id}",
arguments = listOf (
navArgument("id") { type = NavType.IntType }
)
) {
val viewModel: MovieDetailsViewModel = hiltViewModel()
MovieDetailsScreen(viewModel.movieDetailsState.value)
}
}
}
型
1条答案
按热度按时间lxkprmvk1#
我离开了这个问题,因为我希望这将有助于其他人保存同样的问题。
我的另一段代码没有被引用,那就是Repository。
字符串
这就是问题的根源。每次调用compose父函数时,都将重新创建Pager。为了解决这个问题,我必须做出以下改变。
停止使用存储库类,改为更改viewModel,如下所示。
型
然后简单地更新
MovieListScreen
如下://瓦尔movieDataList = viewModel.getMovieListPage().collectAsLazyPagingItems()val movieDataList = viewModel.items.collectAsLazyPagingItems()
结果是movieList然后在导航到描述屏幕和从描述屏幕返回之间保持在其先前位置。
我找到了以下文章,解决了我的问题:
Paging 3 list auto refresh on navigation back in jetpack compose navigation