How to keep a local service running in between tabs? - android

I am currently working on a Pedometer application. At first, I started with one activity, the PedometerActivity. This activity started the service that is supposed to run in the background, and binds to it. The code is long so I'll just give sections of what I think will help in my question.
//Bind service
private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
//binder to communicate with the service
PedometerService.PedometerBinder mBinder = (PedometerService.PedometerBinder)service;
mPedometerService = mBinder.getService();
mPedometerService.registerCallback(mCallback);
}
public void onServiceDisconnected(ComponentName className) {
mPedometerService = null;
}
};
private void startPedometerService() {
if (!isPedometerService) {
Log.v(TAG, "Start service");
isPedometerService = true;
//start service
Intent intent = new Intent(getApplicationContext(),
PedometerService.class);
startService(intent);
}
}
//Bind to the service
private void bindPedometerService() {
Log.i(TAG, "Bind service");
Intent intent = new Intent(PedometerActivity.this, PedometerService.class);
bindService(intent, mServiceConnection,
Context.BIND_AUTO_CREATE + Context.BIND_DEBUG_UNBIND);
}
//close connection with service
private void unbindPedometerService() {
Log.i(TAG, "Unbind service");
unbindService(mServiceConnection);
}
//Stop the service that had been started
private void stopPedometerService() {
Log.i(TAG, "Stop service");
if (mPedometerService != null) {
//stop service
Intent intent = new Intent(PedometerActivity.this, PedometerService.class);
stopService(intent);
isPedometerService = false;
}
}
#Override
public void onResume() {
Log.i(TAG, "onResume");
super.onResume();
startPedometerService();
bindPedometerService();
}
#Override
public void onStop() {
super.onStop();
Log.i(TAG, "onStop");
stopPedometerService();
}
public void onDestroy() {
super.onDestroy();
unbindPedometerService();
stopPedometerService();
}
In the service class that extends Service
/*Local service binding*/
public class PedometerBinder extends Binder {
public PedometerService getService() {
return PedometerService.this;
}
}
/*A client is binding to the service with bindService()
* Returns the IBinder object received in
* ServiceConnection.onServiceConnected(ComponentName,IBinder)*/
#Override
public IBinder onBind(Intent intent) {
return new PedometerBinder();
}
I then modified my application to have tablayout with 3 tabs hence 3 fragments. I pasted the code from PedometerActivity into PedometerFragment and modified it
//Bind service
private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
//binder to communicate with the service
PedometerService.PedometerBinder mBinder = (PedometerService.PedometerBinder)service;
mPedometerService = mBinder.getService();
mPedometerService.registerCallback(mCallback);
}
public void onServiceDisconnected(ComponentName className) {
mPedometerService = null;
}
};
private void startPedometerService() {
if (!isPedometerService) {
Log.v(TAG, "Start service");
isPedometerService = true;
//start service
Intent intent = new Intent(getActivity().getApplicationContext(),
PedometerService.class);
getActivity().startService(intent);
}
}
//Bind to the service
private void bindPedometerService() {
Log.i(TAG, "Bind service");
Intent intent = new Intent(getActivity(), PedometerService.class);
getActivity().bindService(intent, mServiceConnection,
Context.BIND_AUTO_CREATE + Context.BIND_DEBUG_UNBIND);
}
//close connection with service
private void unbindPedometerService() {
Log.i(TAG, "Unbind service");
getActivity().unbindService(mServiceConnection);
}
//Stop the service that had been started
private void stopPedometerService() {
Log.i(TAG, "Stop service");
if (mPedometerService != null) {
//stop service
Intent intent = new Intent(getActivity(), PedometerService.class);
getActivity().stopService(intent);
isPedometerService = false;
}
}
#Override
public void onResume() {
Log.i(TAG, "onResume");
super.onResume();
startPedometerService();
bindPedometerService();
}
#Override
public void onStop() {
super.onStop();
Log.i(TAG, "onStop");
stopPedometerService();
}
public void onDestroy() {
super.onDestroy();
unbindPedometerService();
stopPedometerService();
}
The problem is am having trouble keeping the service running when I switch between tabs. I am using FragmentStatePagerAdapter and therefore when I navigate to the last tab, the first fragment (PedometerFragment) is unloaded. I have been able to save other variables in onSaveInstanceState but this does not seem to help since everything is restarted all over again.

You're using startService, so even if your bound components get destroyed, the service shouldn't be stopped. However, you're explicitly calling stopPedometerService() in onStop(), which is called when your fragment is no longer started.
Try simply removing stopPedometerService() from onStop() andonDestroy() in your fragments.
See: https://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html
This version of the pager is more useful when there are a large number
of pages, working more like a list view. When pages are not visible to
the user, their entire fragment may be destroyed, only keeping the
saved state of that fragment.

