0

I created service and firebase job service too. They work perfectly when app is closed. I want get user's location every minute and send to server when app is closed This is my jobservice:

class NeverEndingJob : JobService() {

var counter = 0
var TAG = "NeverEndingJOb"


private val NOTIFICATION_ID = 404
private val CHANNEL_ID = "AppC"
internal var name: CharSequence = "AppC"
internal var importance: Int = 0
internal var mChannel: NotificationChannel? = null
internal var mNotificationManager: NotificationManager? = null




private var mLocationManager: LocationManager? = null
private var owner: ICapture? = null

var model :MyRestModel? = null
var notificationManager: NotificationManagerCompat? = null
private var mLocationListeners = arrayOf(LocationListener(LocationManager.GPS_PROVIDER), LocationListener(LocationManager.NETWORK_PROVIDER))


init {
    MLog.d(TAG,"job created")
}

override fun onCreate() {
    super.onCreate()
    mNotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        importance = NotificationManager.IMPORTANCE_MIN
        mChannel = NotificationChannel(CHANNEL_ID, name, importance)
        mNotificationManager!!.createNotificationChannel(mChannel)
    }

}
override fun onStopJob(job: JobParameters?): Boolean {

    MLog.d(TAG,"job destroy")
    val intent = Intent("app.name.RestartService")
    sendBroadcast(intent)
    stopTimer()
    return true
}

override fun onStartJob(job: JobParameters?): Boolean {
    mNotificationManager!!.notify(NOTIFICATION_ID, getNotification(R.string.working.getResource()))

    startForeground(NOTIFICATION_ID, getNotification(R.string.working.getResource()))

    startTimer()



    return true
}


private var timer: Timer? = null
private var timerTask: TimerTask? = null
var oldTime: Long = 0

companion object {


    private val TAG = "AppC"
    private var LOCATION_INTERVAL:Long = 0
    private var LOCATION_DISTANCE = 10f
}




private fun startTimer(){
    timer = Timer()


    initializeTimerTask()



    val apiService = ApiService(Handler())
    App.courInfo = Prefs.instance(App.preferences).getCourierLocInfo()

    notificationManager = NotificationManagerCompat.from(this);


    model = MyRestModel(apiService)
    model!!.apiCallback = ApiCallback()


    Log.e(TAG, "onCreate")
    initializeLocationManager()
    setLocationUpdates()



    timer!!.schedule(timerTask, NeverEndingJob.LOCATION_INTERVAL, NeverEndingJob.LOCATION_INTERVAL) //
}

internal var mLastLocation: Location  =Location(LocationManager.NETWORK_PROVIDER)

fun initializeTimerTask() {
    timerTask = object : TimerTask() {
        override fun run() {






            Handler(Looper.getMainLooper()).post {
                setLocationUpdates()
            }

        }

    }
}



private fun stopTimer(){
    if (timer != null) {
        timer?.cancel();
        timer = null;
    }
}

private fun getNotification(title : String): Notification {

    Log.d(TAG, "create notofication")

    val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        NotificationCompat.Builder(this, CHANNEL_ID)
    else
        NotificationCompat.Builder(this)

    builder.setSmallIcon(R.mipmap.ic_launcher)
            .setWhen(0)
    builder.setContentTitle(title)


                  .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher, null))

    val not: Notification
    not = builder.setOngoing(true).build()


    return not
}




private inner class LocationListener(provider: String) : android.location.LocationListener {


    init {
        Log.e(TAG, "LocationListener $provider")
        mLastLocation = Location(provider)
    }

    override fun onLocationChanged(location: Location) {
        Log.e(TAG, "onLocationChanged: $location")
        try{




            val distance = location.distanceTo(mLastLocation)

            mNotificationManager!!.notify(NOTIFICATION_ID, getNotification("${R.string.get_location.getResource()} Метр: ${distance.toInt()}"))

            Handler().postDelayed({
                mNotificationManager!!.notify(NOTIFICATION_ID, getNotification(R.string.working.getResource()))
            },3000)
            Log.e(TAG,"distance"+ "$distance")
            if (distance > 10){
                mLastLocation = location
                sendLocation(mLastLocation)
            }


               Prefs.instance(App.preferences).setLastLocate(location)





          Prefs.instance(App.preferences).setLastLocate(location)





        }catch (e :java.lang.Exception){
            Log.e(TAG, "send http lat lon exception: $e")

        }

        mLastLocation.set(location)
    }

    override fun onProviderDisabled(provider: String) {
        Log.e(TAG, "onProviderDisabled: $provider")
    }

    override fun onProviderEnabled(provider: String) {
        Log.e(TAG, "onProviderEnabled: $provider")
    }

    override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {
        Log.e(TAG, "onStatusChanged: $provider")
    }
}



