Started or Bound Services? - android

Which is really for a music player? What's the difference on their behavior? Please let me understand! I'm really confused on what to use. I tried making a music player with a bind service but the problem is every time I exit my application and enter it again, it seems like a new serviceConnection is started. I'm expecting that every time I go back to my app, it would still recognize that the music is already fired up. For an instance I have play and pause functions. When i play the music, exit the app, and return, I would be expecting that I could stop the player. But instead, it will play another music. So now I'm confused, should i really use bind? or started service?
public class MyService extends Service{
public IBinder myBinder = new MyPlaylistBinder();
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return myBinder;
}
public class MyPlaylistBinder extends Binder{
MyService getService(){
return MyService.this;
}
}
The code above is my MyService.java
public ServiceConnection myConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
MyPlaylistBinder binder = (MyPlaylistBinder) service;
myService = binder.getService();
Toast.makeText(getApplicationContext(), "Service is connected", Toast.LENGTH_SHORT).show();
}
#Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "Service is disconnected", Toast.LENGTH_SHORT).show();
}
};
And this one is a portion of my MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnPrevious = (ImageButton)findViewById(R.id.btnPrevious);
btnBackward = (ImageButton)findViewById(R.id.btnBackward);
btnPlay = (ImageButton)findViewById(R.id.btnPlay);
btnForward = (ImageButton)findViewById(R.id.btnForward);
btnNext = (ImageButton)findViewById(R.id.btnNext);
ComponentName myService = startService(new Intent(this, MyService.class));
Intent intent = new Intent(this, MyService.class);
bindService(intent, myConnection, Context.BIND_AUTO_CREATE);
listview = (ListView)findViewById(R.id.listView1);
ContentResolver resolver = getContentResolver();
Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
cursor = resolver.query(uri, null, null, null, null);
Above is a portion of the MainActivity's onCreate()
As you can see I'm not using an AIDL because I haven't tried that and I'm afraid I might make it worse. Please bear with me, I'm just a beginner in android :(

Documentation:
Started
A service is "started" when an application component (such as
an activity) starts it by calling startService(). Once started, a
service can run in the background indefinitely, even if the component
that started it is destroyed. Usually, a started service performs a
single operation and does not return a result to the caller. For
example, it might download or upload a file over the network. When the
operation is done, the service should stop itself.
Bound
A service is
"bound" when an application component binds to it by calling
bindService(). A bound service offers a client-server interface that
allows components to interact with the service, send requests, get
results, and even do so across processes with interprocess
communication (IPC). A bound service runs only as long as another
application component is bound to it. Multiple components can bind to
the service at once, but when all of them unbind, the service is
destroyed.
Based on that, you probably want to start a service since you intend it to keep running after the components that started it are no longer there. As a convenience to the user, you should consider having an ongoing notification as long as the service is running, and include music controls that lets the user directly pause, resume, or completely stop playback (that last one could invoke stopService, at which point you cancel the notification).

Related

The same background music playing in all activities

I use services to play background music in all activities and it works. The problem is the music continues playing even if my app is in background (when user exit with home button or back button). How can I solve this?
Services class BackgroundSoundService
public class BackgroundSoundService extends Service {
private static final String TAG = null;
MediaPlayer player;
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
player = MediaPlayer.create(this, R.raw.slow_shock);
player.setLooping(true); // Set looping
player.setVolume(100,100);
}
public int onStartCommand(Intent intent, int flags, int startId) {
player.start();
return START_NOT_STICKY;
}
public void onStart(Intent intent, int startId) {
// TO DO
}
public IBinder onUnBind(Intent arg0) {
// TO DO Auto-generated method
return null;
}
public void onStop() {
}
public void onPause() {
}
#Override
public void onDestroy() {
player.stop();
player.release();
}
#Override
public void onLowMemory() {
}
}
Starting with
Intent svc = new Intent(this, BackgroundSoundService.class);
startService(svc);
Android Manifest:
<service android:enabled="true" android:name=".BackgroundSoundService" />
This is happened because the Service is still bounded in the activity. To terminate the service when multiple activity is bound to the service, you need to unbind the service from all of them as in the documentation says:
The service lifecycle—from when it's created to when it's
destroyed—can follow either of these two paths:
A started service
The service is created when another component calls startService().
The service then runs indefinitely and must stop itself by calling
stopSelf(). Another component can also stop the service by calling
stopService(). When the service is stopped, the system destroys it.
A bound service
The service is created when another component (a client) calls
bindService(). The client then communicates with the service through
an IBinder interface. The client can close the connection by calling
unbindService(). Multiple clients can bind to the same service and
when all of them unbind, the system destroys the service. The service
does not need to stop itself.
These two paths are not entirely separate. You can bind to a service
that is already started with startService(). For example, you can
start a background music service by calling startService() with an
Intent that identifies the music to play. Later, possibly when the
user wants to exercise some control over the player or get information
about the current song, an activity can bind to the service by calling
bindService(). In cases such as this, stopService() or stopSelf()
doesn't actually stop the service until all of the clients unbind.
Then call Context.stopService() to stop it:
context.stopService(new Intent(context, BackgroundSoundService.class));

