0

I am using geofence in my app and based on geofence events (Enter or Exit) I want to perform some action. Geofence documentation says that once you set geofence it will trigger events automatically and you can catch this events with IntentService. For that I have made intentservice as below:

GeofenceTransitionsIntentService.java

public class GeofenceTransitionsIntentService extends IntentService {

    Handler mHandler;
    public GeofenceTransitionsIntentService() {
        super("GeofenceTransitionsIntentService");
        mHandler = new Handler();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("JK-->>","service started!");
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        Log.e("JK-->>","onHandel--->>");

        GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
        if (geofencingEvent.hasError()) {
            Log.e("JK-->>","geofenceEvent has error!");
            return;
        }

        int geofenceTransitionType = geofencingEvent.getGeofenceTransition();
        if (geofenceTransitionType == Geofence.GEOFENCE_TRANSITION_ENTER) {
            Log.e("JK-->>","enter!");
            mHandler.post(new DisplayToast(this,"Enter"));
        } else if (geofenceTransitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
            mHandler.post(new DisplayToast(this,"Exit"));
            Log.e("JK-->>","exit");
        }
    }

    public class DisplayToast implements Runnable {
        private final Context mContext;
        String mText;

        public DisplayToast(Context mContext, String text){
            this.mContext = mContext;
            mText = text;
        }

        public void run(){
            Toast.makeText(mContext, mText, Toast.LENGTH_SHORT).show();
        }
    }

}

Now, problem is that when app is open(No matter foreground or background) and I enter or exit in geofence it works fine and show me a toast message and logcat shows log but when I remove app from recent apps there is no toast message showing to me or no log is showing in logcat.

I have tried to find solution on google but mostly all answers suggests to use the service but if i am not wrong then IntentService stops itself automatically after work is done and start itself when any intent received. So, I think it's more efficient to use IntentService to do this task.

UPDATE I am registering geofence using following line of code.

geofencingClient.addGeofences(getGeofencingRequest(),getGeofencePendingIntent());

and in getGeofencePendingIntent() i am starting intent service using following line of code.

private PendingIntent getGeofencePendingIntent() {
        if(geofencePendingIntent != null)
            return geofencePendingIntent;
        Intent in = new Intent(SetProfileOnlineActivity.this,GeofenceTransitionsIntentService.class);
        geofencePendingIntent = PendingIntent.getService(SetProfileOnlineActivity.this,111451,in,PendingIntent.FLAG_UPDATE_CURRENT);
        return geofencePendingIntent;
    }
Jaydip Kalkani
  • 2,493
  • 6
  • 24
  • 56
  • 1
    How are you starting this `IntentService`. `IntentService` won't live forever once its task done it will stop . You might wanna take a look at `IntentService` Documentation . – ADM Mar 02 '18 at 05:33
  • Only Service can run in Background Indefinitely without being app running. Even if the app is stopped Service will not stop. But IntentService will stop once the Task in done or tif there are no new tasks incoming. – Akshay Mar 02 '18 at 05:36
  • look at updated question to see that how i am starting IntentService. @ADM – Jaydip Kalkani Mar 02 '18 at 05:39
  • As [this](https://stackoverflow.com/questions/15524280/service-vs-intentservice) answer says IntentService will stopped once task is done but it will start again when any intent is received. @akshay – Jaydip Kalkani Mar 02 '18 at 05:42
  • You have pass context as `SetProfileOnlineActivity.this` its an Activity isn't it ? So how is this context going to alive in background ? Am i missing something here ? – ADM Mar 02 '18 at 05:44
  • Yes, it's an activity. sorry for this question but please tell me what should i pass instead of 'SetProfileOnlineActivity.this' @ADM – Jaydip Kalkani Mar 02 '18 at 05:50
  • 1
    Well i am not much familiar with `Geofence` . I have gone through the documentation. And you code looks the same . So keep digging . Check it on other devices too. on different API level just to make sure . – ADM Mar 02 '18 at 05:55
  • Yep it will start once intent is received but if your app is not running at all, how can you send a Intent to IntentService() @ Jaydip Kalkani – Akshay Mar 02 '18 at 05:57
  • Is it not possible to send intent from outside app by changing context (SetprofileActivity.this)?? If it's not possible then please tell me what should i do for complete my task.@akshay – Jaydip Kalkani Mar 02 '18 at 05:59
  • I did not get you by stating "Outside App" Use this example https://stackoverflow.com/a/28535885/7156233 to get location updates. Use IntentService for GeoFencing, in case of locationChnage event call IntentService Service will run indefinitely in background and get the locationUpdates – Akshay Mar 02 '18 at 06:03
  • From "Outside app" i mean when app is closed from recent app. Let me try solution which you have given to me. Thanks for solution. @akshay – Jaydip Kalkani Mar 02 '18 at 06:07
  • 1
    You don't have any control over User. User might close the app any time. Use service with START_REDELIVER_INTENT it will restart the service even if it is stopped by system due to memory or resource allocation. – Akshay Mar 02 '18 at 06:17
  • Thanks for suggesting to test app on different APIs. From that i see that my app is working perfectly on all android APIs except Oreo. Till now i was testing my app on android oreo. it's not working in background in oreo because there is more bettery saving logic is implemented in android oreo as said in documentation. So, my problem is solved. thanks again. @ADM – Jaydip Kalkani Mar 02 '18 at 15:56
  • You got it buddy .. Sayonara. – ADM Mar 02 '18 at 15:58

3 Answers3

0

This Service will run always :


Goto project java -> right click->New->service->service name it watchman


watchman.java

public class watchman extends Service
{
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "1";


public watchman() { }

@Override
public void onCreate()
{

    try
    {
        mNotifyManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);

        mBuilder = new NotificationCompat.Builder(this, null);
        mBuilder.setContentTitle("Insta Promo")
                .setContentText("We are ready to help you.")
                .setSmallIcon(R.drawable.ic_launcher_background);



        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        {
            notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);

            // Configure the notification channel.
            notificationChannel.setDescription("Channel description");
            notificationChannel.enableLights(true);
            notificationChannel.setLightColor(Color.RED);
            notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
            notificationChannel.enableVibration(true);
            notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
            mNotifyManager.createNotificationChannel(notificationChannel);
        }
        else
        {
            mBuilder.setContentTitle("Insta Promo")
                    .setPriority(NotificationCompat.PRIORITY_HIGH)
                    .setColor(ContextCompat.getColor(this, R.color.colorAccent))
                    .setVibrate(new long[]{100, 250})
                    .setLights(Color.YELLOW, 500, 5000)
                    .setAutoCancel(true);
        }

        mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);

        mNotifyManager.notify(1, mBuilder.build());

        startForeground(1, mBuilder.build());

    }
    catch(Exception e)
    {
        Log.d(TAG, "EXCEPTION IN SHOWING NOTIFICATION xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...\n");
        Log.e("MY_APP", "exception", e);

    }

}

