본문 바로가기
Projects/FineByMe

[Android/Kotlin] StaggeredGridLayout 사용시 발생한 화면 재구성문제 수정

by quessr 2024. 7. 29.

최근에 StaggeredGridLayoutManager를 사용한 즐겨찾기 화면에서 다음과 같은 문제가 발생했습니다:

  • 즐겨찾기 화면에서 첫 번째 사진을 클릭하여 상세 보기로 이동
  • 사진 상세 화면에서 즐겨찾기를 해제
  • 뒤로 가기를 눌러 다시 즐겨찾기 화면으로 돌아오면 빈 화면이 보여짐

이 문제는 StaggeredGridLayoutManager에서 아이템을 재배치하는 과정에서 발생했습니다. 아이템들을 제대로 불러오지 못하고 화면을 재구성하는 데 실패하여 빈 화면을 보여주게 된 것입니다.

이 문제를 해결하기 위해 RecyclerView의 상태를 복원하는 방법을 적용했습니다. 이를 통해 화면이 빈 화면으로 나타나는 현상을 해결할 수 있었습니다. 다음은 해결 방법입니다.

해결 방법: RecyclerView 상태 복원

RecyclerView 상태를 복원하는 방법을 사용하여 문제를 해결했습니다. 상태를 복원하면 사용자가 상세 화면에서 돌아왔을 때 RecyclerView가 정확히 이전 상태를 유지할 수 있습니다.

 

1. 상태 저장을 위한 변수 추가:

  • Fragment 클래스에 RecyclerView의 상태를 저장할 변수를 추가합니다.
private var recyclerViewState: Parcelable? = null

 

2. 상태 저장:

  • Fragment가 중단되기 전에 RecyclerView의 상태를 저장합니다.
override fun onPause() {
    super.onPause()
    recyclerViewState = recyclerView.layoutManager?.onSaveInstanceState()
}

 

3. 상태 복원:

  • Fragment가 다시 활성화될 때 저장된 상태를 복원합니다.
override fun onViewStateRestored(savedInstanceState: Bundle?) {
        super.onViewStateRestored(savedInstanceState)
        recyclerView.layoutManager?.onRestoreInstanceState(recyclerViewState)
    }

 

5. 전체 수정된 코드:

class FavoriteListFragment : Fragment() {

    private lateinit var photoAdapter: PhotoAdapter
    private val favoriteListViewModel: FavoriteListViewModel by activityViewModels {
        val application = requireActivity().application
        val photoDao = FavoritePhotosDatabase.getDatabase(application).PhotoDao()
        val retrofitService = RetrofitInstance.retrofitService
        val unSplashDataSource = UnSplashDataSource(retrofitService)
        val userDataSource = UserDataSource(photoDao)
        val photoRepository = PhotoRepository(unSplashDataSource, userDataSource)
        AppViewModelFactory(application, photoRepository)
    }
    private var recyclerViewState: Parcelable? = null

    private var _binding: FragmentFavoriteListBinding? = null
    private val binding get() = _binding!!
    private lateinit var recyclerView: RecyclerView
    private var isPass = false

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentFavoriteListBinding.inflate(inflater)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        setupRecyclerview()
        setupObservers()
        setupListeners()

    }

    private fun setupRecyclerview() {
        photoAdapter = PhotoAdapter(favoriteListViewModel)
        recyclerView = binding.recyclerView

        val numberOfColumns = 2
        val layoutManager =
            StaggeredGridLayoutManager(numberOfColumns, LinearLayoutManager.VERTICAL).apply {
                gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
            }

        recyclerView.layoutManager = layoutManager
        binding.recyclerView.adapter = photoAdapter
    }

    private fun setupObservers() {
        favoriteListViewModel.photos.observe(
            viewLifecycleOwner
        ) { photos ->
            photoAdapter.submitList(photos) {
                if (recyclerViewState != null) {
                    recyclerView.layoutManager?.onRestoreInstanceState(recyclerViewState)
                }
                else {
                    recyclerView.scrollToPosition(0)
                }
            }
            binding.tvEmpty.isVisible = photos.isEmpty()
        }
    }

    private fun setupListeners() {
        photoAdapter.setOnPhotoClickListener(object : PhotoAdapter.OnPhotoClickListener {
            override fun onPhotoClick(photo: Photo) {
                val intent = newPhotoDetail(requireContext(), photo)
                startActivity(intent)
            }
        })
    }

    override fun onViewStateRestored(savedInstanceState: Bundle?) {
        super.onViewStateRestored(savedInstanceState)
        recyclerView.layoutManager?.onRestoreInstanceState(recyclerViewState)
    }
    
    override fun onResume() {
        super.onResume()
        if (isPass) {
            isPass = false
            return
        }
        favoriteListViewModel.onResumeScreen()
    }

    override fun onPause() {
        super.onPause()
        recyclerViewState = recyclerView.layoutManager?.onSaveInstanceState()
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

 

이 방법을 통해 RecyclerView의 상태를 저장하고 복원하여 상세 보기에서 돌아왔을 때 빈 화면이 나타나는 문제를 해결할 수 있습니다. 이로 인해 사용자 경험이 향상되었으며, 즐겨찾기 목록이 정상적으로 표시됩니다.