Showing posts with label Android Services Unbound and Bound Tutorial. Show all posts
Showing posts with label Android Services Unbound and Bound Tutorial. Show all posts

Thursday, June 6, 2013

Android Services Unbound and Bound Tutorial


Android Services Unbound and Bound Tutorial

             Service is one of the four application component long with  Activities,Broadcast Receiver and content provider  are the building blocks for an application.The service component can be chosen to be used in an application which require performing  a longer-running operation while not interacting with the user.Eg:on Playing Mp3 player once it is started it will play music  (such as MP3 playback) or networking operations such as downloading apps from app market  these applications do not need user interaction but CPU intensive long running task.
        A Service is neither  a separate process  nor  a thread,but it  runs in its own main thread.A service  started by the application component t will continue to run in the background even if the user switches to another application(remember application process  in which service runs is still running only the component ( an activity) which might be killed).
                  A service component can be started by another component Activity,another service or Broadcast receiver which may be in the same or different process..There are two types of service 
    1.Local Service 2.Remote Service
                 Local service can only run in the same process and remote service can be called and  run in different process i.e different application can access a remote service that is running on the different application but  a local service cannot called  that is running in a different application.

  Services have a lifecycle that is separate from that of the component, such as an Activity, that starts them. This autonomy allows a service to continue running even after the starting component is no longer alive
The figure above shows a variety of methods that are called at different points in the lifecycle of a service. The following list describes each of them:
  • OnCreate – Called one time when the service is first started.initialization code should be implemented. such as preparing Media player or connecting to network or database etc.
  • OnStartCommand – Called for each request to start the service, either as a result of a call to StartService or a restart by the system. This is where the service can begin any long-running task. The method returns a StartCommmandResult value that indicates how or if the system should handle restarting the service after a shutdown due to low memory. This value is of type StartCommandResult, which can be any of the following:
    • Sticky – A sticky service will be restarted, and a null intent will be delivered to OnStartCommand at restart. Used when the service is continuously performing a long-running operation, such as updating a stock feed.
    • RedeliverIntent – The service is restarted, and the last intent that was delivered to OnStartCommand before the service was stopped by the system is redelivered. Used to continue a long-running command, such as the completion of a large file upload.
    • NotSticky – The service is not automatically restarted.
    • StickyCompatibility – Restart will behave like Sticky on API level 5 or greater, but will downgrade to pre-level 5 behavior on earlier versions.
     his call takes place on the main thread.
  • OnDestroy – Called after the service receives a StopSelf or StopService call. This is where service-wide cleanup can be performed such as realesing resources
Services can also communicate with the other components through an interface called binding.Bound service can  interacted with Activities so that activity can control the running service. Eg Pause an Audio player running a music in background as service.The Activity can call the bound service method to control the operation of the service.
The lifecycle of a Bound Service is different from that of a Started Service. Unlike Started Services, Bound Services do not run indefinitely. Instead, they are created when a client connects to them and are destroyed after all bound clients have disconnected. However, a Bound Service can be implemented in the same Service subclass as a Started Service, so if it has been started with a StartService call, it will not be destroyed even after all bound clients have disconnected. Likewise a StartedService will not be destroyed after a call to StopService or StopSelf, if it still has bound clients connected.
The following diagram illustrates the lifecycle of a Bound Service:
  • OnBind – This method is used to return an instance on an IBinder that the client uses to obtain a service instance that can, in turn, call methods on the service.
  • OnUnbind – This method is called when all bound clients have unbound. By returning true from this method, the service will later call OnRebind with the intent passed to OnUnbind when new clients bind to it. You would do this when a service continues running after it has been unbound. This would happen if the recently unbound service were also a started service, and StopService or StopSelf hadn’t been called. In such a scenario, OnRebind allows the intent to be retrieved. The default returns false, which does nothing.  
1.Create  Android project with details as listed in the table below.
Property name
Property value
Project name
SRM_ServiceTutorial
Package name
in.ac.srmuniv.services
Activity name
MainActivity
Layout xml name
main
    
 2. Create the Service UnboundedAudioService.java.Code listing given below

packagein.ac.srmuniv.services;

import android.app.Service;
importandroid.content.Intent;
importandroid.media.MediaPlayer;
import android.os.IBinder;
import android.util.Log;