Allowing service to run permanently in background

I have a messaging app based on webscokets that relies on a background service to send and receive messages. Once the service is started, I need it to run indefinitely in the background, even when the app closes as well as the phone goes into sleep mode.
In the app, the service is started just as a user logs in, and in the onCreate method as startService(new Intent(LoggingIn.this, MessagingService.class));
How can I setup my service to run permanently in the background?
private ServiceConnection mConnection = new ServiceConnection() {
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.
imService = ((MessagingService.IMBinder) service).getService();
if (imService.isUserAuthenticated() == true) {
// Intent i = new Intent(LoggingIn.this, ListOfFriends.class);
Intent i = new Intent(LoggingIn.this, MainActivity.class);
startActivity(i);
LoggingIn.this.finish();
}
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// Because it is running in our same process, we should never
// see this happen.
imService = null;
Toast.makeText(LoggingIn.this, R.string.local_service_stopped,
Toast.LENGTH_SHORT).show();
}
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
* Start and bind the imService
*/
startService(new Intent(LoggingIn.this, MessagingService.class));
...etc
Use startForeground() in your onStartCommand() method in your service.
you need to use START_STICKY in the onStartCommand:
http://developer.android.com/reference/android/app/Service.html#START_STICKY
Then you can read this thread to start your service during boot:
Android -Starting Service at Boot Time
You need to define a name for the service in the manifest to make it run in a different thread: android:process=":my_process" so it will continue to run inbackground if you close the app

Communicate with foreground service android

First question here, but I've been around for a while.
What do I have:
I'm building an Android app which plays audio streams and online playlists. Everything is working fine now, but I'm having issues in communicating with my service.
The music is playing in a Service, started with startForeground, so it doesn't gets killed.
I need to communicate from my activity with the service, for getting the track name, image, and a couple of things more.
Whats my issue:
I think I need to start my service with bindService (instead of my current startService) so the activity can talk to it.
However, when I do that, my service gets killed after closing the Activity.
How can I get both? Binding and foreground service?
Thanks!
No. bindService will not start a service . It will just bind to the Service with a service connection, so that you will have the instance of the service to access/control it.
As per your requirement I hope you will have the instance of MediaPlayer in service . You can also start the service from Activity and then bind it. If the service is already running onStartCommand() will be called, and you can check if MediaPlayer instance is not null then simply return START_STICKY.
Change you Activity like this..
public class MainActivity extends ActionBarActivity {
CustomService customService = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// start the service, even if already running no problem.
startService(new Intent(this, CustomService.class));
// bind to the service.
bindService(new Intent(this,
CustomService.class), mConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
customService = ((CustomService.LocalBinder) iBinder).getInstance();
// now you have the instance of service.
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
customService = null;
}
};
#Override
protected void onDestroy() {
super.onDestroy();
if (customService != null) {
// Detach the service connection.
unbindService(mConnection);
}
}
}
I have similar application with MediaPlayer service. let me know if this approach doesn't help you.
Quoting Android documentation:
A bound service is destroyed once all clients unbind, unless the service was also started
And about the difference between started and bound just take a look to https://developer.android.com/guide/components/services.html
So, you have to create the Service using startService and then bindService, like #Libin does in his/her example. Then, the service will run until you use stopService or stopSelf or until Android decides that it needs resources and kills you.

How to implement a service that runs only when the app is running?