fun sendLocation(location : Location){
    Log.e(TAG, "ready for send http lat lon $location ")


    val currentTime = Functions.calculateDifference(System.currentTimeMillis())
    Log.e(TAG, "get current time $currentTime ")



    if (App.courInfo != null){
        Log.e(TAG, "get open time ${App.courInfo!!.startTime} ")
        Log.e(TAG, "get close time ${App.courInfo!!.endTime} ")


        val startTime = App.courInfo!!.startTime
        val endTime = App.courInfo!!.endTime

        val isHourLess =currentTime.hour.toInt() > startTime.hour.toInt()
        val isHourLessEqual =currentTime.hour.toInt() == startTime.hour.toInt()
        val isMinLess = currentTime.minute.toInt() >= startTime.minute.toInt()


        val isHourMore =currentTime.hour.toInt() < endTime.hour.toInt()
        val isHourMoreEqual =currentTime.hour.toInt() == endTime.hour.toInt()
        val isMinMore = currentTime.minute.toInt() <= endTime.minute.toInt()



        if (isHourLess && isHourMore){
            if (model != null){
                model!!.setLocation(App.userData!!.phone, App.userData!!.token, App.userData!!.cId,location.latitude.toString(),location.longitude.toString())
            }

        }else if (isHourLessEqual && isHourMore){

            if (isMinLess){
                if (model != null){
                    model!!.setLocation(App.userData!!.phone, App.userData!!.token, App.userData!!.cId,location.latitude.toString(),location.longitude.toString())

                }
            }
        }else if (isHourLess && isHourMoreEqual){
            if (isMinMore){
                if (model != null){
                    model!!.setLocation(App.userData!!.phone, App.userData!!.token, App.userData!!.cId,location.latitude.toString(),location.longitude.toString())

                }
            }
        }



    }
}

private fun initializeLocationManager() {
    Log.e(TAG, "initializeLocationManager")

        mLocationManager = applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager

}
fun setLocationUpdates(){
    try {
        val locInfo = Prefs.instance(App.preferences).getCourierLocInfo()
        if (locInfo != null){

            NeverEndingJob.LOCATION_INTERVAL = 3000
            NeverEndingJob.LOCATION_DISTANCE = locInfo.metres.toFloat()
        }
        Log.e(TAG, "onCreate $locInfo")



        mLocationManager!!.requestLocationUpdates(
                LocationManager.NETWORK_PROVIDER, 1000, 0.toFloat(),
                mLocationListeners[1])
    } catch (ex: java.lang.SecurityException) {
        Log.i(TAG, "fail to request location update, ignore", ex)
    } catch (ex: IllegalArgumentException) {
        Log.d(TAG, "network provider does not exist, " + ex.message)
    }


}

inner class ApiCallback : ApiService.Callback{
    override fun onSuccess(result: String) {

        mNotificationManager!!.notify(NOTIFICATION_ID, getNotification(R.string.success_sended.getResource()))
        Handler().postDelayed({
            mNotificationManager!!.notify(NOTIFICATION_ID, getNotification(R.string.working.getResource()))
        },3000)

notificationManager!!.notify(1,mBuilder.build()) }

    override fun onFail(failure: String) {
        Log.e(TAG, "onFail $failure")

    }

}



fun clearLocationListeners(){
    if (mLocationManager != null) {
        for (i in mLocationListeners.indices) {
            try {
                mLocationManager!!.removeUpdates(mLocationListeners[i])
            } catch (ex: Exception) {
                Log.i(NeverEndingJob.TAG, "fail to remove location listners, ignore", ex)
            }

        }
    }
}

}

