How to use same viewModel method inside multiple fragment?

378 Views Asked by At

I want use one viewModel and observe object from one method. But I dont want write this observe method in all fragment. Only write in one place and use other fragments. I think I need fragment extension but can't get it how do this. I need help.

This viewModel that I want use.

SharedViewModel.kt


class SharedViewModel @Inject constructor(private val notificationServiceRepo: NotificationServiceRepo) : ViewModel() {

    private val _helpNotification = SingleLiveEvent<NetworkResult<BaseResponse<Any>>>()
    val helpNotification get() = _helpNotification

    fun postHelpNotification(helpNotificationRequest: HelpNotificationRequest) = viewModelScope.launch (
        Dispatchers.IO){
        _helpNotification.postValue(NetworkResult.Loading)
        _helpNotification.postValue(notificationServiceRepo.postNotificationHelp(helpNotificationRequest))
    }
}

this is call method and observe function:

MainFragment.kt

      viewModel.postHelpNotification(HelpNotificationRequest(0))

       viewModel.helpNotification.observe(viewLifecycleOwner) {
           it?.onLoading {}
           it?.onSuccess { result->
               result?.let {
                   InfoDialogWithOneText(
                       InfoDialogType.GOT_HELP_ASKING_FROM_STAFF
                   ).show(childFragmentManager, InfoDialog.TAG)
               }
           }
           it?.onError { error ->
               InfoDialogWithOneText(
                   InfoDialogType.GOT_HELP_ASKING_FROM_STAFF
               ).show(childFragmentManager, InfoDialog.TAG)
           }
       }
   }
  • Tried use sharedViewModel but I will have to write observe method for all.
  • Tried to baseViewModel but it get error hilt view model and also it will be same like shared view model.
1

There are 1 best solutions below

1
TheLibrarian On

For the abstract part, you want it need to cover everything - from having a view model that provides the observable event and handling it. I had to change some types because you did not provide them but it should not be too difficult to apply this to your case.

abstract class HelpNotificationFragment : Fragment() {
    internal abstract val viewModel: HelpNotificationViewModel

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel.helpNotification.observe(viewLifecycleOwner) { result ->
            println(result)
        }
    }
}

abstract class HelpNotificationViewModel : ViewModel() {
    private val _helpNotification = SingleLiveEvent<Result<Any>>()
    // Specify the immutable type otherwise you would expose it as mutable
    val helpNotification: LiveData<Result<Any>>
        get() = _helpNotification

    fun postHelpNotification(helpNotificationRequest: Result<Any>) {
        viewModelScope.launch(Dispatchers.IO) {
            _helpNotification.postValue(helpNotificationRequest)
        }
    }
}

And this is how you would implement the fragments that would use it - the overriding the view model will take care of forcing you to use view model with proper parent:

@HiltViewModel
class MainViewModel @Inject constructor(): HelpNotificationViewModel()

@AndroidEntryPoint
class MainFragment : HelpNotificationFragment() {
    override val viewModel: MainViewModel by viewModels()

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_main, container, false)
        view.findViewById<Button>(R.id.button).setOnClickListener {
            viewModel.postHelpNotification(Result.success("Yay!"))
        }
        return view
    }
}