You need to bind service in the Activity class. Then you can use it from any attached Fragment via interface or public methods.

Related

Stop service and close app

My app use a background music service.
I have a button to quit my app but I can't find anything to close my app and my service.
I bind my service to my activity.
I tried:
unbindService(serviceConnection);
myService().stopSelf();
stopService(new Intent(this, MediaPlayer.class));
and absolutely nothing works !!! The service continues.
How can I do to destroy my service and how can I do to close my app ??
Tx
EDIT:
I use this in the onCreate method
Intent intent = new Intent(this, serviceClass);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
And in the MediaPlayer class
public class LocalBinder extends Binder {
public MediaPlayer getService() {
return MediaPlayer.this;
}
}
public IBinder onBind(Intent intent) {
Log.i(TAG, "service bound");
init();
return mBinder;
}
And that...
But I dont know if I really need to start the service. Bind the service already starts it
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
Now I did this
#Override
public void onDestroy() {
player.stop();
super.onDestroy();
}
The onDestroy method works only if i unbind the service !
This doesnt work at all:
getService().stopSelf();
this.stopService(new Intent(this, MediaPlayer.class));
So, how can I stop the service and how can I close the app ?
This is what I do in my app. onDestroy() method from the activity will be called when you close your app.
private ServiceConnection musicServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.LocalBinder binder = (MusicService.LocalBinder) service;
musicService = binder.getService();
musicService.setCallbacks(MainActivity.this);
musicServiceBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "MusicService service disconnected (unbinded)");
musicServiceBound = false;
}
};
#Override
protected void onStart() {
super.onStart();
Intent intent1 = new Intent(this, MusicService.class);
bindService(intent1, musicServiceConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onDestroy() {
super.onDestroy()
if(musicServiceBound){
musicService.stopSelf();
unbindService(musicServiceConnection);
}
}
You wrote myService(), where you are creating another service using ().
For closing your app programmatically you can refer to this question.

Android - My service onunbind but no bind again

I'm stuck in a problem with a service binding that is giving me nuts.
I got an activity that is binding a service, and is frequent that the user go in and out of that activity.
The problem comes when the user goes out first time of the activity this one unBinds the service and when is going in again, do not binds again.
The activity calls the binding service this way:
#Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, CService.class);
intent.putExtra("id_local", (String) getIntent().getExtras().get("id_local"));
intent.putExtra("id_send", (String) getIntent().getExtras().get("id_send"));
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
registerReceiver(uiUpdated, new IntentFilter("SERVER_MESAGE"));
mBound = true;
}
Where the mConnection is defined that way:
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
CService.LocalBinder binder =(CService.LocalBinder) service;
mService = binder.getService();
Log.d("Service", "onServiceConnected");
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
Log.d("Service", "onServiceDisconnected");
mBound = false;
}
};
And in the onStop I unbindService:
#Override
protected void onStop() {
if (mBound) {
Log.d("ActivityStop", "Stoping activity");
unregisterReceiver(uiUpdated);
unbindService(mConnection);
mBound = false;
}
super.onStop();
}
The onBind in the service is that one:
#Override
public IBinder onBind(Intent intent) {
final String id_local = intent.getStringExtra("id_local");
final String id_send = intent.getStringExtra("id_send");
if (!misatgesList.isEmpty()) {
misatgesList.clear();
}
mBackGroundTimer.schedule(new TimerTask() {
#Override
public void run() {
String serverResult = restRecive(id_local, id_send,
misatgesList.size());
if (serverResult != null) {
misatgesList.addAll(procesMisatges(serverResult,
id_local));
Intent i = new Intent("SERVER_MESAGE");
i.putExtra("recive", serverResult);
sendBroadcast(i);
}
}
}, 0, 1000);
return mBinder;
}
And the onUnBind is that one:
#Override
public boolean onUnbind(Intent intent) {
mBackGroundTimer.cancel();
misatgesList.clear();
Log.d("ServiceOnUnBind", "ServiceOnUnBind");
//stopSelf();
return super.onUnbind(intent);
}
So my question would be, how I can bind again the service when the activity goes in again? Or what should I do to keep the binding alive until the user goes in the activity?
I found the solution!
What I meant was how to call again the onBind. That is done using the onRebind, that alows you to call again the onBind.
So, I created the onRebind:
#Override
public void onRebind(Intent intent) {
super.onRebind(intent);
}
Also, for the onRebind to work, you have to turn the return in the onUnbind to true.
#Override
public boolean onUnbind(Intent intent) {
mBackGroundTimer.cancel();
misatgesList.clear();
Log.d("ServiceOnUnBind", "ServiceOnUnBind");
//return super.onUnbind(intent);
return true;
}
For more explanation, check there: Bound Services
Use getApplicationContext() API when binding to your service from Activity as below:
getApplicationContext().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
getApplicationContext returns the global application context - the difference from other contexts is that for example, an activity context may be destroyed (or otherwise made unavailable) by Android when your activity ends. The Application context remains available all the while your Application object exists (which is not tied to a specific Activity)

