I have background service which started on device boot . I want to get some data from that service in my activity .
I want the data, only when my activity start. so the basic requirement is that when my activity start it make a connection with the background service and get the data from this service and when activity stop then disconnect from the service.
You need to use bindService() to bind with running service and communicate with it.
Reference : http://developer.android.com/guide/components/bound-services.html
For example (from Android Docs),
public class BindingActivity extends Activity {
YourService mService;
boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onStart() {
super.onStart();
// Bind to Your Service
Intent intent = new Intent(this, YourService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from your Service.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to the running Service, cast the IBinder and get instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
In your service,
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
Basically, you should use bindService() in your activity onStart() and unbindService() in onStop()
Related
In this, the service is been create repeated times but I need to get the instance of running service so that I can start the timer task. The object of this service can get from any activity. The basic aim is to start the timer task after the particular button click.
public class MainActivity extends Activity {
MyService mService;
boolean mBound = false;
int b=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_start_timer).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mBound) {
mService.runTimerTask(++b);
}
}
});
}
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, MyService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
unbindService(mConnection);
mBound = false;
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
MyService.LocalBinder binder = (MyService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
You could create a ServiceManager class and route all methods through that and store it in the application:
public class YourApplication extends Application {
...
private ServiceManager serviceManager = ...;
public ServiceManager getServiceManager() {
return serviceManager;
}
}
In MainActivity:
ServiceManager serviceManager = ((YourApplication)getApplication()).getServiceManager();
MyService runningService = serviceManager.getRunningService();
The ServiceManager would handle unbinding etc and all methods that involve the state of the service. So you just ask the ServiceManager for the running service. Where you have ServiceConnection::onServiceConnected doing the work, delegate that work to the ServiceManager so it can keep state and share it with the rest of the application:
public void onServiceConnected(ComponentName className,
IBinder service) {
((YourApplication)getApplication()).getServiceManager().bind(service);
}
It's a general technique for sharing object state across an application but you'd need to tailor it to fit.
I'm developing an application, which plays music in the background by using service.
Music stops when we hit back app will be paused and but, music is not resuming when I get back to the application.
public class backService extends Service implements ComponentCallbacks2 {
private MediaPlayer mp;
SharedPreferences sharedpreferences;
public Boolean musicSwitch;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
if (mp != null){
mp.stop();
mp.release();
}
}
#Override
public void onCreate() {
super.onCreate();
sharedpreferences = getSharedPreferences(mypreference,
Context.MODE_PRIVATE);
musicSwitch = sharedpreferences.getBoolean("music", true);
if(musicSwitch){
mp = MediaPlayer.create(this, R.raw.all);
mp.setLooping(true);
mp.start();
}
}
#Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
if(mp != null){
mp.pause();
}
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
I want the application to resume music when we get back to the application, I have tried using onResume method, but there is no onResume method in services.
TIA
1) You need to create foreground service to prevent it from killing by OS
How can we prevent a Service from being killed by OS?
2) You can bind service (bindService(serviceIntent)) and use Binder interface
https://developer.android.com/guide/components/bound-services.html#Binder
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
Activity:
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
unbindService(mConnection);
mBound = false;
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
}
}
3) Then, in your activity onResume you can call method from your Binder to control music
I launch my app, the start is called, do the bind service and trigger the onServiceConnected. Everything is ok.
But...
When I press back, onStop is called, my bound var is true as excpected but the onServiceDisconnected is never called...
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart()
{
Log.e("START", "START");
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocationService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop()
{
Log.e("STOP", "STOP");
super.onStop();
// Unbind from the service
if (mBound)
{
this.unbindService(mConnection);
mBound = false;
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection()
{
#Override
public void onServiceConnected(ComponentName className, IBinder service)
{
Log.e("ON SERVICE START", "ON SERVICE START");
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocationService.LocationBinder binder = (LocationService.LocationBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0)
{
Log.e("ON SERVICE END", "ON SERVICE END");
mBound = false;
}
};
And my service
// Binder given to clients
private final IBinder mBinder = new LocationBinder();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocationBinder extends Binder
{
public LocationService getService()
{
// Return this instance of LocationService so clients can call public methods
return LocationService.this;
}
}
#Override
public IBinder onBind(final Intent intent)
{
Log.e("onBind", "onBind onBind onBind onBind onBind onBind");
return mBinder;
}
/** method for clients */
public int getRandomNumber()
{
return new Random().nextInt(100);
}
Every call to bindService() should be paired with a call to unbindService(). It actually doesn't matter if the binding worked or not. The point is to let Android know that you no longer want the connection to be active. Android will take care of the details of determining if the connection is currently bound and active and taking the appropriate action.
Bottom line is that you should not conditionally call unbindService() here. Simply always call it in onStop() with the same ServiceConnection that you used when calling bindService() in onStart().
I'm implementing Service that establishes TCP connection with server and then allows clients to pass messages through this connection. Clients connect to service with bindService call. As a result onServiceConnected called in clients ServiceConnection object. The problem is that onServiceConnected called right after return from bindService, but my Service was not established connection with server at this moment. Can I somehow delay onServiceConnected call while connection was not established? If it is not possible please suggest some good pattern for my case. Thank you.
You should do it as follows:
Service code:
class MyService implements Service {
private boolean mIsConnectionEstablished = false;
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
public MyService getService() {
// Return this instance of LocalService so clients can call public
// methods
return MyService.this;
}
}
public interface OnConnectionEstablishedListener {
public void onConnectionEstablished();
}
private OnConnectionEstablishedListener mListener;
#Override
public void onCreate() {
super.onCreate();
new Thread( new Runnable() {
#Override
void run() {
//Connect to the server here
notifyConnectionEstablished();
}
}).start();
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private void notifyConnectionEstablished() {
mIsConnectionEstablished = true;
if(mListener != null) {
mListener.onConnectionEstablished();
}
}
public void setOnConnectionEstablishedListener(
OnConnectionEstablishedListener listener) {
mListener = listener
// Already connected to server. Notify immediately.
if(mIsConnectionEstablished) {
mListener.onConnectionEstablished();
}
}
}
Activity code:
class MyActivity extends Activity implements ServiceConnection,
OnConnectionEstablishedListener {
private MyService mService;
private boolean mBound;
#Override
public void onCreate() {
super.onCreate();
//bind the service here
Intent intent = new Intent(this, MyService.class);
bindService(intent, this, BIND_AUTO_CREATE);
}
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
mService.setOnConnectionEstablishedListener(this);
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
#Override
public void onConnectionEstablished() {
// At this point the service has been bound and connected to the server
// Do stuff here
// Note: This method is called from a non-UI thread.
}
}
Ok, I'm new to android development and am trying to bind to a service so that I can call methods on the service once it's been started. The Activity and Service described below are both part of the same application so there shouldn't be any problems there, but everytime I run my app I get the following error:
java.lang.ClassCastException: android.os.BinderProxy
The line this happens on is:
LocalBinder binder = (LocalBinder) service;
My Activity code (simplified is):
public class Main extends Activity {
boolean gpsBound = false;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
/** Called whenever the activity is started. */
#Override
protected void onStart() {
super.onStart();
// Bind to GPSService
Intent i = new Intent(this, GPSService.class);
startService(i);
bindService(i, connection, Context.BIND_AUTO_CREATE);
}
/** service binding */
private ServiceConnection connection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// After binding to GPSService get the instance of it returned by IBinder
LocalBinder binder = (LocalBinder) service;
gpsBound = true;
}
public void onServiceDisconnected(ComponentName className) {
gpsBound = false;
}
};
}
Service:
public class GPSService extends Service {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public IBinder onBind(Intent i) {
// TODO Auto-generated method stub
return new LocalBinder<GPSService>(this);
}
/**
* Our implementation of LocationListener that handles updates given to us
* by the LocationManager.
*/
public class CustomLocationListener implements LocationListener {
DBHelper db;
CustomLocationListener() {
super();
}
// Overridden methods here...
}
}
And finally my LocalBinder:
/**
* A generic implementation of Binder to be used for local services
* #author Geoff Bruckner 12th December 2009
*
* #param <S> The type of the service being bound
*/
public class LocalBinder<S> extends Binder {
private String TAG = "LocalGPSBinder";
private WeakReference<S> mService;
public LocalBinder(S service){
mService = new WeakReference<S>(service);
}
public S getService() {
return mService.get();
}
}
I understand the meaning of the ClassCast Exception but cannot understand what to do! I've followed the example in the google documentation but it's still not working. Can anyone shed any light on what might be causing this?
Thanks in advance!
Delete attribute process in your AndroidManifest.xml of your service.
Had same error. I had added the android:process=":process_description" attribute in the manifest. When you add it, your service is created as separate process and hence you get instance of binderProxy (Hence the class cast exception)
If you are trying to bind to a local service than yes, you can just cast it. However if you are trying to bind to a remote (separate process) service you must use the AIDL method as prescribed in this article.
http://developer.android.com/guide/components/aidl.html
the LocalBinder passed in onServiceConnected has a generic type argument, while your local variable LocalBinder binder does not have one.
Resolve this one way or another, either by removing the generic type from the definition of LocalBinder, or by adding one to your declaration of your local variable binder in onServiceConnected
class MyBoundService extends Service{
private final IBinder mBinder = new MyBinder();
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class MyBinder extends Binder{
public void doStuff(){
//Stuff
}
//More Binder Methods
}
}
class MyActivity extends Activity{
private MyBinder mBinder;
#Override
protected void onStart(){
Intent intent = new Intent(this, MyBoundService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop(){
unbindService(mConnection);
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
mBinder = (TaskBinder) service;
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
private void doStuff(){
if (mBound)
mBinder.doStuff();
}
}
No real need to fiddle around with weak references and whatnot. just be sure to unbind (I didn't in the sample)
If you want to invoke service methods ASAP, just put calls in onServiceConnected, after you set mBinder. otherwise, just invoke from other callbacks (onClick events and whatnot).