android-fragments 问题实施LiveData:观察在恢复片段时是否总是调用(从另一个片段回栈)?

1l5u6lss  于 2022-11-14  发布在  Android
关注(0)|答案(1)|浏览(176)

我正在学习如何在我的应用程序中实现LiveData。我的应用程序有一个MainActivity,其中有2个片段,带有导航列表器。ListFragmentDetailListFragment
我通过viewModel在onCreateViewListFragment上调用函数从服务器获取数据,并观察这一点,以便在成功时将数据填充到RecyclerView中。然后,我单击一个项目,在DetailListFragment中显示详细信息。
问题是当从DetailListFragment返回时,观察viewModel被重新调用,但我不想要它
惨叫我的代码

列表片段

class ListFragment : BaseFragment(), ListClickListener {
    private lateinit var _observeListViewModel: Observer<BaseViewModel.State>
    lateinit var listViewModel: ListViewModel
    private lateinit var adapter: ListAdapter
    private var _binding: ListBinding? = null
    private val binding get() = _binding!!

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
        listViewModel.state.removeObserver(_observeListViewModel)
    }

    private var itemsData = ArrayList<ListResponseDtoListModel>()

    @SuppressLint("PrivateResource")
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        // Inflate the layout for this fragment
        _binding = ListBinding.inflate(inflater, container, false)
       
        listViewModel =
            ViewModelProvider(this).get(ListViewModel::class.java)

        adapter = ListAdapter(itemsData, this)
        val llm = LinearLayoutManager(requireActivity())
        binding.rv.setHasFixedSize(true)
        binding.rv.layoutManager = llm
        binding.rv.adapter = adapter

        //get List
        _observeListViewModel =
            Observer<BaseViewModel.State> { observeListViewModel(it) }
        listViewModel.state.observe(viewLifecycleOwner, _observeListViewModel)
        listViewModel.getList(requireContext())

        return binding.root
    }

    private fun observeListViewModel(state: BaseViewModel.State?) {
        when (state) {
            BaseViewModel.State.Loading -> {
                loadingState()
            }
            is BaseViewModel.State.Error -> {
                errorState()
            }
            is BaseViewModel.State.Success -> {
                val data = state.data as ListModel
                if (data.status == KopraMobile().SUCCESS) {
                    if (data.content!!.listResponseDtoList.size == 0) {
                        nodataState()
                    } else data.content?.listResponseDtoList.let {
                        successState(it)
                    }
                } else
                    errorState()
            }
            is BaseViewModel.State.SessionTimeout -> {
                errorState()
                (parentFragment as BaseFragment).logOut()
            }
            is BaseViewModel.State.ErrorResponse -> {
                errorState()
            }

            else -> {}
        }
    }

    private fun successState(it: Any) {
        ....
    }

    private fun loadingState() {
        ....
    }

    private fun nodataState() {
        ....
    }

    private fun errorState() {
        ....
    }

    override fun onItemClicked(dashboardItem: ListResponseDtoListModel?) {
        findNavController().navigate(R.id.action_listFragment_to_detailListFragment)
    }

}

详细数据片段

class DetailListFragment : BaseFragment(){
    private var _binding: DetailListBinding? = null
    private val binding get() = _binding!!

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

    private var itemsData = ArrayList<DetailListResponseDtoListModel>()

    @SuppressLint("PrivateResource")
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        // Inflate the layout for this fragment
        _binding = DetailListBinding.inflate(inflater, container, false)
      
        binding.incToolbar1.header.text = "Detail"
        binding.incToolbar1.back.setImageResource(com.google.android.material.R.drawable.material_ic_keyboard_arrow_previous_black_24dp)
        binding.incToolbar1.back.setOnClickListener {
            findNavController().popBackStack()
        }

        return binding.root
    }
}

列表视图模型

class ListViewModel : BaseViewModel() {
    fun getList(context: Context)
    {
        _state.postValue(State.Loading)
        job = CoroutineScope(Dispatchers.IO + exceptionHandler).launch {
            try {
                val response =
                    NetworkApi().getListApi().getList( BuildConfig.APPLICATION_ID,  Prefs.getPublicAuthorization(context)
                    )
                withContext(Dispatchers.Main) {
                    _state.postValue(
                        if (response.isSuccessful) {
                            State.Success( response.headers(), response.body()   )
                        } else {
                            State.ErrorResponse( response.headers(), response.errorBody()  ) }
                    )
                }
            } catch (throwble: Throwable) {
                _state.postValue(
                    State.Error("Error : ${throwble.message.toString()} ")
                )
            }
        }
    }
}

基本视图模型

open class BaseViewModel : ViewModel() {

    sealed class State {
        object Loading : State()
        data class Success(val headers: Headers, val data: Any?) : State()
        data class ErrorResponse(val headers: Headers, val errorResponse: ResponseErrorModel) :
            State()
        data class Error(val message: String?) : State()
        data class SessionTimeout(val sessionTimeout: String?) : State()
    }

    var job: Job? = null
    val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
        _state.postValue(State.Error("Exception handled: ${throwable.localizedMessage}"))
    }

    val _state = MutableLiveData<State>()
    val state: LiveData<State> get() = _state
    
    override fun onCleared() {
        super.onCleared()
        job?.cancel()
    }
}

我希望有人能帮我解决这个问题。谢谢,对不起我的英语。

wpcxdonn

wpcxdonn1#

您可以使用LiveData的这个子类,它只会发出一次

public class SingleLiveEvent<T> extends MutableLiveData<T> {

private static final String TAG = "SingleLiveEvent";

private final AtomicBoolean mPending = new AtomicBoolean(false);

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull final Observer<? super T> observer) {

    if (hasActiveObservers()) {
        Log.w(TAG, "Multiple observers registered but only one will be notified of changes.");
    }

    // Observe the internal MutableLiveData
    super.observe(owner, new Observer<T>() {
        @Override
        public void onChanged(@Nullable T t) {
            if (mPending.compareAndSet(true, false)) {
                observer.onChanged(t);
            }
        }
    });
}

@MainThread
public void setValue(@Nullable T t) {
    mPending.set(true);
    super.setValue(t);
}

/**
 * Used for cases where T is Void, to make calls cleaner.
 */
@MainThread
public void call() {
    setValue(null);
 }
}

相关问题