Sự cố ViewPager2 / Tab với trạng thái ViewModel


9

Tôi đang theo mẫu MVVM - có nghĩa là tôi có ViewModel cho mỗi Fragment.

Tôi đã thêm hai tab bằng cách sử dụng ViewPager2.

Bộ điều hợp của tôi trông như thế này:

@Override
public Fragment createFragment(int position) {
    switch (position) {
        case 0:
            return new MergedItemsFragment();
        case 1:     
            return new ValidatedMergedItemsFragment();
    }
    return new MergedItemsFragment();
}

Các tab đang hoạt động. Tuy nhiên, tôi nhận thấy rằng ViewModel của MergedItemsFragment của tôi đang hoạt động kỳ lạ. Trước khi tôi thêm các tab, tôi đã điều hướng đến Fragment như thế này:

NavHostFragment.findNavController(this).navigate(R.id.action_roomFragment_to_itemsFragment);

Khi tôi để lại đoạn NavHostFragment.findNavController(this).popBackStack()đó và sau đó trở lại đoạn đó, tôi sẽ nhận được một ViewModel trống mới. Điều này đã được dự định.

Với cách tiếp cận mới, tôi đang điều hướng return new MergedItemsFragment(). Khi tôi rời khỏi đoạn đó và sau đó trở về, tôi nhận được một ViewModel chứa dữ liệu cũ . Đó là một vấn đề vì dữ liệu cũ không còn phù hợp nữa vì Người dùng đã chọn dữ liệu khác nhau trong một đoạn khác.


Cập nhật số 1

Tôi nhận ra rằng anh ta thực sự giữ tất cả các Mảnh vỡ cũ trong bộ nhớ vì các câu lệnh in giống nhau được gọi nhiều lần. Số lần nó được gọi là tăng theo số lần tôi rời khỏi và quay lại màn hình đó. Vì vậy, nếu tôi rời đi và quay lại 10 lần và xoay thiết bị của mình, anh ta thực sự sẽ thực hiện một dòng 10 lần. Bạn có đoán được cách triển khai Tab / ViewPager với Thành phần điều hướng theo cách hoạt động với ViewModels không?


Cập nhật số 2

Tôi đặt ViewModels của mình như thế này:

viewModel = new ViewModelProvider(this, providerFactory).get(MergedItemViewModel.class)

Tôi nhận được kết quả tương tự với:

viewModel = ViewModelProviders.of(this).get(MergedItemViewModel.class);

Tôi liên kết ViewModel trong Fragment. Do đó, thislà mảnh vỡ.


Bạn có thể chỉ ra cách bạn đang thiết lập ViewModels không? Ngoài ra, có lý do nào bạn không thể tạo ViewModel mới khi bạn nhận được dữ liệu mới không?
BlackHatSamurai

Tôi đã cập nhật câu hỏi của mình. Không phải là quan điểm của một khung nhìn mà nó tự chăm sóc nó sao? Tôi tạo ra nó một lần và nó tồn tại cho một mảnh. Làm thế nào chính xác tôi sẽ tạo lại nó trong trường hợp tôi có dữ liệu mới và tại sao tôi không cần phải làm điều đó trước đây?
dùng123456789

Bạn không cần phải làm điều đó trước vì mảnh vỡ đã bị phá hủy. Bây giờ bạn đang sử dụng ViewPager và Nó lưu trữ đoạn trong bộ nhớ. Tôi sẽ đề nghị chỉ xóa dữ liệu khi bạn cần. Bạn cần quản lý dữ liệu trong VM, thay vì chính VM.
BlackHatSamurai

Vấn đề tôi gặp phải là các máy ảo cũ thực sự vẫn đang phục vụ LiveData cũ và cung cấp cho các thành phần khác dữ liệu cũ. Vì vậy, việc xóa dữ liệu sẽ không được thực hiện vì các máy ảo cũ tiếp tục can thiệp. Ví dụ: Tôi xóa một danh sách trong ViewModel hiện tại. Tuy nhiên màn hình vẫn nhận được danh sách cũ. Khi tôi gỡ lỗi ViewModel và kiểm tra độ dài của Danh sách, nó báo là 0 - vì nó đã bị xóa. Giải thích hợp lý duy nhất là các ViewModels khác phục vụ dữ liệu cũ.
user123456789

Bạn có đang sử dụng cùng một VM cho mỗi phân đoạn không? Hay mỗi phân đoạn có VM riêng?
BlackHatSamurai

Câu trả lời:


3

Theo nhận xét của bạn, bạn đang sử dụng Fragment và bên trong Fragment đó có viewpager của bạn. Vì vậy, trong khi tạo Bộ điều hợp cho ViewPager, bạn cần phải vượt qua childFragmentManager thay vì getActivity ()

Dưới đây là một bộ chuyển đổi mẫu cho viewPager của bạn mà bạn có thể sử dụng

class NewViewPagerAdapter(fm: FragmentManager, behavior: Int) : FragmentStatePagerAdapter(fm, behavior) {
    private val mFragmentList: MutableList<Fragment> = ArrayList()
    private val mFragmentTitleList: MutableList<String> = ArrayList()

    override fun getItem(position: Int): Fragment {
        return mFragmentList[position]
    }

    override fun getCount(): Int {
        return mFragmentList.size
    }

    fun addFragment(fragment: Fragment, title: String) {
        mFragmentList.add(fragment)
        mFragmentTitleList.add(title)
    }

    override fun getPageTitle(position: Int): CharSequence? {
        return mFragmentTitleList[position]
    }
}

và trong khi tạo bộ điều hợp của bạn, hãy gọi nó như

   val adapter = NewViewPagerAdapter(
        childFragmentManager,
        FragmentPagerAdapter.POSITION_UNCHANGED
    )

như thể bạn thấy tài liệu về FragmentStatePagerAd CHƯƠNG, nó nói rằng bạn nên vượt qua (FragmentManager, int) bên trong hàm tạo của bộ điều hợp

Tôi hy vọng điều này sẽ giải quyết vấn đề của bạn vì tôi đã phải đối mặt với cùng một vấn đề một ngày nào đó.

Chúc mừng mã hóa.


1
Cảm ơn. Như ianhanniballake đã nói, tự mình đi vào đoạn là đủ, chỉ cần đảm bảo rằng bạn có một dụng cụ điều chỉnh phù hợp. Vì vậy, cả hai anwers là chính xác.
user123456789
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.