I am working on a wallpaper application in which i am setting a gallery of images on wallpaper with shuffle effect for 5 min, 10 min etc. I am using service for this task. My service works well when app remains in background, but service get stopped when app get stopped.This is my code for service class:
public class WallpaperService extends Service {
ArrayList<String> arrayList;int counter = 0;
boolean serviceStopped;
private IBinder binder = new WallpaperServiceBinder();
public WallpaperService() {
}
private Handler mHandler;
private Runnable updateRunnable = new Runnable() {
#Override
public void run() {
if (serviceStopped == false)
{
createNotificationIcon();
}
queueRunnable();
}
};
public class WallpaperServiceBinder extends Binder {
public WallpaperService getService() {
return WallpaperService.this;
}
}
private void queueRunnable() {
// 600000 : cada 10 minutos, comprueba si hay nuevas notificaciones y actualiza la
// notification BAR
mHandler.postDelayed(updateRunnable, 5000);
}
#Override
public int onStartCommand(Intent intent,int flag, int start_id){
super.onStartCommand(intent,flag,start_id);
arrayList = intent.getStringArrayListExtra("image_url");
return START_STICKY;
}
#Override
public void onRebind(Intent intent) {
Log.v("Service","in onRebind");
super.onRebind(intent);
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public void onCreate() {
serviceStopped = false;
mHandler = new Handler();
queueRunnable();
}
#Override
public void onStart(Intent intent, int startid) {
}
public void createNotificationIcon()
{
counter += 1;
Toast.makeText(this, "Hello", Toast.LENGTH_SHORT).show();
Picasso.with(getApplicationContext()).load(arrayList.get(counter)).into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
try {
final WallpaperManager wallpaperManager =
WallpaperManager.getInstance(getApplicationContext());
wallpaperManager.setBitmap(bitmap);
wallpaperManager.suggestDesiredDimensions(1080, 1920);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
//Here you should place a loading gif in the ImageView to
//while image is being obtained.
}
});
}}
This is the code i am using to start service:
Intent intent = new Intent(CategoryActivity.this,WallpaperService.class);
intent.putExtra("image_url",img_urls);
intent.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
startService(intent);
bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
Have you added these lines in manifest file
<application> <service android:name=".ExampleService" /></application>
Important Fact about the bindService
If a component calls bindService() to create the service and onStartCommand() is not called, the service runs only as long as the component is bound to it. After the service is unbound from all of its clients, the system destroys it.
Try using Started Service
A started service is one that another component starts by calling
startService(), which results in a call to the service's
onStartCommand() method.
When a service is started, it has a lifecycle that's independent of
the component that started it. The service can run in the background
indefinitely, even if the component that started it is destroyed. As
such, the service should stop itself when its job is complete by
calling stopSelf(), or another component can stop it by calling
stopService().
An application component such as an activity can start the service by
calling startService() and passing an Intent that specifies the
service and includes any data for the service to use. The service
receives this Intent in the onStartCommand() method.
Handling onStartCommand
Notice that the onStartCommand() method must return an integer. The
integer is a value that describes how the system should continue the
service in the event that the system kills it. The default
implementation for IntentService handles this for you, but you are
able to modify it. The return value from onStartCommand() must be one
of the following constants:
START_NOT_STICKY If the system kills the service after onStartCommand() returns, do not recreate the service unless there are
pending intents to deliver. This is the safest option to avoid running
your service when not necessary and when your application can simply
restart any unfinished jobs.
START_STICKY If the system kills the service after onStartCommand() returns, recreate the service and call
onStartCommand(), but do not redeliver the last intent. Instead, the
system calls onStartCommand() with a null intent unless there are
pending intents to start the service. In that case, those intents are
delivered. This is suitable for media players (or similar services)
that are not executing commands but are running indefinitely and
waiting for a job.
START_REDELIVER_INTENT If the system kills the service after onStartCommand() returns, recreate the service and call
onStartCommand() with the last intent that was delivered to the
service. Any pending intents are delivered in turn. This is suitable
for services that are actively performing a job that should be
immediately resumed, such as downloading a file.
Note: In your case you should use Started Service and return START_STICKY or START_REDELIVER_INTENT (based on your requirement) in onStartCommand()
Check Official Documentation for detailed description of the Services.
Related
As a Unity3D developer, I've created an application and exported it to Android Studio. My client is asking me to make this app go back to foreground after 10 seconds of user's inactivity (in case the user opens another app). I've tried to create a service that is started on the OnPause function of my UnityPlayerActivity. Then the service would detect the user's inactivity and launch my app again (putting it back to foreground). First I've only tried to use Time.Schedule to launch my app after 10 seconds no matter what, but everytime the application is paused (goes to background), it starts the service and then it crashes. The question is: is there a simple way to do this? I'm not an Android Java Developer (only know the basics) and I'm struggling with this part .
I'm trying to create this Service and then I try to start it from the onPause() function in my activity. When I pause the app on my phone the app crashes. Can anyone tell me if I'm on the right way and, please, help me?
public class ReturnToForeground extends Service {
public ReturnToForeground() {
}
// constant
public static final long NOTIFY_INTERVAL = 10 * 1000; // 10 seconds
// run on another Thread to avoid crash
private Handler mHandler = new Handler();
// timer handling
private Timer mTimer = null;
Intent intent = new Intent(this, UnityPlayerActivity.class);
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// cancel if already existed
if (mTimer != null) {
mTimer.cancel();
} else {
// recreate new
mTimer = new Timer();
}
// schedule task
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0, NOTIFY_INTERVAL);
return super.onStartCommand(intent, flags, startId);
}
class TimeDisplayTimerTask extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
// do action
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
startActivity(intent);
}
});
}
}
}
Make a timer for when the app is in the onPause(), when the timer reaches 10 seconds you should pass an intent which will make your app active again (let's say taking the user back to the main view). You can save the current data of your app in something like shared preffs, so that information wont be lost in most situations.
In many cases this problem appears when a resource which you are trying to reload is not active anymore inside the application.
From the info you have shared it seems like you are not starting the service correctly. It would be nice if you can add a crash log so that we can debug it and see where is the problem.
I have a service declared in manifest like
<service android:name=".services.ScreenOnService" android:process="#string/screenProcess"/>
all the service does is registering for Screen_on broadcast (As i always need the information that the Screen was turned on and not only if my app is running)
#Nullable
#Override
public IBinder onBind(Intent intent)
{
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
//All this service has to do is register for the screen on broadcast
//as this one can't be registere in manifest and the ACTION_USER_PRESENT is
//not guaranteed to be fired. (E.g. if no lock screen is used)
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
registerReceiver(screenEventReceiver,filter);
return START_STICKY;
}
#Override
public void onDestroy()
{
unregisterReceiver(screenEventReceiver);
super.onDestroy();
}
I start the service from my Application onCreate
#Override
public void onCreate() {
super.onCreate();
if(!isScreenOnServiceAlreadyRunning())
{
//Start the screen on service
Intent screenOnService = new Intent(this, ScreenOnService.class);
startService(screenOnService);
}
}
Everything is fine as long as the app is running. If I kill the app, the service in it's own process is also killed and I don't get why.
I found a promising article here http://fabcirablog.weebly.com/blog/creating-a-never-ending-background-service-in-android and hoped the best but even if I do this and send a broadcast, it will not work.
Why does the service stop working if the app is killed? I assumed it will keep running, as it's in it's own process. If what I want is not realisable with my approach, what's the best way to do so?
Thanks already.
#Hardcore_Graverobber I think you should start the service as a separate process,
please refer this tutorial
http://www.vogella.com/tutorials/AndroidServices/article.html
I have an app that gets users messages from database and if there is a new message it pushes a notification i use a service for that.. The service works fine when the app is opened or in the foreground.. But when I close it it doesn't work.. It is not destroyed or stopped it's just doesn't work :S I don't know why.. This is my service code :
public class BGService extends Service {
ArrayList<Message> messages = new ArrayList<Message>();
ArrayList<String> requests = new ArrayList<String>();
Timer timer = new Timer();
Timer timer2 = new Timer();
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onDestroy() {
Log.d("Chat", "BGService Destroyed");
timer.cancel();
timer.purge();
timer2.cancel();
timer2.purge();
}
#SuppressWarnings("unchecked")
#Override
public void onStart(Intent intent, int startId) {
Log.d("Chat", "BGService Started");
messages = (ArrayList<Message>) intent.getExtras().get("messages");
requests = (ArrayList<String>) intent.getExtras().get("requests");
Log.d("Button Clicked", "Messages: " + messages);
new Timer().scheduleAtFixedRate(new TimerTask() {
public void run() {
Log.d("Service", "Running");
}
}, 2000, 2000);
}
}
Your telling the service to stop in your code. Because your using onBind() it appears that your not starting the service and instead binging to it. If you bind to a service the service automatically ends when your activity ends.
If you want to keep your service running.
Start the service to keep service running
Bind to the service to have a service while app is running
Set a notification so the service is in the foreground
Change your manifest so the service runs in a separate process
Start the service so you can return startsticky in the onStartCommand() to tell the os you want this to stick on
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
Start Service. Bind to the service only if you have a connection to communicate with the service back and forth with. This is returned from onBind()
startService(new Intent(context, ServiceLocationRecorder.class));
// bind to the service
if (!mIsBound) {
// Bind to the service
bindService(new Intent(context,
ServiceLocationRecorder.class), mConnection,
Context.BIND_AUTO_CREATE);
mIsBound = true;
}
Binding to the service is used to setup a binder handler that you can communicate to and from the service with. Returning null in onBind() defeats the purpose of the onBind() event so you could skip this code.
/**
* When binding to the service, we return an interface to our messenger for
* sending messages to the service.
*/
#Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
set the service to the foreground you do this and the os will be less likely to end your service to get memory for another app.
//this is done inside the service
startForeground(R.id.action_record, getMyCustomNotification());
Run the service in its own process then GC will be able to collect your activity and keep the service running.
<service
android:name="com.example.service"
android:process=":myseparateprocess" >s -->
</service>
I have a foreground service to download some contents form the web.
Unfortunately, due to bug which reported here my service being killed when a receiver received a broadcast within my service but it's notification won't be killed and I saw the following log in my logcat:
I/ActivityManager(449): Killing 11073:my-package-name/u0a102 (adj 0): remove task
Is there anyway to to destroy foreground notification when it's parent service get killed by OS?
Service ending remove the foreground notification.
#Override
public void onDestroy() {
// mycleanup first
stopForeground(true);
super.onDestroy();
}
Use stopForeground:
#Override
public void onDestroy() {
// as the bug seems to exists for android 4.4
if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.KITKAT)
{
stopForeground(true);
}
super.onDestroy();
}
or
public void onTaskRemoved (Intent rootIntent)
{
// as the bug seems to exists for android 4.4
if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.KITKAT)
{
stopForeground(true);
}
}
Inside the notification check periodically (e.g. Handler) if service is still running using code below:
public static boolean isMyServiceRunning(Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (MyService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
And if not just shut down notification.
private static final int DEALY = 10000;
private Handler handler = new Handler();
...
handler.postDelayed(ensureSericeIsRunning, DELAY);
...
private Runnable ensureSericeIsRunning = new Runnable() {
#Override
public void run() {
if (!isMyServiceRunning(getActivity())){
//shut down notification
} else {
handler.postDelayed(ensureSericeIsRunning, DELAY);
}
}
};
use onDestroy(). Even tho the documentation says it is not guaranteed to be called, I have tested multiple times and the only cases it doesn't get called is when the system kills the process, but to that point your notification will be killed to, so it's ok.
You could remove the notification from onStop or onDestroy inside of your service class.
P.S there no guarantee this would work, in api 14 and above the service can still be running even without foreground notification, you could return START_STICKY that will bring back your service even if the system destroyed it, system will restart it.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
use the service onTaskRemoved() method.
At the moment I have code that starts an application from boot-up but opens it into the foreground.
This was done by
public void onReceive(Context context, Intent intent) {
if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
Intent start = new Intent(context, ApolloMobileActivity.class);
start.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(start);
Then to get it sent to the background at boot-up I created another java file called, StartAtBootService
so I changed the receiver class to:
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Intent i = new Intent();
i.setAction("com.example.ssab.StartAtBootService");
context.startService(i);
}
And the Service class was
public class StartAtBootService extends Service
{
public IBinder onBind(Intent intent)
{
return null;
}
#Override
public void onCreate()
{
Log.v("StartServiceAtBoot", "StartAtBootService Created");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.v("StartServiceAtBoot", "StartAtBootService -- onStartCommand()");
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
/*
* In Android 2.0 and later, onStart() is depreciated. Use
* onStartCommand() instead, or compile against API Level 5 and
* use both.
* http://android-developers.blogspot.com/2010/02/service-api-changes-starting-with.html
#Override
public void onStart(Intent intent, int startId)
{
Log.v("StartServiceAtBoot", "StartAtBootService -- onStart()");
}
*/
#Override
public void onDestroy()
{
Log.v("StartServiceAtBoot", "StartAtBootService Destroyed");
}
}
Is it possible to change the StartAtBootService to run an activity in another java file called ApolloMobileActivity in the background?
I have tested this code and even though it runs in the background at boot-up it doesn't run the code in ApolloMobileActivity.
Please help! Thanks guys :)
An Activity is an application component that provides a screen with
which users can interact in order to do something, such as dial the
phone, take a photo, send an email, or view a map. Each activity is
given a window in which to draw its user interface. The window
typically fills the screen, but may be smaller than the screen and
float on top of other windows.
from Activities
You can start an Activity, but there is no such thing as an invisible Activity. These are UI-components. If you want to do invisible work in the background, you have to do it in your service.