Bound Services on Android

By CodingWithMitch

Share:

Key Concepts

  • Bound Services: Services that allow components (e.g., activities, fragments) to bind to them and interact with them.
  • Started Services: Services started by calling startService or startForegroundService. A bound service can also be a started service.
  • Client-Server Interaction: Bound services facilitate a client-server interaction, where the service acts as the server and the binding component acts as the client.
  • IBinder Interface: The base interface for a remoteable object, used to provide an access point for retrieving a service instance.
  • ServiceConnection Object: Responsible for facilitating the connection between the service and the client.
  • onBind() Method: Required method in a service that returns an IBinder object.
  • onTaskRemoved() Method: Called when the application is removed from the recently used applications list.
  • Model-View-ViewModel (MVVM): An architectural design pattern used in the demo application.
  • MutableLiveData & LiveData: MVVM components for observable data. MutableLiveData allows setting values, while LiveData only allows observation.
  • Handler & Runnable: Used to simulate long-running tasks in the background.
  • startForegroundService(): Method to start a service that runs indefinitely and displays a notification (required in Android O and above).

Bound Services vs. Started Services

  • Started Service: Initiated by calling startService or startForegroundService.
  • Bound Service: Initiated by a component binding to it, or by calling startService and then binding.
  • Key Difference: A started service continues to run even if all clients unbind, while a bound service started solely by binding will stop when all clients unbind.

When to Use Bound Services

  • When consistent or frequent communication is needed between a component (activity, fragment) and the service.
  • Example: Streaming music, where playback progress needs to be constantly sent to the activity.

Application Demo: Long-Running Task Simulation

Overview

  • The demo app simulates a long-running task in a background service.
  • The UI includes a progress bar, a text view (displaying progress percentage), and a button (start/pause/restart).
  • The app uses MVVM architecture.

Implementation Details

  1. Service Class (MyService):

    • Extends Service.
    • Implements onBind() to return a custom IBinder implementation (MyBinder).
    • MyBinder provides a getService() method to return an instance of MyService.
    • Uses a Handler and Runnable to simulate a long-running task by incrementing an integer value (mProgress).
    • startPretendLongRunningTask(): Starts the runnable, incrementing mProgress every 100 milliseconds.
    • pausePretendLongRunningTask(): Sets mIsPaused to true, pausing the runnable.
    • unpausePretendLongRunningTask(): Sets mIsPaused to false, resuming the runnable.
    • getIsPaused(), getProgress(), getMaxValue(), resetTask(): Methods to retrieve service state.
    • onTaskRemoved(): Calls stopSelf() to stop the service when the app is removed from the recent tasks list.
  2. View Model Class (MainActivityViewModel):

    • Extends ViewModel.
    • Contains MutableLiveData objects for mIsProgressUpdating (boolean) and mBinder (MyService.MyBinder).
    • Provides LiveData getters for isProgressUpdating and binder.
    • ServiceConnection object: Handles the connection and disconnection events.
      • onServiceConnected(): Called when the service is connected. Retrieves the IBinder and posts it to the mBinder LiveData.
      • onServiceDisconnected(): Called when the service is disconnected. Sets the mBinder LiveData to null.
    • getServiceConnection(): Returns the ServiceConnection object.
    • setIsUpdating(): Sets the value of mIsProgressUpdating.
  3. Main Activity (MainActivity):

    • Binds to the service in onResume() using bindService().
    • Starts the service in onResume() using startService().
    • Unbinds from the service in onPause() using unbindService().
    • Observes the binder LiveData in the ViewModel to get a reference to the MyService instance.
    • toggleUpdates(): Starts, pauses, or restarts the long-running task in the service based on the current state.
    • Observes the isProgressUpdating LiveData in the ViewModel to update the UI (button text, progress bar, text view).
    • Uses a Handler and Runnable to periodically update the UI with the progress from the service.

