I'm developing an app for Android that should receive some notifications via a protocol similar to MQTT from an Arduino device. This notification will be a sort of alarm and will not be continuous but it will be rare. The service will do a lite job: receive single notification, it registry in a sqlite database and sends a notification to system bar. What kind of background service I should use for API level 26 or higher. I know thet the system imposes restrictions on running background services
thanks
Luigi
/*Note: IntentService is a service, and is therefore subject to the new restrictions on background services. As a result, many apps that rely on IntentService do not work properly when targeting Android 8.0 or higher. For this reason, Android Support Library 26.0.0 introduces a new JobIntentService class, which provides the same functionality as IntentService but uses jobs instead of services when running on Android 8.0 or higher.*/
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.SystemClock;
import android.support.v4.app.JobIntentService;
import android.util.Log;
import android.widget.Toast;
/**
* Example implementation of a JobIntentService.
*/
public class SimpleJobIntentService extends JobIntentService {
/**
* Unique job ID for this service.
*/
static final int JOB_ID = 1000;
/**
* Convenience method for enqueuing work in to this service.
*/
static void enqueueWork(Context context, Intent work) {
enqueueWork(context, SimpleJobIntentService.class, JOB_ID, work);
}
#Override
protected void onHandleWork(Intent intent) {
// We have received work to do. The system or framework is already
// holding a wake lock for us at this point, so we can just go.
Log.i("SimpleJobIntentService", "Executing work: " + intent);
String label = intent.getStringExtra("label");
if (label == null) {
label = intent.toString();
}
toast("Executing: " + label);
for (int i = 0; i < 5; i++) {
Log.i("SimpleJobIntentService", "Running service " + (i + 1)
+ "/5 # " + SystemClock.elapsedRealtime());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
Log.i("SimpleJobIntentService", "Completed service # " + SystemClock.elapsedRealtime());
}
#Override
public void onDestroy() {
super.onDestroy();
toast("All work complete");
}
final Handler mHandler = new Handler();
// Helper for showing tests
void toast(final CharSequence text) {
mHandler.post(new Runnable() {
#Override public void run() {
Toast.makeText(SimpleJobIntentService.this, text, Toast.LENGTH_SHORT).show();
}
});
}
}
Related
Android Oreo has imposed many restrictions on running background service. Services now don't behave like normal in Oreo as they used to before.
But what if I have to run a service in background for long periods of time.
I am developing an application to launch the flashlight when user shakes the phone. To achieve this I will have to put the Sensor listener code inside a service.
How do I prevent android system to not kill the service.
PS: I don't want to start a foreground service with a notification.
How do I prevent android system to not kill the service.
To summarize the comments: Use a foreground service, with a notification on a dedicated channel, with the channel set to IMPORTANCE_DEFAULT. Advise the user that they can mute that channel (e.g., long-press on the Notification in the notification shade). Using a dedicated channel means that you can still raise notifications on other channels. Your notification should also be useful:
Have a "stop" action to stop your service, if the user wants to shut it down for a while
Tapping on the notification itself would lead to your activity for configuring your app's behavior
I don't want to start a foreground service with a notification.
Then most likely you cannot write your app.
I cannot rule out the possibility of some bug in Android 8.x that could be exploited to have an indefinite-duration service. In fact, I'd consider it to be fairly likely that there's something floating around out there. However, this is clearly against Google intentions, meaning:
Exploiting that technique, without what Google would consider to be valid justification, might get your app banned from the Play Store, if that was how you planned to distribute it
The bug might be fixed in a future version of Android, and getting in an arms race with Google tends to be a losing proposition
There are enough "air gesture" apps floating about (i.e., do things based on a shake) that, ideally, Google would add some dedicated low-power API for it. For example, they could add functionality to JobScheduler to allow you to register for a shake event and have your JobService be invoked in that circumstance, just as they allow you to register for changes in a ContentProvider. I have no idea whether they will ever offer such an API, but you could file a feature request for it, if you wanted.
Make a service unstoppable on Oreo or later without shown notification is possible (Yes We Can).
Let me to explain how make a service stoppable ONLY BY USER and not by system (or better to say THE ONLY WAY TO STOP THEM IS UNINSTALLING YOUR APP).
Note that even I make a service unstoppable in my point of view is not a good technique and I’m CONTRARY on that for different reasons (like battery consuming, clear user experience etc.)
First of all you need to declare the service in manifest file.
The separate name “:serviceNonStoppable” make the service running in a separate process and not in main app process. Is better for background processes which need to run separately.
To make our own service process invisible to other processes or apps you need to set exported=false parameter.
The description “#string/service_description” will say to users what your service do and why user should not stop them (you create this description in strings.xml).
<service
android:process=":serviceNonStoppable"
android:name="your.package.name.serviceOn"
android:exported="false"
android:description="#string/service_description" />
Secondly we go to create a support class with static methods usable in different points.
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import java.util.Map;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
class Utils {
// This is a support class witch have static methods to use everywhere
final static int NOTIFICATION_INT_CHANNEL_ID = 110211; // my daughter birthday but you can change that with your number
final static String NOTIFICATION_STRING_CHANNEL_ID = "put.a.random.id.here"; //if you write "the.pen.is.on.the.table" is the same
final static int TEST_THIS = 111; // or you can put here something else
final static String BROADCAST_MSG_ID = "BROADCAST_MSG_ID"; // or you can put here something else
final static String APP_MESSAGE = "your.package.name.action.APP_MESSAGE"; // or you can put here pippo.pluto.and.papperino
static void returnUpMyService(final Context context) {
try {
//to avoid crashes when this method is called by service (from itself) make sure the service is not alredy running (maybe is in cache)
if (killServiceIfRun(context)) {
startServiceOn(context);
}
} finally {
System.out.println(" I'm trying to start service ");
}
}
private static boolean killServiceIfRun(final Context context) {
boolean isRunning = isMyServiceRunning(context);
if (!isRunning) { return true; }
try {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
// maybe killing process is not terminated by system in this fase
//I force to kill them by my one
if (manager != null) {
manager.killBackgroundProcesses(getServicename(context));
return true;
}
return true;
} catch (Exception e) {
System.out.println("killServiceIfRun error: " + e.toString());
}
return false;
}
private static boolean isServiceInCache(final Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (manager != null && manager.getRunningAppProcesses() != null) {
if (manager.getRunningAppProcesses().size() > 0) {
for (ActivityManager.RunningAppProcessInfo process : manager.getRunningAppProcesses()) {
if (process.processName != null) {
if (process.processName.equalsIgnoreCase(getServicename(context))) {
// Here we know that the service is running but sleep brrrrrrrr
if (process.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE) {
return true;
}
}
}
}
}
}
return false;
}
static void StartMyService(Context context) {
// If the sevice is running doesn't need to restart
if (isMyServiceRunning(context) && !isServiceInCache(context)) {
return;
}
// If service is running but is in chache is the same like killed, so we need to kill them
if (isServiceInCache(context)) {
// this method at first kill and after that start the service
returnUpMyService(context);
} else {
//Otherwise we start own service
startServiceOn(context);
}
}
private static void startServiceOn(final Context context) {
// After we had been sure about that service doesn't exist
// we make a schedule to restart them
new ScheduledThreadPoolExecutor(1).schedule(() -> {
//Create an instance of serviceOn
serviceOn service = new serviceOn();
//prepare the launch intent
Intent launchIntent = new Intent(context, service.getClass());
// Now we start in background our service
context.startForegroundService(launchIntent);
// I put 50 ms to allow the system to take more time to execute GC on my killed service before
}, 50, TimeUnit.MILLISECONDS);
}
private static boolean isMyServiceRunning(final Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (manager != null && manager.getRunningAppProcesses() != null) {
if (manager.getRunningAppProcesses().size() > 0) {
for (ActivityManager.RunningAppProcessInfo process : manager.getRunningAppProcesses()) {
if (process != null && process.processName != null && process.processName.equalsIgnoreCase(getServicename(context))) {
return true;
}
}
}
}
return false;
}
static void SendMsgToService(Context context, int id, Map<String, Object> params) {
try {
Intent mServiceIntent = new Intent(APP_MESSAGE);
if (params != null) {
for (Map.Entry<String, Object> entry : params.entrySet()) {
//System.out.println(entry.getKey() + "/" + entry.getValue());
if (entry.getValue() instanceof String) {
mServiceIntent.putExtra(entry.getKey(), (String) entry.getValue());
} else if (entry.getValue() instanceof Integer) {
mServiceIntent.putExtra(entry.getKey(), (Integer) entry.getValue());
} else if (entry.getValue() instanceof Float) {
mServiceIntent.putExtra(entry.getKey(), (Float) entry.getValue());
} else if (entry.getValue() instanceof Double) {
mServiceIntent.putExtra(entry.getKey(), (Double) entry.getValue());
} else if (entry.getValue() instanceof byte[]) {
mServiceIntent.putExtra(entry.getKey(), (byte[]) entry.getValue());
}
}
}
mServiceIntent.putExtra(BROADCAST_MSG_ID, id);
context.sendBroadcast(mServiceIntent);
} catch (RuntimeException e) {
System.out.println(e.toString());
}
}
private static String getServicename(final Context context) {
// the name declared in manifest you remember?
return context.getPackageName() + ":serviceNonStoppable";
}
}
This is service class witch extend IntentService.
import android.app.IntentService;
import android.app.Notification;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class serviceOn extends IntentService {
// Needed to keep up notifying without show the icon
private ScheduledExecutorService notifyer = null;
// don't remove this. cause error becouse we declare this service in manifest
public serviceOn() {
super("put.a.constant.name.here");
}
// We need this class to capture messages from main activity
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, Intent intent) {
if (intent != null) {
if (intent.getAction() != null) {
if (intent.getAction().equals(Utils.APP_MESSAGE)) {
int msgID = intent.getIntExtra(Utils.BROADCAST_MSG_ID, -1);
switch (msgID) {
case Utils.TEST_THIS:
String message = intent.getStringExtra("message");
if (!TextUtils.isEmpty(message)) {
System.out.println(message);
}
//Do your task here
//Do your task here
//Do your task here
//Do your task here
break;
}
}
}
}
}
};
#Override
protected void onHandleIntent(#Nullable Intent intent) { }
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
try {
// First of all we need to register our receiver
List<String> actions = Arrays.asList(
Utils.APP_MESSAGE, // this is the string which identify our mesages
Intent.ACTION_SCREEN_ON, // this event is raised on sreen ON by system
Intent.ACTION_SCREEN_OFF, // this event is raised on screen OFF by system
Intent.ACTION_TIME_TICK);// this event is raised every minute by system (helpful for periodic tasks)
for (String curIntFilter : actions) {
IntentFilter filter = new IntentFilter(curIntFilter);
registerReceiver(broadcastReceiver, filter);
}
} catch (RuntimeException e) {
e.printStackTrace();
}
final Notification notificationDefault = new NotificationCompat.Builder(getApplicationContext(), Utils.NOTIFICATION_STRING_CHANNEL_ID)
.setOngoing(true) //Ongoing notifications do not have an 'X' close button, and are not affected by the "Clear all" button
.setCategory(Notification.CATEGORY_SERVICE) // indicate this service is running in background
.setSmallIcon(R.drawable.ic_radio) // put here a drawable from your drawables library
.setContentTitle("My Service") // Put here a title for the notification view on the top
// A smaller explanation witch system show to user this service is running
// in background (if existing other services from other apps in background)
.setContentText("My Service is unstoppable and need to run in background ")
.build();
// This is an efficient workaround to lie the system if we don't wont to show notification icon on top of the phone but a little aggressive
notifyer = Executors.newSingleThreadScheduledExecutor();
notifyer.scheduleAtFixedRate(() -> {
try {
// Here start the notification witch system need to permit this service to run and take this on.
// And we repeat that task every 15 seconds
startForeground(Utils.NOTIFICATION_INT_CHANNEL_ID, notificationDefault);
//immediately after the system know about our service and permit this to run
//at this point we remove that notification (note that is never shown before)
stopForeground(true);
//better not invoke Exception classes on error, make all a little heavy
} finally {
// Log here to tell you your code is called
System.out.println(" Service is running");
}
// So, the first call is after 1000 millisec, and successively is called every 15 seconds for infinite
}, 1000, 15000, TimeUnit.MILLISECONDS);
}
#Override
public void onDestroy() {
// unregister the receiver
unregisterReceiver(broadcastReceiver);
// stop the notifyer
if (notifyer != null) {
notifyer.shutdownNow();
notifyer = null;
System.out.println(" notifyer.shutdownNow() ");
}
final Context context = getBaseContext();
try {
new Thread() {
#Override
public void run() {
// The magic but dirty part
// When the system detect inactivity by our service decides to put them in cache or kill it
// Yes system you can kill me but I came up stronger than before
Utils.returnUpMyService(context);
}
}.start();
} finally {
System.out.println("You stop me LOL ");
}
}
}
And here the usage.
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import java.util.HashMap;
class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Sstart the first time
Utils.StartMyService(this);
// Test after 3 seconds
new Handler().postDelayed(() -> {
Utils.SendMsgToService(X_App.getContext(), Utils.TEST_THIS, new HashMap<String, Object>() {{
put("message", "Hello from main activity");
}});
}, 3000);
}
}
I discovered that we can run forground service without showing notification for android oreo and above, here is the solution first create notification with notification Channel also set channel id for notifications then start forground service with notification. now it's time to cancel notification Channel with id after 1 or 2 second that's means the notification will remove and the service will run alwayes . that's all
You would not be able to run background services long running in Oreo as there are behaviour changes, now Oreo to optimise system memory, battery etc, it kills background service, to solve your issue you should use foreground service.
Have a look at Background execution limits
https://developer.android.com/about/versions/oreo/android-8.0-changes
Hope this helps in understanding the issue....
As you know,
sendStickyBroadcast method is now deprecated. How to replace it?
Of course I can use sendBroadcast but then it will be not sticky.
You could use an event bus, the following are some of the most used libraries.
- https://github.com/greenrobot/EventBus
- http://square.github.io/otto/
- https://blog.kaush.co/2014/12/24/implementing-an-event-bus-with-rxjava-rxbus/ (how to use Rx as an event bus)
Another approach would be to create a class that listens to the broadcast and then stores the last state that it retrieved. In my opinion, this approach would not be ideal though.
Maybe one can use a JobScheduler to
schedule a periodic job,
which will send broadcasts.
The "keep alive" service, which will send periodoc broadcasts.
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.content.Intent;
import static my.UtilsLocation.PACKAGE_NAME;
/**
* JobService to be scheduled by the JobScheduler.
* start another service
*/
public class KeepAliveBroadcastJobService extends JobService {
public static final String INTENT_ACTION_KEEP_ALIVE = PACKAGE_NAME + ".action.KEEPALIVE";
#Override
public boolean onStartJob(JobParameters params) {
// send recurring broadcast
final Intent intent = new Intent(getApplicationContext());
intent.setAction(INTENT_ACTION_KEEP_ALIVE);
sendBroadcast(intent);
return false;
}
#Override
public boolean onStopJob(JobParameters params) {
return true;
}
}
A util, to periodically schedule the keep alive job.
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
import android.util.Log;
import java.util.concurrent.atomic.AtomicBoolean;
public class UtilsKeepAlive {
private static final String TAG = UtilsKeepAlive.class.toString();
private static AtomicBoolean isKeepAliveOn = new AtomicBoolean(false);
private static final int INTERVAL_MILLIS = 600000; // 10 min
private static final int FLEX_MILLIS = 60000; // 1 min
public static void enableKeepAlive(Context context) {
// if already on
if (isKeepAliveOn.get()) return;
Log.i(TAG, "Keep alive job scheduled");
ComponentName serviceComponent = new ComponentName(context, KeepAliveBroadcastJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); //Require any network
builder.setRequiresCharging(false);
builder.setPeriodic(INTERVAL_MILLIS, FLEX_MILLIS);
JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
jobScheduler.schedule(builder.build());
//we have scheduled the keep alive
isKeepAliveOn.set(true);
}
}
The periodic "keep alive" job - can be e.g. scheduled in a broadcast, on BOOT_COMPLETED.
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "BroadCastReceiver got the location.");
final String action = intent.getAction();
switch (action) {
case INTENT_ACTION_BOOT_COMPLETED:
Log.i(TAG, "Received a BootCompleted");
UtilsKeepAlive.enableKeepAlive(context);
break;
I have used this tutorial explaining the JobScheduler:
https://www.vogella.com/tutorials/AndroidTaskScheduling/article.html
This is Google's explanation to why Sticky Broadcasts was deprecated.
Sticky broadcasts should not be used. They provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. The recommended pattern is to use a non-sticky broadcast to report that something has changed, with another mechanism for apps to retrieve the current value whenever desired.
Hope this helps.
I have an Android application, which uploads data into web service using async tasks(P,Q,R) currently starting fired in button click. I have three tables(A,B,C) of data. Currently I upload Table A data in doInBackground in first async task(P), I call second async task(Q) in onPostExecute of first async task(P).In onPostExecute, I update my local tables with returned data and give some UI messages as well. while that functionality is existing, now I want to upload data in a fixed time interval(every 30 minutes) even though the application is closed. when the device is booting up/installing app/updating app, this process should be started.While uploading data, if the user opens the application, upload button should be disabled.I don't necessarily need a long running task that runs forever.
1.Do I need to use services instead async tasks?
and give me advice on this.
To Upload Data do as follow
I think you are pretty new to android, Rather than Asynctasks i think you should move to volley or retrofit which is very easy and very fast when compared to Asynctask
Do I need to use services instead async tasks
Since you need to upload data every 30 mins i suggest you move your code to a service within which you will upload data. Also since a service is used it will work when the app is closed also, as it runs in the background
Your Receiver class
import java.util.Timer;
import java.util.TimerTask;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class yourReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, Intent intent) {
int delay = 5000; // delay for 5 sec.5000
int period = 60000; // repeat every 1min.60000
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
Intent serviceIntent = new Intent(context,UploadService.class);
context.startService(serviceIntent);
}
}, delay, period);
}
}
Your Service Class
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.widget.Toast;
public class UploadService extends Service {
MediaPlayer myPlayer;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Service Created", Toast.LENGTH_LONG).show();
myPlayer = MediaPlayer.create(this, R.raw.sun);
myPlayer.setLooping(false); // Set looping
}
#Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
serviceThread = new ServiceThread();
serviceThread.start();
}
#Override
public void onDestroy() {
Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
myPlayer.stop();
}
private class ServiceThread extends Thread {
#Override
public void run() {
synchronized(UploadService.class){
if(uploadStatus) {
uploadStatus = false;
uploadData();
uploadStatus =true;
}
}
}
}
}
Does anyone know how can I check if there are any notifications programmatically in android?
I want to check if there is any notification currently available in the notifications list.
for example, if there is any notification, the LED light is turned on and if the notifications list is cleared, the LED light is turned off.
I just want to know the condition or the code that allow us to check if there are any notifications available in the notifications list.
if ( condition - there are any notifications )
// my code
You can use NotificationListener API, which is available on Android 4.3+. To do that you just simply need to create a simple Service that extends NotificationListenerService.
Here is some sample code
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
public class NLService extends NotificationListenerService {
private String TAG = this.getClass().getSimpleName();
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
Log.i(TAG, "Notification posted");
Log.i(TAG, "ID :" + sbn.getId() + "t" + sbn.getNotification().tickerText + "t" + sbn.getPackageName());
}
#Override
public void onNotificationRemoved(StatusBarNotification sbn) {
Log.i(TAG, "Notification Removed");
Log.i(TAG, "ID :" + sbn.getId() + "t" + sbn.getNotification().tickerText + "t" + sbn.getPackageName());
}
}
A complete tutorial is available here
Prior to this version of Android, you can make a hack through the AccessibilityService as described here
I am starting a service using startService(Intent intent) method. When i call this function it reaches the onCreate of service but it is unable to call onStartCommand. Here is my code--
#Override
public void onReceive(Context context, Intent intent) {
// Send a text notification to the screen.
Log.e("mudit", "Action: " + intent.getAction());
try {
ConnectivityManager connManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = connManager.getActiveNetworkInfo();
Log.e("mudit", "getType: " + info.getType());
Log.e("mudit", "isConnected: " + info.isConnected());
if (info.isConnected()) {
Intent newinIntent = new Intent(context, service.class);
context.startService(newinIntent);
}
} catch (Exception e) {
e.printStackTrace();
Intent newinIntent = new Intent(context, service.class);
context.stopService(newinIntent);
}
}
Service Code --
package com.android.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;
public class service extends Service {
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Service created...", Toast.LENGTH_LONG).show();
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service destroyed ...", Toast.LENGTH_LONG).show();
}
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "onStartCommand...", Toast.LENGTH_LONG).show();
return 1;
}
}
Manifest.xml --
<receiver class=".AReceiver" android:name=".AReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<service class=".service" android:name=".service"
android:enabled="true" android:icon="#drawable/icon">
</service>
Unbound Service: it runs in the background indefinitely even started activity with service ends also.
Bound Service : it will run till life time of activity.
Activity can start service via startService() and it will stop via stopService().
If activity wants to interact with service, it can use bindService().
First onCreate() is called, after onStartCommand is called with the intent data provided by the activity.
Source
larsVogel solves this problem (and many others like it) in this excellent post.
this is how i adapted his code to create a connectivity receiver that monitors when the user connects to a WIFI network so as to batch upload usage data:
in the Manifest file, place a receiver and declare a service right before the end tag for your < / application >:
<receiver android:name=".ConnMonitor" android:enabled="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<service android:name=".BatchUploadGpsData" ></service>
</application>
create a broadcast receiver class in a separate file called ConnMonitor.java (please uncomment the Log calls to be able to properly monitor the flow)
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
public class ConnMonitor extends BroadcastReceiver {
private String TAG = "TGtracker";
#Override
public void onReceive(Context context, Intent intent) {
//String typeName = "";
String state = "";
int type = -1;
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE );
NetworkInfo test = (NetworkInfo) connectivityManager.getActiveNetworkInfo();
//Log.v(TAG,"there has been a CONNECTION CHANGE -> "+intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO));
try {
//typeName = test.getTypeName().toString();
type = test.getType();
state = test.getState().toString();
//Log.i(TAG,"type -> '"+typeName +"' state -> '"+state+"'" );
} catch (Exception e) {
//typeName = "null";
type = -1;
state = "DISCONNECTED";
//Log.i(TAG,"type -> error1 "+e.getMessage()+ " cause = "+e.getCause() );
}
if ( (type == 1) && (state == "CONNECTED") ) {
//Log.i(TAG, "I am soooo friggin uploadin on this beautiful WIFI connection ");
Intent batchUploadDataService = new Intent(context, BatchUploadGpsData.class);
context.startService(batchUploadDataService);
} else {
//Log.e(TAG,"NO FOUND MATCH type -> '"+typeName +"' state -> '"+state+"'" );
}
}
}
and, finally, create a service BatchUploadGpsData.java like this:
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class BatchUploadGpsData extends Service {
final String TAG = "TGtracker";
#Override
public void onCreate() {
Log.e(TAG, "here i am, rockin like a hurricane. onCreate service");
// this service tries to upload and terminates itself whether it is successful or not
// but it only effectively DOES anything while it is created
// (therefore, you can call 1 million times if uploading isnt done, nothing happens)
// if you comment this next line, you will be able to see that it executes onCreate only the first it is called
// the reason i do this is that the broadcast receiver is called at least twice every time you have a new change of connectivity state with successful connection to wifi
this.stopSelf();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Log.i(TAG, "Received start id " + startId + ": " + intent);
Log.e(TAG, "call me redundant BABY! onStartCommand service");
// this service is NOT supposed to execute anything when it is called
// because it may be called inumerous times in repetition
// all of its action is in the onCreate - so as to force it to happen ONLY once
return 1;
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
this is not pseudocode, this is actual code, tested and running on android 2.2 and up.
the way to test this service is to shut down and restart your WIFI services on your android (powering off the wifi router will also do the trick). BUT this code does not verify if you are effectively connected to the net. for that, i recomend that you make an httpclient request and check out the result of the call. beyond the scope of this discussion.
NOTE: since services run on the same thread as the UI, i highly recommend that you implement the uploading proper on a separate thread or asynctask, depending your specific needs. you can also run the whole service on a separate thread, but that is once again not the scope of this discussion, despite being standard practice in these cases.
First you should add #Override before onStartCommand(..) then make sure that the target for the Android project is higher than 2.0 .
I believe, that you cannot access any UI components like Dialog or even a Toast in a service.
try this.
public int onStartCommand(Intent intent, int flags, int startId) {
/* Toast.makeText(this, "onStartCommand...", Toast.LENGTH_LONG).show();
return 1; */
Log.i("YourService", "Yes this works.");
}
First of all name your class to something else is my recommendation to avoid confusion down the line. Second here is an example of my manifest call of a service I have that works. I use full path names when calling services and such since they are not in the same package as my application.
<service android:name="com.public.service.UploaderService" android:icon="#drawable/vgbio"></service>
Here is the gist of my service class,
package com.public.service;
....
public class UploaderService extends Service{
....
}
Third make sure you use #Override to the onStartCommand().