public classUnboundedAudioPlayerService extends Service{
    private static final String LOGCAT = null;
    MediaPlayer AudioPlayer;

    public void onCreate(){
        super.onCreate();
        Log.d(LOGCAT, "Service Started!");
        AudioPlayer = MediaPlayer.create(this,R.raw.krtheme);
    }

    public intonStartCommand(Intent intent, int flags, int startId){
        AudioPlayer.start();
        Log.d(LOGCAT, "Media Player started!");
        if(AudioPlayer.isLooping() != true){
            Log.d(LOGCAT, "Error in Playing Audio");
        }
        return START_STICKY;
    }

    public void onStop(){
        AudioPlayer.stop();
        AudioPlayer.release();
    }

    public void onPause(){
        AudioPlayer.stop();
        AudioPlayer.release();
    }
    public void onDestroy(){
        AudioPlayer.stop();
        AudioPlayer.release();
    }
    @Override
    public IBinder onBind(Intent Audioindent) {
        return null;
    }
}
3.Copy the code  to the file main.xml in res/layout folder 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
> 
<ImageButton
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_marginRight="35dp"
    android:layout_marginTop="43dp"
    android:layout_toLeftOf="@+id/button2"
    android:onClick="playAudio"
    android:background="@drawable/play" />

<TextView
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@+id/button2"
    android:layout_alignLeft="@+id/button1"
    android:text="Audio Player"
    android:textAppearance="?android:attr/textAppearanceLarge" />

<ImageButton
    android:id="@+id/button2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_alignTop="@+id/button1"
    android:layout_marginRight="116dp"
    android:onClick="stopAudio"
    android:background="@drawable/stop" />

</RelativeLayout>
4.Copy the code in Mainactivity.java. Activity.                                           
package in.ac.srmuniv.activities;
import android.os.Bundle;
importandroid.app.Activity;
import android.view.Menu;
import android.view.View;
import android.content.Intent;

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    public booleanonCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    public void playAudio(View view) {
        Intent serviceIntent = new Intent(thisUnboundedAudioPlayerService.class);
        startService(serviceIntent);
    }

    public void stopAudio(View view) {
        Intent serviceIntent = new Intent(thisUnboundedAudioPlayerService.class);
        stopService(serviceIntent);   
    }

5.Modify the Androidmanifest.xml
<?xml version="1.0"encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="in.ac.srmuniv.activities"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
android:name="in.ac.srmuniv.activities.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
<service android:name="in.ac.srmuniv.services.UnboundedAudioPlayerService"  android:enabled="true">
</service>
    </application>

</manifest>


CODE EXPLANATION
             The onCreate() method is called  when startservice() is called for the first time The method do   the initialization work such as calling  MediaPlayer.create() method is used to change  the state of the MediaPlayer instance from idle to prepared state.
Next the onStartCommand() command is used to start the media player. This method will be invoked when the startService method is called from other application component. Here an activity is used to trigger the service and also to stop the running services..onBind() method is overridden in the service  class. If the service is bounded with any other component, then this method will return corresponding parameter. Otherwise, it will return null value.
MainActivity has  two buttons defined in   layout. These buttons are named as play and stop to start the background music and to stop respectively. In the onClick event of these button refer the event handling methods named startAudio and stopAudio. These Event handlers are defined with the corresponding java class associated with the activity component. The startService() and stopService() are invoked from those handler to work with the services call back methods. 
1.Create  Android project with details as listed in the table below.
Property name
Property value
Project name
SRM_ServiceTutorial
Package name
in.ac.srmuniv.activities
Activity name
MainActivity
Layout xml name
main
2. Create the  Service BoundedAudioService.java.Code listing given below   
package in.ac.srmuniv.services;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class BoundedAudioPlayerService extends Service{

        private static final String LOGCAT = null;
        MediaPlayer AudioPlayer;

        public void onCreate(){
            super.onCreate();
            Log.d(LOGCAT"Service Started!");
            AudioPlayer = MediaPlayer.create(this,R.raw.krtheme);
        }

        public int onStartCommand(Intent intent, int flags, int startId){
            AudioPlayer.start();
            Log.d(LOGCAT"Media Player started!");
            if(AudioPlayer.isLooping() != true){
                Log.d(LOGCAT"Problem in Playing Audio");
            }
            return START_STICKY;
        }

       
        public void onDestroy(){
            AudioPlayer.stop();
            AudioPlayer.release();
        }
        public class MyLocalBinder extends Binder {
            BoundedAudioPlayerService getService() {
                return BoundedAudioPlayerService.this;
            }
        }
        private final IBinder myBinder = new MyLocalBinder();
       
        @Override
        public IBinder onBind(Intent arg0) {
            // TODO Auto-generated method stub
            return myBinder;
        }
        public void plauseAudio() {
            if(AudioPlayer.isPlaying())
                  AudioPlayer.pause(); 
           
        }
    }
  3.Copy the code  to the file main.xml in res/layout folder 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
