Communication between Service and fragment

80 Views Asked by At

How can we communicate/pass data betweeen service and fragment

I am trying to make a service and i am doing some action in that and i want to update my fragment ui state according to that action which is performed through service but i don't know how to do it

2

There are 2 best solutions below

0
Usman Mahmood On BEST ANSWER

There are many ways you can do that

  1. First and easy way is you can directly get service variable in fragment like this :

        lateinit var sessionService: SessionService
        var isBound = false
    
        val connection = object : ServiceConnection {     
        override fun onServiceConnected(className: ComponentName, service: IBinder){
    
        val binder = service as SessionService.SessionBinder
        sessionService = binder.getService()
        sessionService.exoPlayer = activity.exoPlayer
        isBound = true
    
        if (!mViewModel.prefManager.sessionCompleted) {
            collectServiceStates()
            collectServiceProgress()
        }
    }
    
    override fun onServiceDisconnected(arg0: ComponentName) {
        isBound = false
    }
    }
    
    val progress = sessionService.progress
    
  2. Next you can use stateflow or livedata in service and collect/observe it in fragment like this :

Service file :

fun stopSession(){
        **curretState.value = SessionState.Stopped**
        resetValues()
        countDownTimer.cancel()
        if (isPlaying) {
            pauseAudio()
        }
    } 

Fragment file :

fun collectServiceStates(){
        viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
            sessionService.curretState.collectLatest {
                when(it){
                    SessionState.Paused -> {
                        pauseSession()
                    }
                    SessionState.Started -> {
                        startSession()
                    }
                    SessionState.Stopped -> {
                        stopSession()
                    }
                    SessionState.Completed -> {
                        updateMainViews(true)
                        mViewModel.prefManager.sessionCompleted=true
                    }

                    SessionState.Resumed -> {
                        resumeSession()
                    }
                    SessionState.Idle -> {

                    }
                }
            }
        }
    }
  1. One other way is you can use Local broadcast receiver to communicate between service and fragment
0
Cosmin Oprea On

You can follow the official documentation page https://developer.android.com/guide/fragments/communicate#java

But basically there is an example from the page:

public class ListViewModel extends ViewModel {
private final MutableLiveData<Set<Filter>> filters = new MutableLiveData<>();

private final LiveData<List<Item>> originalList = ...;
private final LiveData<List<Item>> filteredList = ...;

public LiveData<List<Item>> getFilteredList() {
    return filteredList;
}

public LiveData<Set<Filter>> getFilters() {
    return filters;
}

public void addFilter(Filter filter) { ... }

public void removeFilter(Filter filter) { ... }
}

public class ListFragment extends Fragment {
private ListViewModel viewModel;

@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    viewModel = new ViewModelProvider(requireActivity()).get(ListViewModel.class);
    viewModel.getFilteredList().observe(getViewLifecycleOwner(), list -> {
        // Update the list UI.
    });
}
}

public class FilterFragment extends Fragment {
private ListViewModel viewModel;

@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
    viewModel = new ViewModelProvider(requireActivity()).get(ListViewModel.class);
    viewModel.getFilters().observe(getViewLifecycleOwner(), set -> {
        // Update the selected filters UI.
    });
}

public void onFilterSelected(Filter filter) {
    viewModel.addFilter(filter);
}

public void onFilterDeselected(Filter filter) {
    viewModel.removeFilter(filter);
}
}

Both fragments use their host activity as the scope for the ViewModelProvider. Because the fragments use the same scope, they receive the same instance of the ViewModel, which enables them to communicate back and forth.