@Override
public int onStartCommand(Intent intent, int flags, int startId)
{

    new Thread(new Runnable()
    {

        public void run()
        {

            while (true)
            {
                try
                {
                    Log.d(TAG, "Thread : Running again...\n");

                    Thread.sleep(10000);
                }
                catch (InterruptedException e)
                {
                    Log.d(TAG, "Thread : InterruptedException Error in service...\n");
                }

            }


        }

    }).start();
    return START_STICKY;

}

@Override
public void onDestroy()
{
    super.onDestroy();
}

@Override
public IBinder onBind(Intent intent)
{
    // TODO: Return the communication channel to the service.
    throw new UnsupportedOperationException("Not yet implemented");
}

}

It will get automatically registered in manifest file as you created it as service, no need to update manifest file.


From main activity or from wherever you want to start it call it like

    Log.d(TAG, " Good to Go \n");
    Log.d(TAG, "Starting Service from main...\n");
    Intent intent = new Intent(MainActivity.this, watchman.class);
    startService(intent);
    Log.d(TAG, "Main has started the service...\n");

Now you even if removed it from recents..., It will be there in memory running always for you, To check it keep eye on logcat. Hope it helps. Its working in project from 4.1 onwards upto latest 8.0 oreo


for showing notifications i am using vibration permission so also making manifest file available for you.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.rushi.oreo">


<uses-permission android:name="android.permission.VIBRATE"/>

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <service
        android:name=".watchman"
        android:enabled="true"
        android:exported="true" />


</application>

</manifest>

Hope it really helps you or someone else.

  • If you want this always running service to come in background without opening app on every rebbot or startup, then only you will need receiver class and update manifest to receive on boot complete. If you want this too let me know here. –  Mar 02 '18 at 06:47
  • Also let me know what happens when you use this, i will guide you until it works as you intended. Actually its working code and it should work. But let me know so that i can help –  Mar 02 '18 at 06:48
  • I will recommend create a new blank project with blank activity and use these instructions to make it work. Once you get it working your idea will be clear and you can then implement in your project as per your need. –  Mar 02 '18 at 06:51
0
  1. IntentService will stop automatically when the work assigned to it is finished.
  2. If you want a service to run in background with very less chances of getting stopped, it has to be a Foreground Service. Please make sure to start your Service in a background worker thread because by default a Service runs on the main thread.

More details are here - https://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification)

But please note that making a Service as foreground impacts your phone's battery life too much. And a making a Service as Foreground is also annoying to the user since it shows a notification always and cannot be closed.

You can better use a JobScheduler or Firebase JobDispatcher to schedule background works.

Asutosh Panda
  • 1,463
  • 2
  • 13
  • 25
0

I had found an answer... there was no problem in my code and IntentService was also working perfectly but the mistake was in the testing. I was testing my application on android Oreo running device.

In android oreo google has updated their policy that in foreground they will send location updates any number of times but in background they will send location updates only few times in hour. The main reason behind it to save the bettery life of device.

For more information about android oreo location updates you can check out this documentation.

Jaydip Kalkani
  • 2,493
  • 6
  • 24
  • 56