I have made an app in which a service runs in the background. But if the android system requires resources, it will stop the service. However I may still require my service to run.
Is it a bad practice to restart the service (if condition relevant to my app still holds true) in the onDestroy method of my service?
How can I make sure my service runs indefinitely (if condition relevant to my app still holds true)? Or atleast on high priority?
Probably the best you can do is use the START_STICKY flag, which tells Android to attempt to restart the service if it has stopped. Beyond that ensure that it consumes as few resources as possible, so that it is less likely to be destroyed.
Android prioritizes the UI over everything. Then processes that are related to the UI. Then processes that are consuming the least amount of resources. A Service runs in the background, so unless it has resources that are also in use on the UI or connected to the UI in some way, it should be a lower priority.
Also you cannot tell Android how to prioritize your Service (everyone would make theirs the "highest priority" right?). So it goes by how well you minimize the impact on overall resources - why kill 3 Services when it could kill 1 and regain all the resources it needs?
To help understand how to manage memory better: http://developer.android.com/training/articles/memory.html
set it START_STICKY. It Causes after killing service the service will restart again. it is my code :
android manifest :
<application
....
<service android:name=".UpdateService" />
</application>
service class :
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class UpdateService extends Service {
BroadcastReceiver mReceiver;
#Override
public void onCreate() {
super.onCreate();
// register receiver that handles screen on and screen off logic
IntentFilter filter = new IntentFilter(Intent.....);
filter.addAction(Intent....);
mReceiver = new MyReceiver();
registerReceiver(mReceiver, filter);
}
#Override
public void onDestroy() {
unregisterReceiver(mReceiver);
Log.i("onDestroy Reciever", "Called");
super.onDestroy();
}
#Override
public void onStart(Intent intent, int startId) {
Log.i("log", "action Called");
}
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
}
receiver class :
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("Log", "recevid");
}
}
in StartupActivity :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Context context = getApplicationContext();
Intent service = new Intent(context, UpdateService.class);
context.startService(service);
}
Related
I want to start service on reboot of the device.
First I used broadcast receiver.It worked on my android phone having version 7. But I want to implement it on Xixun controller which is android based having version 4.0.3
Broadcast receiver did not work. I have gone through reading that, for API levels below 26, one should use WakefulBroadcastReceiver. When I did that, it worked on my phone but not on Xixun controller.
The process to reboot Xixun controller is just to power on and power off using supply.I have also used power intent of broadcast receiver. But it didn't work because device is batteryless.
What would be reason behind my service is not working?
[manifest receiver]
Following is service code
package com.example.serviceexample;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;
import android.view.Gravity;
import android.widget.Toast;
public class MyService extends Service {
#Override
public void onCreate()
{
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast myToast =Toast.makeText(this,"service started",Toast.LENGTH_LONG);
myToast.setGravity(Gravity.TOP|Gravity.LEFT, 0, 0);
myToast.setDuration(Toast.LENGTH_LONG);
myToast.show();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
When I used broadcast receiver, codes are same except basic syntax.
The problem
I wrote a program for Android 4.3, with a main activity, a broadcast receiver and a service. The activity binds to the service in its onCreate method. The activity has a button that schedules an alarm 10 seconds in the future. The alarm triggers the BroadcastReceiver.onReceive. This method attempts to get a hold on the binder, but there is a circumstance in which this fails and peekService returns null.
What works
Clicking the button and waiting 10 seconds
Clicking the button, clicking home, and wait in the home screen till 10 seconds are elapsed.
Clicking the button, clicking the activity list, close the activity by swiping it to the left, reopen the program and wait till 10 seconds are elapsed (you need to be fast :-).
What doesn't work
Clicking the button, clicking the activity list, close the activity by swiping it to the left and wait till 10 seconds are elapsed; this is essentially like (3.) without reopening the program.
Specifically, if I execute these 4 tests I get the following log:
02-05 20:53:29.992: D/ServiceSSCCE.MyService(476): I've been bound.
02-05 20:53:30.179: D/ServiceSSCCE.MainActivity(476): Service connected.
02-05 20:53:43.265: D/ServiceSSCCE.MyReceiver(476): Awesome, let's get this **** done!
02-05 20:53:55.460: D/ServiceSSCCE.MyReceiver(476): Awesome, let's get this **** done!
02-05 20:54:08.531: D/ServiceSSCCE.MyService(764): I've been bound.
02-05 20:54:08.663: D/ServiceSSCCE.MainActivity(764): Service connected.
02-05 20:54:10.890: D/ServiceSSCCE.MyReceiver(764): Awesome, let's get this **** done!
02-05 20:54:23.593: D/ServiceSSCCE.MyReceiver(788): I just received a null binder.
The last message shows that test (4.) failed, while previous messages show that (1.), (2.) and (3.) succedeed.
I'm aware of this, this and this answer, as well as pretty much any relevant result that Google lists in the first two pages. I tried several things, including but not limited to:
Calling startService, both from BroadcastReceiver.onReceive and from the main activity (although I'm not sure I understood how bindService and startService interact)
Fiddling with intents, in particular with context (this VS getApplicationContext and so on).
Setting the service as foreground (see this)
I'm really interested in why this happens, more than I'm interested in the solution.
MainActivity.java
package it.damix.examples.servicesscce;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
public class MainActivity extends Activity {
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d("ServiceSSCCE.MainActivity", "Service disconnected.");
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("ServiceSSCCE.MainActivity", "Service connected.");
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE);
}
public void scheduleAlarm(View view) {
AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getBroadcast(this, 101, new Intent(this, MyReceiver.class), 0);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 10000, pi);
}
}
MyReceiver.java
package it.damix.examples.servicesscce;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
IBinder binder = peekService(context, new Intent(context, MyService.class));
if (binder == null)
Log.d("ServiceSSCCE.MyReceiver", "I just received a null binder.");
else
Log.d("ServiceSSCCE.MyReceiver", "Awesome, let's get this **** done!");
}
}
MyService.java
package it.damix.examples.servicesscce;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Messenger;
import android.util.Log;
public class MyService extends Service {
static class MyHandler extends Handler {
}
#Override
public IBinder onBind(Intent arg0) {
Log.d("ServiceSSCCE.MyService", "I've been bound.");
return new Messenger(new MyHandler()).getBinder();
}
#Override
public boolean onUnbind(Intent intent) {
Log.d("ServiceSSCCE.MyService", "I've been unbound.");
return super.onUnbind(intent);
}
#Override
public void onRebind(Intent intent) {
Log.d("ServiceSSCCE.MyService", "I've been rebound.");
super.onRebind(intent);
}
}
ApplicationManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="it.damix.examples.servicesscce"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="18"
android:targetSdkVersion="18" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="it.damix.examples.servicesscce.MyReceiver" android:enabled="true"></receiver>
<service android:name="it.damix.examples.servicesscce.MyService" android:enabled="true"></service>
</application>
</manifest>
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="it.damix.examples.servicesscce.MainActivity" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me to schedule an alarm..."
android:onClick="scheduleAlarm"/>
</RelativeLayout>
Links
Done that
This too
Yep
Ah-ah
Something else that doesn't help
+1 for damix911's very complete statement of the problem and steps for possible resolution. The posting of all the code allowed me to easily recreate the test app.
The short answer to the question of why case #4 fails lies in some undocumented details of peekService()'s behavior. In this post by Android framework engineer Dianne Hackborn, she explains that for peekService() to return an IBinder, some component must have previously bound to the service, causing the system to create an IBinder. That post is the only place I have found those additional conditions for obtaining an IBinder described.
Here, for cases #1 through #3, an instance of MainActivity exists and has bound to the service, creating an IBinder. When the receiver runs and calls peekService(), it obtains that IBinder. For case #4, swiping the app from the recent task list kills the entire app process: the activity and bound service. When the alarm subsequently fires, the app process is recreated for the receiver, but the activity is not launched, there is no request to bind to the service, and the service is not created, so peekService() returns null.
I was not able to reproduce damix911's solution. When I modified the service attributes to make it run as an isolatedProcess I got a security exception (KitKat device). I question how starting the service and making it a foreground service would change anything. Starting it and returning the default (super) mode does cause the service to become sticky, so that when the process is recreated after the swipe the service will be recreated. But there is still nothing binding to it, so there is no IBinder for peekService() to return.
In short
The solution involves three things:
Making the service a foreground service.
Starting it in the activity using startService and binding to it. Aparently it's not enough for peekService to having started a service; aparently someone (an activity or probably another service) must have bound to it. Why this is the case it's beyond comprehension (to me).
Adding android:isolatedService="true" in the service declaration.
In detail
MyReceiver.java is correct.
The service declared in MyService.java needs indeed to be foreground:
public class MyService extends Service {
...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = new Notification.Builder(this)
.setTicker("Bla bla...")
.setContentTitle("Title...")
.setContentText("Text...")
.build();
startForeground(1234, notification);
return super.onStartCommand(intent, flags, startId);
}
...
}
This change in the service caused, at least one time, my activity to raise a connection leak warning (although I was not able to reproduce the behavior). However, it was fixed by properly unbinding the connection; this means removing the service code from onCreate and adding appropriate onResume and onStop methods to MainActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume() {
startService(new Intent(this, MyService.class));
bindService(new Intent(this, MyService.class), mConnection, 0);
super.onResume();
}
#Override
protected void onStop() {
unbindService(mConnection);
super.onStop();
}
We are almost done. At this point (1.), (2.) and (3.) still work, and (4.) still doesn't work. The patient, actually got worse: now BroadcastReceive.onReceive doesn't even get triggered.
The final touch that fixes everything is adding the attribute android:isolatedService="true" to the service declaration in ApplicationManifest.xml.
<service
android:name="it.damix.examples.servicesscce.MyService"
android:enabled="true"
android:isolatedProcess="true"></service>
i am trying to write a sample Android service code to test whether , the service stop itself or not after returning START_NOT_STICKY to onStartCommand. But i whenever , i closed my app , the service stop itself , whereas according to the rule START_NOT_STICKY will not allow to stop the service automatically.
MyCode :
ServiceDemo.java
package com.example.servicedemo;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent in = new Intent(this,TrackService.class);
startService(in);
}}
TrackService.java
package com.example.servicedemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class TrackService extends Service
{
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags , int startId)
{
return START_NOT_STICKY;
}
#Override
public boolean onUnbind(Intent intent)
{
return super.onUnbind(intent);
}}
this my above code , whenever i close my app , the app service stops itself , please help me out , how can i restrict my service to stop or restart itself.
close my app means , pressing home and from slide menu swipe up app to close completely
That means that you are terminating your background process. At that point, your service is gone, and since you are returning START_NOT_STICKY, it will not automatically restart.
In other words, what is happening is perfectly normal.
Close with swipe won't kill this code.
It's a service that runs in the foreground so android treats it as if it is on the screen. It runs in a seperate process so the main process can be killed. It shows a custom notification to the user when its running so its completely ligit and it is written.
Note Eclipse ADK Users only put the service in a different process when your done debugging it.
manifest
<service
android:name="com.gosylvester.bestrides.ServiceLocationRecorder"
android:process=":myService" >
</service>
</application>
MyService class
private boolean isRecording = false;
public int onStartCommand(Intent intent, int flags, int startId) {
boolean isTrackerMarker = SettingMarker.TRACKER_MARKER_DEFAULT;
if (intent != null) {
isRecording = intent.getBooleanExtra("isrecording", isRecording);
startRecording(isRecording);
}
//if isRecording keep the service running else let os know service can be killed
if (isRecording) {
startForeground(R.id.action_record, getMyCustomNotification());
return Service.START_STICKY;
} else {
stopForeground(true);
return Service.START_NOT_STICKY;
}
}
The service does get re-created, just not re-started.
If you override the onCreate and do a Log.d or a Toast, you will see that onCreate gets called after your activity and app is destroyed and even the service onDestroy is called.
So the trick to keep it running after it is re-created is to put your code on the onCreate method and use the onStartCommand just to return START_STICKY.
Note: onCreate is called before onStartCommand, so your code will run both when it is started by startService and from the system self re-creation.
I am trying to make a Lock Screen App, that is why I want to start my app every time the Screen is turned on. Currently I found a solution where a Receiver for Screen on/off and the methods onPause() and onResume() are used. This is the Link of the Example: http://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/#comment-4777
I am using the example of the activity and not the service.
I am actually getting Feedback in the LogCat when the screen is turned off and on and the app is already running. The problem is that the app doesn't start when I am turning the screen on (even if it is shown under recently used apps).
I am not sure but I think the example works fine and I am just missing to add the essential code.
I hope someone can help !!
Thanks for the quick answer. I have tried to run your code but it is still not working. I am not sure what is wrong. There is no error message. The application just runs normally but won't start when the screen goes on.
To make it easier to help me here is my code ;)
This is my Receiver:
package com.example.screenlocker;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class StartMyServiceAtBootReceiver extends BroadcastReceiver {
public static boolean screenOff = true;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
screenOff = true;
Intent i = new Intent(context,LockService.class);
i.putExtra("screen_state", screenOff);
context.startService(i);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
screenOff = false;
}
}
and this my Service:
package com.example.screenlocker;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
public class LockService extends Service {
public void onCreate(){
IntentFilter filter=new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver locker=new StartMyServiceAtBootReceiver();
registerReceiver(locker, filter);
}
#Override
public void onStart(Intent intent, int startId) {
boolean screenOn = intent.getBooleanExtra("screen_state", false);
if(screenOn){
startActivity(new Intent(this, MainActivity.class));
}
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
Maybe you know what is wrong.
The following things need to be done in order to achieve this.
1.When your application starts you must start a service for registering the SCREEN_TURN_ON and SCREEN_TURN_OFF events.
REASON If you won't start a service to register these events and just register it inside an activity.Then when activity gets destroyed it stops registering for the screen on/off events.Making a service causes it to outlive the activity's or your application's lifetime.
2.Now you need to put some code in your service (inside the onCreate method)
IntentFilter filter=new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
locker=new startLockActivity();
registerReceiver(locker, filter);
3.Make a BroadCastReciever and check for the Screen ON/OFF events and perform actions accordingly.
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
screenOff = true;
Intent i = new Intent(context,Locker.class);
i.putExtra("screen_state", screenOff);
context.startService(i);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
screenOff = false;
}
4.Now in your service onStartCommand method put some code to get the flag sent via the receiver and start your lock activity.
boolean screenOn = intent.getBooleanExtra("screen_state", false);
if(screenOn){
startActivty(this,yourLockActivity.class);
}
Hope it helps you out.
I see the following error in DDMS when trying to use a CheckBox on my MyActivity" activity to start a service called "MyService":
W/ActivityManager( 73): Unable to start service Intent { cmp=com.example.android.myprogram/.MyService }: not found
I used the tutorial http://developer.android.com/resources/tutorials/views/hello-formstuff.html and added the provided code to the end of my onCreate() method. I have the classes specified separately in MyActivity.java and MyService.java.
package com.example.android.myprogram;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CheckBox;
public class MyActivity extends Activity {
private static final String TAG = "MyActivity";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final CheckBox checkbox = (CheckBox) findViewById(R.id.checkbox);
checkbox.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// Perform action on clicks, depending on whether it's now checked
if (((CheckBox) v).isChecked()) {
// TODO: Add code to START the service
Log.d(TAG, "startService from checkbox");
startService(new Intent(MyActivity.this, MyService.class));
} else {
// TODO: Add code to STOP the service
Log.d(TAG, "stopService from checkbox");
stopService(new Intent(MyActivity.this, MyService.class));
}
}
});
}
}
My manifest file does have the following in which I've also tried the full namespace, short name, using an intent-filter per another search, etc. I'm not saying what is there is correct. I just left it at a stopping point.
<service android:name=".MyService">
<intent-filter><action android:name="com.example.android.myprogram.MyService"></action>
</intent-filter>
</service>
And lastly, my service which I've decided to break down to it's bare minimum:
package com.example.android.myprogram;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
private static final String TAG = "MyService";
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Log.d(TAG, "onCreate");
//code to execute when the service is first created
}
#Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
//code to execute when the service is shutting down
}
#Override
public void onStart(Intent intent, int startid) {
Log.d(TAG, "onStart");
//code to execute when the service is starting up
}
}
I'm very, very, very new to Java/Android programming and programming in general (but learning) so I'm sure this is user error and probably common sense to everyone else. Any suggestions would be great.
I kept digging around and, as I figured, I was making an obvious rookie error. In AndroidManifest.xml, I had the < service> declaration after < application> instead of nested inside it.
You need not to write intent filter because you are starting service explicitly.
If you are new to android use following link it will be very helpful for you.
It has service example too.
http://saigeethamn.blogspot.com/2009/08/android-developers-tutorial-for.html
see my answer in
Unable to start Service Intent
there's a good example
http://www.websmithing.com/2011/02/01/how-to-update-the-ui-in-an-android-activity-using-data-from-a-background-service/comment-page-1/
clean up the line in your manifest.xml
<intent-filter>
<action android:name="com.example.android.myprogram.MyService">
</action>
</intent-filter>