My background music service stops when I load a new activity. Am I connecting or binding wrong?

I'm trying to add background music to my game and I thought I could persist it across activities by starting the service and then just connecting and binding to it in different activities in order to control it. But my music stops playing when I try to establish a connection from my second activity. I'm very new to working with services, so I apologize for any simple mistakes.
From my MusicService class (extends Service)
private final IBinder mBinder = new ServiceBinder();
MediaPlayer mPlayer;
private int length = 0;
public static boolean STOP_ON_DESTROY = true;
// Binder subclass. Allows access from clients to the server
public class ServiceBinder extends Binder {
MusicService getService(){
return MusicService.this;
}
}
public MusicService() {}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onCreate(){
super.onCreate();
}
#Override
public int onStartCommand (Intent intent, int flags, int startId)
{
return START_STICKY;
}
public boolean isPlaying(){
if(mPlayer != null){
return mPlayer.isPlaying();
}
return false;
}
public void stopMusic()
{
if(mPlayer != null){
if(mPlayer.isPlaying()) {
mPlayer.stop();
mPlayer.release();
mPlayer = null;
}
System.out.println("stopMusic service fn");
}
}
This is the code I call in both my Main and secondary activities in order to interact with the service. The music stops during the connectToMusicService function in the secondary activity. The Main activity works great.
onCreate(){....
startMusicService();
MusicService.STOP_ON_DESTROY = true;
}
private void startMusicService() {
Intent musicIntent = new Intent();
musicIntent.setClass(getApplicationContext(), MusicService.class);
startService(musicIntent);
}
#Override
public void onStart(){
super.onStart();
// establish connection for binding to the service
connectToMusicService();
// bind to the service
bindToMusicService();
}
private void bindToMusicService() {
Intent intent = new Intent(this, MusicService.class);
bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE);
MusicService.STOP_ON_DESTROY = true;
}
private void connectToMusicService() {
myServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.ServiceBinder binder = (MusicService.ServiceBinder) service;
mService = binder.getService();
if(!mService.isPlaying())
mService.startMusic();
isServiceBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("Service disconnected from main");
isServiceBound = false;
}
};
}
The only thing I do during my Main activity's onStop is
#Override
public void onStop(){
super.onStop();
if(mService != null) {
if (MusicService.STOP_ON_DESTROY) {
mService.stopMusic();
}
}
}
UPDATE: I got it working. My issue wasn't with service binding at all. It was with static STOP_ON_DESTROY variable I was using to manage whether the music should stop when leaving an activity. I cleaned that up and all is good now. Thanks!
First of all, do you need to bind at all? Or could starting the service be enough? Started services run until you stop them (except if killed by the system when resources are scarce). I am not sure there's any point binding from each of your activities.
Btw if your service should run and play music also when your activities are closed, consider making it a foreground service.

Is it possible to use AIDL without binding service to the activity

I've implemented and aidl file as follows:
interface ITaskService{
void addGetNamesJob();
void addUploadJob();
}
I then in my service have done the following:
#Override
public IBinder onBind(Intent intent) {
return new ITaskService.Stub() {
#Override
public void addBeerNamesJob() throws RemoteException {
jobManager.addJobInBackground(new GetNamesTask());
}
#Override
public void addUploadJob() throws RemoteException {
jobManager.addJobInBackground(new UploadRatingTask(wifi, twitter, TWITTER_CONSUMER, TWITTER_CONSUMER_SECRET, /*ctx,*/ accessToken, accessTokenSecret ));
}
};
}
then in my main activity the service is bound as follows:
private void initService() {
Log.i(TAG, "initService()" );
mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
service = ITaskService.Stub.asInterface((IBinder)iBinder);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
bound = false;
service = null;
}
};
if(service == null){
Intent it = new Intent();
it.setAction("com.company.taskservice");
bindService(it, mServiceConnection, Context.BIND_AUTO_CREATE);
bound = true;
}
}
private void releaseService() {
if(bound && mServiceConnection!=null && service!=null){
unbindService(mServiceConnection);
}
bound = false;
service = null;
Log.d(TAG, "releaseService(): unbound.");
}
This all works perfectly, I can call on the methods in the service via the interface. However, what I would like to do now is on device boot is start the service, which I written like this:
public class DeviceBootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
Intent ratingUpload = new Intent(context, RatingUploaderService.class);
//Toast.makeText(context, "------------->>>>DEVICE BOOT RECEIVER CALLED ---- CONNECTED", Toast.LENGTH_LONG).show();
context.startService(ratingUpload);
}
}
}
I don't want the service to die if the app is A. sent to the background or B. killed. So if it's possible to start the service on boot, it will run independently of the application. However, can I through my aidl file access the methods without binding and if so can someone show me how?
thanks in advance

