I am trying to create a service(in smart watch) which should run forever even if the user is not using the app. Main purpose is to use the service for Speech Recognition. So whenever user say a specific word the app should be able to respond just like google voice.
However, for test purpose, I am printing an integer in the Log, but it only executed once. that means the service is not running forever.
My service code:
public class VoiceService extends Service {
private IBinder mBinder = new VoiceBinder();
int i = 1;
public VoiceService() {
}
#Override
public void onCreate() {
super.onCreate();
updateLog();
}
public void updateLog() {
++i;
Log.v("DATA", Integer.toString(i));
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return mBinder;
}
//inner helper class
public class VoiceBinder extends Binder {
//constructor
VoiceService getService() {
return VoiceService.this;
}
}
}
My MainActivity Code:
serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
VoiceService.VoiceBinder binder = (VoiceService.VoiceBinder) iBinder;
iBinder = (IBinder) binder.getService();
MainActivity.this.voiceService = ((VoiceService.VoiceBinder)iBinder).getService();
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
voiceService = null;
}
};
//bind service
bindService(new Intent(this, VoiceService.class), serviceConnection, getApplicationContext().BIND_AUTO_CREATE);
startService(new Intent(this, VoiceService.class));
AndroidManifest:
<service
android:name=".VoiceService"
android:enabled="true"
android:exported="false">
</service>
My output:
12-20 22:27:20.307 23624-23624/? V/DATA: 2
You might want to go through Running in a Background Service wherein it mentions that
Long-running foreground operations can cause problems and interfere with the responsiveness of your user interface, which annoys your users and can even cause system errors. To avoid this, the Android framework offers several classes that help you off-load operations onto a separate thread that runs in the background. The most useful of these is IntentService.
And, also note that:
If your app targets Android 5.0 (API level 21), you should use JobScheduler to execute background services.
For best application's performance and minimize draining of battery, you may want to also check the following links:
Best Practices for Background Jobs
Adding Voice Capabilities
Create a background service in android wear
Related
What I want to do is send a logout request to my backend server when the user quits my app (can happen during any Activity, there are many).
It seems like I cannot use OnStop() as I have a gallery chooser and camera Intent and when these are started, OnPause and OnStop are called. I need a way to definitively know that the app has closed.
I've read up about using a Service/BroadcastReceiver or even a LocalBroadcastManager, or possibly tying the request to when the home button has been clicked.
I can't check if the application has been sent to background as this would be true for a camera/gallery Intent starting as well as the app being sent to background. I've also tried checking the package name of the activity being started but this may be variable on other devices (e.g. gallery might have a different package name).
Any advice/direction is much appreciated.
Edit: I've discovered there isn't really a way to intercept a home button press. Still looking for a solution!
I had a similar problem like this,I used a Service to solve my problem.This is what I have done
In main activity
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder binder) {
((KillingNotificationBar.KillBinder) binder).service.startService(new Intent(
Main.this, KillingNotificationBar.class));
}
public void onServiceDisconnected(ComponentName className) {
}
};
bindService(new Intent(Main.this,
KillingNotificationBar.class), mConnection,
Context.BIND_AUTO_CREATE);
KillingNotificationBar class
public class KillingNotificationBar extends Service {
private final IBinder mBinder = new KillBinder(this);
public class KillBinder extends Binder {
public final Service service;
public KillBinder(Service service) {
this.service = service;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onCreate() {
you will know if the activity is destroyed
}
}
add this in your manifest
<service android:name=".services.KillingNotificationBar"/>
Note
It will take 1-5 seconds to get executed.
In my application I am using an IntentService to download a file from a cloud. And showing the progress in NotificationManager. I need to show the status (Downloading/Completed or Failed) in the Activity which stared the IntentService too.
My problem is once I closed the app and open it back, I want to get the status of downloading from IntentService.
Which is the best way to do this?
You can let your Activity bind to your Service, by calling bindService() in your Activity. As per the documentation:
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.
Also:
You should create a bound service when you want to interact with the
service from activities and other components in your application or to
expose some of your application's functionality to other applications,
through interprocess communication (IPC).
The documentation provides a fully functional example of this. Below is taken from the provided link.
Service class:
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 class:
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();
// 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 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;
}
};
}
In your Service, you can define public methods that your Activity can call, such as polling for your download progress. Please refer to the documentation for explanation in detail.
There are couple of ways to have communication connection between Service and Activity. I would suggest these 2
First, you can use the great library Otto. With Otto, you can also have #Produce annotated method. With this method you will return the latest information about the download. When you #Subscribe in your Activity you will get the latest info immediately. https://github.com/square/otto
If you are using Android built-in DownloadManager it returns the updates and results with a Broadcast, you can register to that Broadcast both in your Service and Activity. This way you will be able to update both of them. I suggest you to use DownloadManager, it is awesome.
http://developer.android.com/reference/android/app/DownloadManager.html
I have a bound service that in turn binds multiple services using the same ServiceConnection object. In the onServiceConnected I save the ComponentName and the Binder of each service inside a Map, so that I can use them individually. At a certain point I'd like to unbind some of these services separately. Is there a way to do this in Android?
The only way I was able to find out to unbind a service is to use unbindService(ServiceConnection), but I don't think that I can unbind a specific service using that.
Why this seems to be not supported? Are there any downsides?
Despite the time elapsed by the library and for offering support to lower versions in Android, it works correctly, I am also using services nested in a main one and the connections work or go through the main one. They are multiple Good note that when you start a connection via intent you must close it In the same way, it creates problems in the management of processes when the service is reused by other processes within the application. When closing the connection and instantiating a new one, it creates a small error in the process that was not terminated correctly.
Just to mention how it is currently done! happy code!
here is sample code to bind and unbind service
i = new Intent(this, YourService.class)
protected ServiceConnection mServerConn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
Log.d(LOG_TAG, "onServiceConnected");
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d(LOG_TAG, "onServiceDisconnected");
}
}
public void start() {
mContext.bindService(i, mServerConn, Context.BIND_AUTO_CREATE);
mContext.startService(i);
}
public void stop() {
mContext.stopService(new Intent(mContext, ServiceRemote.class));
mContext.unbindService(mServerConn);
}
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.
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.