Step-by-Step Process

  1. Service Creation: The MyService class is created, extending the Service class.
  2. Binder Implementation: A custom IBinder class (MyBinder) is created within MyService to provide access to the service instance.
  3. Service Registration: The service is registered in the AndroidManifest.xml file.
  4. View Model Setup: The MainActivityViewModel class is created, extending the ViewModel class.
  5. Service Connection: A ServiceConnection object is created in the MainActivityViewModel to handle connection and disconnection events.
  6. Binding and Starting: In MainActivity, the service is started and bound in the onResume() method.
  7. Unbinding: In MainActivity, the service is unbound in the onPause() method.
  8. Observing Changes: The MainActivity observes the binder and isProgressUpdating LiveData objects in the MainActivityViewModel to update the UI.
  9. Task Management: The toggleUpdates() method in MainActivity controls the starting, pausing, and restarting of the long-running task in the service.
  10. UI Updates: A Handler and Runnable are used in MainActivity to periodically update the UI with the progress from the service.
  11. Task Removal Handling: The onTaskRemoved() method in MyService stops the service when the app is removed from the recent tasks list.

Code Snippets

  • Starting the service and binding (MainActivity - onResume):

    Intent serviceIntent = new Intent(this, MyService.class);
    startService(serviceIntent);
    bindService(serviceIntent, mViewModel.getServiceConnection(), BIND_AUTO_CREATE);
    
  • Unbinding the service (MainActivity - onPause):

    if (mViewModel.getBinder().getValue() != null) {
        unbindService(mViewModel.getServiceConnection());
    }
    
  • Getting service instance (MainActivity - Observer):

    mViewModel.getBinder().observe(this, new Observer<MyService.MyBinder>() {
        @Override
        public void onChanged(@Nullable MyService.MyBinder myBinder) {
            if (myBinder != null) {
                mService = myBinder.getService();
            } else {
                mService = null;
            }
        }
    });
    
  • Simulating long running task (MyService):

    private void startPretendLongRunningTask(){
        final Runnable runnable = new Runnable() {
            @Override
            public void run() {
                if(mProgress >= mMaxValue || mIsPaused){
                    Log.d(TAG, "run: removing callbacks");
                    mHandler.removeCallbacks(this);
                    pausePretendLongRunningTask();
                }
                else{
                    Log.d(TAG, "run: progress: " + mProgress);
                    mProgress += 100;
                    mHandler.postDelayed(runnable, 100);
                }
            }
        };
    
        mHandler.postDelayed(runnable, 100);
    }
    

Key Arguments and Perspectives

  • Services run on the main thread by default: It's a common misconception that services run on a background thread.
  • MVVM advantages: MVVM helps maintain UI state across app lifecycle events.

Notable Quotes

  • "A service is an application component that can perform long-running operations in the background with no user interface."
  • "Technically a bound service can also be a started service, but a started service cannot be a bound service."

Technical Terms and Concepts

  • Service Lifecycle: The lifecycle of a service is independent of the activity or fragment that creates it.
  • BIND_AUTO_CREATE: A flag used with bindService() that creates the service if it's not already running.
  • stopSelf(): A method called within a service to stop itself.
  • postValue(): A method of MutableLiveData used to post a value to the main thread.
  • observe(): A method of LiveData used to observe changes to the data.

Logical Connections

  • The video starts with an overview of services and then narrows down to bound services.
  • The explanation of bound services is followed by a practical demonstration using MVVM.
  • The demo is broken down into smaller, manageable parts (service, view model, activity).
  • The code is explained step-by-step, with clear explanations of the purpose of each component.

Data, Research Findings, or Statistics

  • No specific data, research findings, or statistics are mentioned in the transcript.

Synthesis/Conclusion

The video provides a comprehensive guide to using bound services in Android, emphasizing their role in facilitating communication between components. It highlights the importance of understanding the service lifecycle and the distinction between bound and started services. The demo application showcases a practical implementation of a bound service using the MVVM architectural pattern, demonstrating how to manage long-running tasks and update the UI accordingly. The video also stresses the importance of properly handling the onTaskRemoved() method to prevent services from running indefinitely in the background. The use of MVVM is presented as a key advantage for maintaining UI state and improving the overall user experience.

Chat with this Video

AI-Powered

Load the transcript when you're ready to chat so the initial page stays lighter.

Related Videos

Ready to summarize another video?

Summarize YouTube Video