Android music service stops when backbutton is pressed

I am working on android code that switches between two different activities. There is a service that plays music over both of these activities. The problem is that when i use the back button the service ( the music) stops. I have done research on the topic i have both onResume and onRestart methods in place....i can't figure out what to do next,any help will be greatly appreciated. Both activites and service are listed below.
MainActivity.java
public class MainActivity extends Activity {
MusicService myService;
private boolean isBound;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
isBound=false;
playAudio();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void onButtonClick(View v) {
Intent intent = new Intent(this, Second_activity.class);
startActivity(intent);
onStop();
///Intent i= new Intent(this,EmpireShips.class);
//// startActivity(i);
//// onStop();
}
public void playAudio() {
Intent objIntent = new Intent(this, MusicService.class);
if(!isBound)
{
bindService(objIntent, myConnection, Context.BIND_AUTO_CREATE);
isBound=true;
startService(objIntent);
}
else
{
myService.plauseAudio();
isBound=false;
unbindService(myConnection);
}
}
public void stopAudio(View view) {
Intent objIntent = new Intent(this, MusicService.class);
if(isBound)
{
isBound=false;
unbindService(myConnection);
stopService(objIntent);
}
else
stopService(objIntent);
}
private ServiceConnection myConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
myService = ((MusicService.MyLocalBinder) service).getService();
isBound = true;
}
public void onServiceDisconnected(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;
}
}
public void onStop(){
super.onStop();
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;
myService.plauseAudio();
}
}
Second_activity.java
public class Second_activity extends Activity {
MusicService myService;
private boolean isBound;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
isBound=false;
playAudio();
}
public void playAudio() {
Intent objIntent = new Intent(this, MusicService.class);
if(!isBound)
{
bindService(objIntent, myConnection, Context.BIND_AUTO_CREATE);
isBound=true;
startService(objIntent);
}
else
{
myService.plauseAudio();
isBound=false;
unbindService(myConnection);
}
}
public void stopAudio(View view) {
Intent objIntent = new Intent(this, MusicService.class);
if(isBound)
{
isBound=false;
unbindService(myConnection);
stopService(objIntent);
}
else
stopService(objIntent);
}
private ServiceConnection myConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
myService = ((MusicService.MyLocalBinder) service).getService();
isBound = true;
}
public void onServiceDisconnected(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;
}
}
public void onStop(){
super.onStop();
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;
myService.plauseAudio();
}
}
#Override
protected void onResume() {
super.onResume();
Intent objIntent = new Intent(this, MusicService.class);
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.
bindService(objIntent, myConnection, Context.BIND_AUTO_CREATE);
isBound=true;
startService(objIntent);
}
}
public void onRestart(){
super.onRestart();
Intent objIntent = new Intent(this, MusicService.class);
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.
bindService(objIntent, myConnection, Context.BIND_AUTO_CREATE);
isBound=true;
myService.play();
}
}
}
#Override
protected void onResume() {
super.onResume();
Intent objIntent = new Intent(this, MusicService.class);
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.
bindService(objIntent, myConnection, Context.BIND_AUTO_CREATE);
isBound=true;
startService(objIntent);
}
}
public void onRestart(){
super.onRestart();
Intent objIntent = new Intent(this, MusicService.class);
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.
bindService(objIntent, myConnection, Context.BIND_AUTO_CREATE);
isBound=true;
myService.play();
}
}
}
MusicService.java
public class MusicService 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.starwars_song);
}
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 onStop(){
AudioPlayer.stop();
AudioPlayer.release();
}
public void onPause(){
AudioPlayer.stop();
AudioPlayer.release();
}
public void onDestroy(){
AudioPlayer.stop();
AudioPlayer.release();
}
public class MyLocalBinder extends Binder {
MusicService getService() {
return MusicService.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();
}
public void play() {
AudioPlayer.start();
}
}
There are multiple issue on the way you implemented.
You have to start the service on activity create (if the service is already running Service.onStartCommand will be called. create MediaPlayer instance only if not null).
Bind to the service after the service started in OnCreate to establish the ServiceConnection
keep hold of the service instance till the activity is destroyed
You can pause the media in onPause if required and start again when onResume.
Unbind the service on onDestroy activity.
Stop the service if required when exit your application else service will be running. When the application is completely removed from stack, service will also be stopped. You can avoid service been killed, by running your service as Foreground using notification.
Just delete onDestroy method in your MusicService and music continues but your service become destroy.

Categories

Resources