13

I have the folowing method in a Service in my appplication:

public void switchSpeaker(boolean speakerFlag){

        if(speakerFlag){
        audio_service.setSpeakerphoneOn(false);
        }
        else{
        audio_service.setSpeakerphoneOn(true);
        }

    }

So my question is whats the best and most effective way to be able to use this method in an Activity like follows

final Button speaker_Button = (Button) findViewById(R.id.widget36);

            speaker_Button.setOnClickListener(new View.OnClickListener(){
                public void onClick(View v){

                    switchSpeaker(true); //method from Service

                }

            });

Do I have to do an AIDL or is there a simpler way?

Donal Rafferty
  • 19,707
  • 39
  • 114
  • 191

3 Answers3

71

There are 3 ways to binding service with your activity.

  1. IBinder Implementation
  2. Using Messanger
  3. Using AIDL

Among these IBinder Implementation is the best suit in your case

Example of IBinder class

1. Server.java Service

public class Server extends Service{

    IBinder mBinder = new LocalBinder();


    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    public class LocalBinder extends Binder {
        public Server getServerInstance() {
            return Server.this;
        }
    }

    public void switchSpeaker(boolean speakerFlag){

        if(speakerFlag){
        audio_service.setSpeakerphoneOn(false);
        }
        else{
        audio_service.setSpeakerphoneOn(true);
        }

    }
}

2. Client.java Activity

public class Client extends Activity {

boolean mBounded;
Server mServer;
TextView text;
Button button;

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

text = (TextView)findViewById(R.id.text);
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {
            mServer.switchSpeaker(true);
        }
    });

}

@Override
protected void onStart() {
    super.onStart();
    Intent mIntent = new Intent(this, Server.class);
bindService(mIntent, mConnection, BIND_AUTO_CREATE);
};

ServiceConnection mConnection = new ServiceConnection() {

    public void onServiceDisconnected(ComponentName name) {
        Toast.makeText(Client.this, "Service is disconnected", 1000).show();
        mBounded = false;
        mServer = null;
    }

    public void onServiceConnected(ComponentName name, IBinder service) {
        Toast.makeText(Client.this, "Service is connected", 1000).show();
        mBounded = true;
        LocalBinder mLocalBinder = (LocalBinder)service;
        mServer = mLocalBinder.getServerInstance();
    }
};

@Override
protected void onStop() {
    super.onStop();
    if(mBounded) {
        unbindService(mConnection);
        mBounded = false;
    }
};
}

Example of Messanger class

1. Server.java service

public class Server extends Service{

    Messenger messenger = new Messenger(new LocalHandler());
    Messenger clientMessenger;
    static final int SysterTime = 0;
    static final int AddHandler = 1;
    List<Handler> mHandlers;

    @Override
    public void onCreate() {
        super.onCreate();
        mHandlers = new ArrayList<Handler>();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }

    public class LocalHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case SysterTime:
                SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                try {
                    clientMessenger.send(Message.obtain(null, SysterTime, mDateFormat.format(new Date())));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;

            case AddHandler:
                clientMessenger = new Messenger((Handler) msg.obj);
                try {
                    clientMessenger.send(Message.obtain(null, AddHandler, "Registed messanger"));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;

            default:
                break;
            }
            super.handleMessage(msg);
        }
    }
}

2. Client.java Activity

public class Client extends Activity {

    Messenger messenger;
    boolean mBounded;
    TextView text;
    Button button;
    Button register;


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