The app has a service which has to detect how many minutes the app is running and based on that, the service will initiate misc actions.
What is the proper way to implement this?
How can I be sure the service is running ONLY when the app is running in front of the user?
Starting the service seems easy - just start it on splash loading. But the harder part is ending it. I cannot just end it when the user press Back button on the last screen. How to handle situation when a user presses Home screen or some other other app (like phone call, or viber popup, or...) takes over the screen?
I tried taking suggestions from the other theme (How to start a android service from one activity and stop service in another activity?), but this does not handle the situation with Home button or other app taking over the screen.
The app has in total around 10 activities. Is it a proper way to bind this service to all 10 activities and when all are off, the service then turn itself off?
Make a BaseActivity for all of your Activities. In the BaseActivity, do the following:
public class MyActivity extends Activity implements ServiceConnection {
//you may add #override, it's optional
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, MyService.class);
bindService(intent, this, 0);
}
//you may add #override, it's optional
protected void onStop() {
super.onStop();
unbindService(this);
}
public void onServiceConnected(ComponentName name, IBinder binder) {};
public void onServiceDisconnected(ComponentName name) {};
/* lots of other stuff ... */
}
Your BaseActivity will need to implement ServiceConnection interface (or you can use an anonymous inner class), but you can leave those methods empty.
In your Service class, you need to implement the onBind(Intent) method and return an IBinder. The easiest way to do that is like so:
public class MyService extends Service {
private final IBinder localBinder = new LocalBinder();
public void onCreate() {
super.onCreate();
// first time the service is bound, it will be created
// you can start up your timed-operations here
}
public IBinder onBind(Intent intent) {
return localBinder;
}
public void onUnbind(Intent intent) {
// called when the last Activity is unbound from this service
// stop your timed operations here
}
public class LocalBinder extends Binder {
MyService getService() {
return MyService.this;
}
}
}
Bound Service is define specifically for this purpose, you can bind Activities to it, and when all the Activities are gone, it will be stopped as well. The link should contain enough detail for you to implement.

OnBind() on service always returns False - Android

I'm trying to bind a service, but onBind() always returns false.
This is the code for the ServiceConnection-
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with our service has been established,
// giving us the service object we can use to interact with our service.
mBoundService = ((ScheduleService.ServiceBinder) service).getService();
}
public void onServiceDisconnected(ComponentName className) {
mBoundService = null;
}
};
This is call to bindService() -
boolean test = getApplicationContext().bindService(new Intent(this, ScheduleService.class), mConnection, Context.BIND_AUTO_CREATE);
This is the declaration of the service in the Manifest -
<service android:name=".Notifications.ScheduleService" android:enabled="true"/>
I've read previous questions regarding the subject and couldn't find an answer(tried switching the Activity context with the Application context, but it didn't help).
I'm using using Frgaments and ActionBarSherlock, and my Activity extends SlidingFragmentActivity (That's why i'm using the application context, which doesn't help).
Edit - This is the code of the service i'm trying to start -
public class ScheduleService extends Service {
/**
* Class for clients to access
*/
public class ServiceBinder extends Binder {
public ScheduleService getService() {
return ScheduleService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("ScheduleService", "Received start id " + startId + ": " + intent);
// We want this service to continue running until it is explicitly stopped, so return sticky.
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
// This is the object that receives interactions from clients. See
private final IBinder mBinder = new ServiceBinder();
/**
* Show an alarm for a certain date when the alarm is called it will pop up a notification
*/
public void setAlarm(Calendar c) {
// This starts a new thread to set the alarm
// You want to push off your tasks onto a new thread to free up the UI to carry on responding
new AlarmTask(this, c).run();
}
}
Any help will be appreciated . Thanks.
What is the fully qualified class-name of ScheduleService (i.e. including the full package-name)?
I'm asking this, because in your AndroidManifest.xml file, your service's name is .Notifications.ScheduleService, which seems a bit odd:
This tells me that either
The (last part of the) package-name contains a upper-case
character... not so good.
I would expect .notifications.ScheduleService instead, if this is the case.
The ScheduleService is defined within a file called Notifications.java.
I would expect .Notifications$ScheduleService instead, if this is the case (dollar sign instead of period).
Do you mean bindService() returns false? onBind() returns IBinder type.
Keep in mind that service binding takes some time. If you want to perform some action after binding is done you can perform it in the onServiceConnected() method.
public void onServiceConnected(ComponentName className, IBinder service) {
mBoundService = ((ScheduleService.ServiceBinder) service).getService();
Calendar c = new Calendar();
mBoundService.setAlarm(c);
}
If you need more guidance on this you need to show us your Activity code.
Why do you use the application context to bind the service?
The method bindService is called through the ContextWrapper. It might not be the issue but I'd share contexts across the place where you bind the service and where you have the connection.
In your case instead of
boolean test = getApplicationContext().bindService(new Intent(this, ScheduleService.class), mConnection, Context.BIND_AUTO_CREATE);
I'd do the following
boolean test = bindService(new Intent(this, ScheduleService.class), mConnection, Context.BIND_AUTO_CREATE);
Or if you want to keep a global context within the application, move everything to your Application file and call it similarly the same way suggested above.
The issue can also be on the package name of your app and the declaration of your service in your manifest. If you are unsure make sure to give the global route to your service in the manifest.

Categories

Resources