I have a service and application. There is communication between them by sending intents on specific situations. In activity I register and unregister broadcast receiver to collect this intents. Intents from service are sending when particular callback method is executed. Is there a possibility to send this intents only when activity is in the foreground? Because when this is hide there is no need to gather this intents (it helpful only to show some situations in real time)? I figure out that in activity could be static field that indicates about such situation, but I don't know how to get access to activity from service and additionally I found information that this is vary bad design practise.. Thank for any suggestions!
Declare this in your Activity:
public static boolean isRunning;
Then in your onPause to set isRunning = false;
and in onResume set it to isRunning = true;
Then from your Service you can simply call ActivityName.isRunning to know if it is in foreground or not!
you can use a static variable within the activity.
class MyActivity extends Activity {
static boolean active = false;
#Override
public void onStart() {
super.onStart();
active = true;
}
#Override
public void onStop() {
super.onStop();
active = false;
}
}
Add just check in service as
if(MyActivity.active)
{
//send broadcast.
}
OR
go with this to check status of activity is it active or not
public boolean isRunning(Context ctx) {
ActivityManager activityManager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);
for (RunningTaskInfo task : tasks) {
if (ctx.getPackageName().equalsIgnoreCase(task.baseActivity.getPackageName()))
return true;
}
return false;
}
I'd have a local boolean variable in service:
protected boolean mIsAppRunning;
Call startService() with true/false extra when app resumes/stops:
#Override
protected void onResume() {
super.onResume();
Intent service = new Intent("my.service.ACTION");
service.putExtra("IS_MY_ACTIVITY_RUNNING", true);
startService(service);
}
#Override
protected void onPause() {
Intent service = new Intent("my.service.ACTION");
service.putExtra("IS_MY_ACTIVITY_RUNNING", false);
startService(service);
}
Check that extra in service's onStartCommand() and assign its value to mIsAppRunning:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
mIsAppRunning = intent.getBooleanExtra("IS_MY_ACTIVITY_RUNNING", false);
}
return START_STICKY;
}
If you design the logic in the service a little carefully, you may even get rid of the local variable, mIsAppRunning, and call the required methods depending on the intent extra value.
Hope this helps.
Related
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.
PROBLEM
As topic mention, I don't know why getBooleanExtra() java.lang.NullPointerException.
I understand that sometimes intent may not contains extras.
However, from the below code as you can see there is a default value for each getBooleanExtra() which is false.
So, that's the reason why I don't understand. please advice. thx!
SOME CODE FROM MY SERVICE CLASS
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("onStartCommand()->","Intent Service.... " + intent);
final boolean SLEEP_MODE_ON = intent.getBooleanExtra("SLEEP_MODE_ON",false);
final boolean SLEEP_MODE_OFF = intent.getBooleanExtra("SLEEP_MODE_OFF",false);
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
connectIfNecessary();
if (SLEEP_MODE_ON){
doSleepMode_on();
} else if (SLEEP_MODE_OFF) {
doSleepMode_off();
}
}
});
thread.start();
return START_STICKY;
}
EDIT as some ask Where I call My service?? First, from activity. Second, from broadcastReceiver
ACTIVITY in onCreate()
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
startService(new Intent(this,mqttPushService.class)); //Setup MQTT Service
}//END of onCreate()
BroadcastReceiver
public class SleepModeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent sleepModeIntent;
int broadcastID = intent.getIntExtra("BROADCAST_ID",0);
switch (broadcastID) {
case DataManager.BROADCAST_ID_SLEEP_MODE_START :
sleepModeIntent = new Intent(context, mqttPushService.class);
sleepModeIntent.putExtra("SLEEP_MODE_ON",true);
context.startService(sleepModeIntent);
break;
case DataManager.BROADCAST_ID_SLEEP_MODE_STOP :
sleepModeIntent = new Intent(context, mqttPushService.class);
sleepModeIntent.putExtra("SLEEP_MODE_OFF",true);
context.startService(sleepModeIntent);
break;
}
}
}
I ran into this recently. The issue is that even services can be killed and restarted by the system , thats why you have START_STICKY. Unlike when you start the service and you pass a valid intent, when the system restarts the service, the intent is null. I just check for a null intent before trying to extract any extras.
Here is the link to the official android developers blog.
http://android-developers.blogspot.com/2010/02/service-api-changes-starting-with.html
and here is the paragraph which basically says what I say above
START_STICKY is basically the same as the previous behavior, where the service is left "started" and will later be restarted by the system. The only difference from previous versions of the platform is that it if it gets restarted because its process is killed, onStartCommand() will be called on the next instance of the service with a null Intent instead of not being called at all. Services that use this mode should always check for this case and deal with it appropriately.
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.
I'm android beginner so please be easy on me. I'm doing some "exercises" and i'm writing simple app which will tell RSSI strength of home wifi network. Getting that number is pretty easy, but updating it and showing that on screen it's a little more complicated as i thought.
First this is my onCreate Activity. In this activity i'm launching another android component - Service. Because the code will run in background (i know i could use thread or something else, but this is for "practice" sake, and i have a few ideas what to do with this app, while running service and not interacting with UI )
public class MainActivity extends Activity {
TextView wifi_check;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
referenceViews();
startService(new Intent(this, CheckingWifiService.class));
//wifi_check.setText(""+getIntent().getExtras().getInt("RSSI"));
}
private void referenceViews() {
wifi_check = (TextView) findViewById(R.id.wifiCheck_TV);
}
}
Because my code will run every second or so, i will use TimerTask for this purpose. And here is my TimerTask class, which includes run() method, and code for executing inside
public class TimerTsk extends TimerTask {
Context act;
WifiManager wifiMan;
WifiInfo info;
Bundle sendInfo;
Intent intent;
int rssi;
public TimerTsk(Context context) {
act = context;
}
#Override
public void run() {
intent = new Intent();
sendInfo = new Bundle();
wifiMan = (WifiManager) act.getSystemService(Activity.WIFI_SERVICE);
info = wifiMan.getConnectionInfo();
rssi = info.getRssi();
Log.d("WORKED", "RUNNING SUCESSFULLY");
// i want to send info to my activity
sendInfo.putInt("RSSI", rssi);
intent.putExtras(sendInfo);
}
}
From this class , i want to send result of RSSI to my activity and then update a text. But when i call this code below, on activity i always get NullPointerException.
wifi_check.setText(""+getIntent().getExtras().getInt("RSSI"));
To be honest i had hard time figuring out which part of code is throwing an exepction. And i found that more exactly, this part of code is throwing an exepction.
getInt("RSSI")
Overall i see that service is running, because in my LOGCAT i see a message that i create with Log.d in TimerTsk class.
Any ideas why is this happening?
Here is my service class:
public class CheckingWifiService extends Service{
int rssi;
Timer time;
TimerTsk ttsk;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
time = new Timer();
time.schedule(new TimerTsk(getApplicationContext()), 500);
return START_STICKY;
}
}
Here is my LogCat:
I see a common mistake. Don't do this:
sendInfo.putInt("RSSI", rssi);
intent.putExtras(sendInfo); // This adds a Bundle to your existing Bundle!
You are creating an Intent, with a Bundle of extras, with a Bundle that holds rssi. Leave out this unnecessary Bundle:
intent.putExtras("RSSI", rssi);
Now in your next Activity you can use:
getIntent().getIntExtra("RSSI", 0);
However you should always check to make sure there aren't any surprise null variables:
Intent in = getIntent();
if(in != null) {
int rssi = in.getIntExtra("RSSI", -1);
if(rssi < 0)
wifi_check.setText(""+rssi);
else
wifi_check.setText("Unknown");
}
is your activity starting? I don't see any call to startActivity(). In any case as mentioned by Sam you just need to call putExtra for your intent. don't forget to call
is your activity starting? I don't see any call to startActivity(). In any case as mentioned by Sam you just need to call putExtra for your intent. don't forget to call
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
you need to put this flag when start activies from background
UPDATE:
After adding the suggested methodes (doBindService() and doUnbindService()) along with calls to no avail) From here suggested by #Nick Campion
I've been trying for a while to get this service running but nothing seems to be working - I know I'm probably missing a semicolon or something :)
The program calls startNotificationService(), then the Log shows the log message... and the app continues to run without the Service showing up. I can't find the Service in Advance Task Killer. HELP!!!
XML (In Manifest) :
<service
android:icon="#drawable/icon"
android:label="Smart Spdate Service"
android:name="notifyService">
<intent-filter
android:label="FULL_PATH_NAME_HERE.updateService">
</intent-filter>
</service>
Service Call
Log.v("NOTICE", "Notification Service was not found running - starting");
//startService(new Intent(this, notifyService.class));
startService(new Intent(notifyService.class.getName()));
//startService(new Intent(TweetCollectorService.class.getName()));
/* FROM GOOGLE */
void doBindService() {
// Establish a connection with the service. We use an explicit
// class name because we want a specific service implementation that
// we know will be running in our own process (and thus won't be
// supporting component replacement by other applications).
this.bindService(new Intent(this, updateService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
/* END OF GOOGLE CODE */
#Override
public void onDestroy() {
web.close();
doUnbindService(); // Added to `onDestroy` - suggested by Google page
super.onDestroy();
Log.v("NOTICE", "PROGRAM TERMINATED");
}
updateService.java
public class updateService extends Service {
private String TAG = "SERVICE";
public static final int INTERVAL = 60000;
private Timer timer = new Timer();
private static updateService Pointer;
public updateService() {
Pointer = updateService.this;
}
public static class LocalBinder extends Binder {
static updateService getService() {
return Pointer;
}
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
if (timer != null) {
timer.cancel();
}
super.onDestroy();
}
#Override
public void onStart(Intent intent, int startId) {
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
doStuff();
}
}, 0, INTERVAL);
super.onStart(intent, startId);
}
public void doStuff() {
Log.v(TAG, "doStuff");
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final IBinder mBinder = new LocalBinder();
}
I don't see anywhere where your client binds to your service. Take a look at the local service example.. The reason for using the bind pattern even though you call startService is because the startService call is asynchronous. You need to make an additional call to bind the service to make sure you get a call back once the startup is complete.
I've found that a really great example of a service client and service are available in the NPR Open Source App for you to learn from!