> 

<ImageButton
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_marginRight="35dp"
    android:layout_marginTop="43dp"
    android:layout_toLeftOf="@+id/button2"
    android:onClick="playAudio"
    android:background="@drawable/play" />

<TextView
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@+id/button2"
    android:layout_alignLeft="@+id/button1"
    android:text="Audio Player"
    android:textAppearance="?android:attr/textAppearanceLarge" />


<ImageButton                             
    android:id="@+id/button2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_alignTop="@+id/button1"
    android:layout_marginRight="116dp"
    android:onClick="stopAudio"
    android:background="@drawable/stop" />

</RelativeLayout>
 4.Copy the code in MainActivity.java. Activity.
packagein.ac.srmuniv.activities;

import in.ac.srmuniv.services.BoundedAudioPlayerService.MyLocalBinder;
import android.os.Bundle;
import android.os.IBinder;
importandroid.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
importandroid.widget.ImageButton;
importandroid.content.ComponentName;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.content.ServiceConnection;

public class MainActivity extends Activity {
    BoundedAudioPlayerService myService;
    private boolean isBound;
    ImageButton btn;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btn=(ImageButton)findViewById(R.id.button1);
        isBound=false;
       
    }

    @Override
    public booleanonCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    public void playAudio(View view) {
        Intent objIntent = new Intent(this,  BoundedAudioPlayerService.class);
        if(!isBound)
        {
        bindService(objIntent, myConnection, Context.BIND_AUTO_CREATE);
        isBound=true;
        btn.setBackgroundResource(R.drawable.pause);//setText("Pause");
        startService(objIntent);
        }
        else
        {
            myService.plauseAudio();
            btn.setBackgroundResource(R.drawable.play);
            isBound=false;
            unbindService(myConnection);
        }
               
    }

    public void stopAudio(View view) {
        Intent objIntent = new Intent(this, BoundedAudioPlayerService.class);
        if(isBound)
        {
            isBound=false;
        unbindService(myConnection);   
        stopService(objIntent);
       
        }
        else
            stopService(objIntent);
        btn.setBackgroundResource(R.drawable.play);
    }
    private ServiceConnection myConnection = new ServiceConnection() {

       

        public voidonServiceConnected(ComponentName className,
                IBinder service) {
            myService = ((BoundedAudioPlayerService.MyLocalBinder) service).getService();
            isBound = true;
        }
       
        public voidonServiceDisconnected(ComponentName arg0) {
            isBound = false;
        }
       
       };
      
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (isBound) {
                // Disconnect from an application service. You will no longer
                // receive calls as the service is restarted, and the service is
                // now allowed to stop at any time.
                unbindService(myConnection);
                isBound = false;
            }
        }

}
                                                
5.Modify the Androidmanifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="in.ac.srmuniv.activities"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
android:name="in.ac.srmuniv.activities.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
<service  
android:name="in.ac.srmuniv.services.BoundedAudioPlayerService" 
android:enabled="true">
</service>
    </application>

</manifest>
6.Run the application in the emulator. 




Code Explanation
           Here  the bound service is local and private to the same application as the client component ( it runs within the same process and is not available to components in other applications), the recommended mechanism is to create a subclass of the Binder class and extend it to provide an interface to the service.Here we use MyLocalBinder inner class which extends Binder class. An instance of this Binder object is then returned by the onBind() method and subsequently used by the client component to directly access methods and data held within the service.
In situations where the bound service is not local to the application (it is running in a different process from the client component), interaction is best achieved using a Messenger/Handler implementation.
The purpose of the bound service is to obtain the pauseAudio() method in the service which will pause the audio player . The bound service will be local and private to the same application as the activity.
in order to successfully bind to a service and receive the IBinder object returned by the service’s onBind() method, it is necessary to create a ServiceConnection subclass and implement onServiceConnected() and onServiceDisconnected() callback methods.
      In our example on binding an instance of BoundedAudioPlayerService is created by getService() method.by using the instance of the service class public method pauseAudio() is called to pause the AudioPlayer.Thus our MainActivity is able to have(IPC)inter process communication with BoundedAudioPlayerService service component