        text = (TextView)findViewById(R.id.text);
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                Message message = Message.obtain(null, Server.SysterTime, null);
                try {
                    messenger.send(message);
                } catch (RemoteException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        register = (Button) findViewById(R.id.register);
        register.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                Message message = Message.obtain(null, Server.AddHandler, new ClientHandle());
                try {
                    messenger.send(message);
                } catch (RemoteException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

    }


    public class ClientHandle extends Handler {

        @Override
        public void handleMessage(Message msg) {

            switch (msg.what) {
            case Server.SysterTime:
                text.setText(msg.obj.toString());
                break;

            case Server.AddHandler:
                text.setText(msg.obj.toString());
                break;

            default:
                break;
            }

            super.handleMessage(msg);
        }


    }

    @Override
    protected void onStart() {
        super.onStart();

        bindService(new Intent(this, Server.class), mConnection, BIND_AUTO_CREATE);
    }



    @Override
    protected void onStop() {
        super.onStop();
        if(mBounded) {
            unbindService(mConnection);
        }
    }



    ServiceConnection mConnection = new ServiceConnection() {

        public void onServiceDisconnected(ComponentName name) {
            mBounded = false;
            messenger = null;
        }

        public void onServiceConnected(ComponentName name, IBinder service) {
            Toast.makeText(Client.this, "Service is connected", 1000).show();
            messenger = new Messenger(service);
            mBounded = true;
        }
    };
}

Example of AIDL

1. IRemoteService.aidl

package com.example.bindservice.aidl;

interface IRemoteService {

    String getMessage(String msg);
}

2. Server.java Service

public class Server extends Service{

    @Override
    public IBinder onBind(Intent intent) {
        return mStub;
    }

    IRemoteService.Stub mStub = new IRemoteService.Stub() {

        public String getMessage(String msg) throws RemoteException {
            return msg;
        }
    };
}

3. Client.java Activity

public class Client extends Activity {

    Button button;
    TextView text;
    boolean mBound;
    IRemoteService mIRemoteService;
    EditText etMsg;

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

        text = (TextView)findViewById(R.id.text);
        button = (Button) findViewById(R.id.button);
        etMsg = (EditText)findViewById(R.id.etMsg);
        button.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                if(mBound) {
                    try {
                        text.setText(mIRemoteService.getMessage(etMsg.getText().toString()));
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }                   
                }
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        bindService(new Intent(Client.this, Server.class), mConnection, BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if(mBound) {
            unbindService(mConnection);
            mBound = false; 
        }
    }

    ServiceConnection mConnection = new ServiceConnection() {

        public void onServiceDisconnected(ComponentName name) {
            mIRemoteService = null;
            mBound = false;
        }

        public void onServiceConnected(ComponentName name, IBinder service) {
            mIRemoteService = IRemoteService.Stub.asInterface(service);
            mBound = true;
        }
    };
}

For more study you can refer this document

Dharmendra
  • 33,296
  • 22
  • 86
  • 129
3

You have to expose service`s switchSpeaker method for clients. Define your .aidl file. Than bind to that service from your activity and simply call switchSpeaker. See documentation

No other simple way to call this method, only if it static)

ponkin
  • 2,363
  • 18
  • 25
  • 1
    For .aidl we have to handle multi-threading and so this is not a proper way to implement the aidl to use a local service. Instead of it there are two other option that we can use and those are Using IBinder and Using Messanger. IBinder will be best if there is a local service binding with the activity. – Dharmendra May 29 '12 at 12:55
  • 1
    link is broken :p @ponkin – Pankaj Jun 04 '15 at 13:06
3

It's public, right :)

You can call bindService(Intent) method. Tale a look at ApiDemos, the class LocalServiceBinding.

In the callback method onServiceConnected, you can see:

    public void onServiceConnected(ComponentName className, IBinder service) {
        // This is called when the connection with the service has been
        // established, giving us the service object we can use to
        // interact with the service.  Because we have bound to a explicit
        // service that we know is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        mBoundService = ((LocalService.LocalBinder)service).getService();

        // Tell the user about this for our demo.
        Toast.makeText(LocalServiceBinding.this, R.string.local_service_connected,
                Toast.LENGTH_SHORT).show();
    }

Now, use the service object (mBoundService) to call the method.

That's all :)

Binh Tran
  • 2,478
  • 1
  • 21
  • 18
  • but then it will become a bounded service and i will not be able to use it even after the activity component gets destroyed..any other way ? – Kaveesh Kanwal Sep 12 '16 at 06:20
  • If you want the service to stay running in the background when the activity gets destroyed then you can just start service normally without binding it to your activity. Then to call the method from the service, instead of call directly, you can call startService with Intent has a predefined action or extra data, whether the service is already running or not, it onStartCommand method will be invoked --> check the intent and call the method you want if the intent matches. The key difference here is this call is asynchronous and you can not get method result directly. – Binh Tran Sep 12 '16 at 09:11