This code work perfectly when app is opened, send every time location to server, but when I close the app, service works every minute says me you should get location but onLocationChanged not called:

timerTask = object : TimerTask() {
        override fun run() {

            Handler(Looper.getMainLooper()).post {
                setLocationUpdates()
            }

        }

    }

Manifest:

<service
        android:name=".service.NeverEndingJob"
        android:enabled="true">
        <!--<intent-filter>-->
        <!--<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE"/>-->
        <!--</intent-filter>-->
    </service>
    <receiver
        android:name=".service.RestartService"

        android:enabled="true"
        android:exported="true"
        android:label="RestartServiceWhenStopped">
        <intent-filter>
            <action android:name="app.name.RestartService" />
            <action android:name="android.net.wifi.STATE_CHANGE" />
            <!--<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />-->
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>

Receiver

class RestartService : BroadcastReceiver() {
var TAG = "RestartService"
override fun onReceive(p0: Context?, p1: Intent?) {
    MLog.d(TAG,"service stopppedd")


    val dispatcher = FirebaseJobDispatcher(GooglePlayDriver(p0))
    val job = dispatcher
            .newJobBuilder()
            .setService(NeverEndingJob::class.java)
            .setTag("AppC-Bg-Job")
            .setRecurring(false)
            .setLifetime(Lifetime.FOREVER)
            .setTrigger(Trigger.executionWindow(0,0))
            .setReplaceCurrent(false)
            .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
            .setConstraints(Constraint.ON_ANY_NETWORK)
            .build()

    dispatcher.mustSchedule(job)
}

}

Activity:

lateinit var dispatcher: FirebaseJobDispatcher

private fun startLocationService() {




     dispatcher = FirebaseJobDispatcher(GooglePlayDriver(this))
    val job = dispatcher
            .newJobBuilder()
            .setService(NeverEndingJob::class.java)
            .setTag("Bringo-Couirer-Bg-Job")
            .setRecurring(false)
            .setLifetime(Lifetime.FOREVER)
            .setTrigger(Trigger.executionWindow(0, 0))
            .setReplaceCurrent(false)
            .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
            .setConstraints(Constraint.ON_ANY_NETWORK)
            .build()

    dispatcher.mustSchedule(job)


}




override fun onDestroy() {
    super.onDestroy()

    dispatcher.cancelAll()
}

Why onLocationChanged not called after few minutes when app is closed in alive service?

1 Answers1

0

I think you need to use the Location Manager.

LocationManager locationManager = (LocationManager) 
getSystemService(Context.LOCATION_SERVICE); 

locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER,
            2000,   
            10, this);

the first parameters is the provider you are using (in this case the GPS Provider). The second parameter (2000) is the minimum time in milliseconds between each update. The third parameter (10) is the minimum distance. The last parameters is your LocationListener (this).

It is also a good idea to implement onProviderDisabled in case the user has his GPS turned off.

override this method in ur service

public void onTaskRemoved(Intent rootIntent) {

    super.onTaskRemoved(rootIntent);

    Utils.showLog("onTaskedremoved called");

    PendingIntent service = PendingIntent.getService(
            getApplicationContext(),
            1001,
            new Intent(getApplicationContext(), ''your service name''.class),
            PendingIntent.FLAG_ONE_SHOT);

    AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
}
  • dispatcher.cancelAll() remove this from onDestroy –  Jun 14 '18 at 12:17
  • After 1 minute again not called onLocationChanged method when app is closed – Muhammadjon Xasanov Jun 14 '18 at 12:18
  • if I remove cancelAll() method how I can call onStopJob for sendBroadCast and call again jobservice – Muhammadjon Xasanov Jun 14 '18 at 12:20
  • Is the service running and only the onLocationChanged() not called. Firstly check if the service is running? If not running then give the permission to run in background. This usually happens with custom OS phones like Xiaomi and all. In the security app go to permissions and enable all permissions required by app. – Amit Mishra Jun 14 '18 at 12:56
  • Amit Mishra, yes Service is running but only the onLocationChanged not called when app minimize or closed – Muhammadjon Xasanov Jun 14 '18 at 13:28
  • i have updated the answer please try this one, may be help you @MuhammadjonXasanov –  Jun 15 '18 at 04:51