2

I am writing an app to tracking the route history on Google map. It will get current location of the device every 5 minutes and send data to server via webservice.

This code to call the BroadcastReceiver from MainActivity

manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
intent.putExtra("USERNAME", mUsername);
intent.putExtra("DB_NAME", mDBName);
intent.putExtra("DB_IP", mDBIP);
intent.putExtra("DB_USER", mDBUsername);
intent.putExtra("DB_PASS", mDBPassword);
intent.putExtra("SERVER_IP", mServerIP);

mAlarmIntent = PendingIntent.getActivity(getApplicationContext(), REQUEST_CODE, intent, 0);
int mTimeRepeat = 300 * 1000;   // repeat every 5 minutes
int mTimeStart = 5 * 1000;

manager.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + mTimeStart, mTimeRepeat, mAlarmIntent);

In BroadcastReceiver, I get the lat-long and invoke webservice.

public class AlarmReceiver extends BroadcastReceiver {
private static final String TAG = "Alarm Receiver";

private String mUsername = "";
private String mDBName = "";
private String mDBIP = "";
private String mDBUsername = "";
private String mDBPassword = "";
private String mServerIP = "";

private Context context;
private static AsyncHttpClient sClient = new AsyncHttpClient();

@Override
public void onReceive(final Context context, Intent intent) {
    this.context = context;

    mUsername = intent.getStringExtra("USERNAME");
    mDBIP = intent.getStringExtra("DB_IP");
    mDBName = intent.getStringExtra("DB_NAME");
    mDBUsername = intent.getStringExtra("DB_USER");
    mDBPassword = intent.getStringExtra("DB_PASS");
    mServerIP = intent.getStringExtra("SERVER_IP");

    if (Utility.checkLocationPermission(context)) {
        try {
          GPSTracker mGPS = new GPSTracker(context);
          // check if GPS enabled
          if (mGPS.canGetLocation()) {
          double latitude = mGPS.getLatitude();
          double longitude = mGPS.getLongitude();

          // more code here

Problem is the app works fine when I keep my phone awake, if the phone sleep, it didn't work. I want this send data even when the phone sleep, how can I do that ?

Jacky
  • 133
  • 1
  • 13
  • Try to use flag `AlarmManager.ELAPSED_REALTIME_WAKEUP` – Stanislav Bondar Aug 10 '17 at 06:56
  • Since Marshmallow, you should implement your app in such a way that it works compatibly with doze mode. https://developer.android.com/training/monitoring-device-state/doze-standby.html Check also https://stackoverflow.com/a/35657522/1196752 – Vektor88 Aug 10 '17 at 06:57
  • AlarmManager is outdated and not working in devices higher than 21 use Job scheduler instead – Shashwat Gupta Aug 10 '17 at 07:13

4 Answers4

1

To achieve this requirement better you use JobScheduler API.

AlarmManager is outdated.

Advantages of using JobScheduler :

  1. On device restart you don't need to receive the OnBootComplete action to restart the service
  2. U can stop service temporarily when device battery is low to avoid bad user experience.
  3. Best way to sync the data from device to server in background.

I tested it is working fine.For more info check below links.

For reference please go through below links :

http://www.vogella.com/tutorials/AndroidTaskScheduling/article.html#schedulingtasks

https://developer.android.com/reference/android/app/job/JobScheduler.html

If anything is unclear please let me know will share working sample and let me know if it helps.

Use below working sample :

  public class PollingService extends JobService {

    @Override
    public boolean onStartJob(JobParameters params) {
        Log.d("PollingService", "onStartJob in PollingService is called");
        jobFinished(params, false);
        return false;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        Log.d("PollingService", "onStopJob in PollingService is called");
        return false;
    }
}

Register in Manifest :

<service
            android:name=".Services.PollingService"
            android:exported="true"
            android:permission="android.permission.BIND_JOB_SERVICE" />

Use below code in Activity to start service :

    //put this in oncreate of Activity or from where u want to start
        JobScheduler mJobScheduler = JobScheduler.getInstance(getApplicationContext());  

    buidJob(); //Method call 

   //Method
    private void buidJob() {
            JobInfo.Builder jobinfo = new JobInfo.Builder(100,new ComponentName(this,PollingService.class));
            jobinfo.setPeriodic(50*1000).
                    setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED).
                    setPersisted(true);
            //build();

            mJobScheduler.schedule(jobinfo.build());
            Log.d(TAG,"buidJob()");
        }

Dependencies :

 compile 'me.tatarka.support:jobscheduler:0.1.1'

To support lower end version used above aar. You can do it with out using above aar if we follow above mentioned links.

Jeelan
  • 173
  • 1
  • 11
  • thanks for your reference links, but it still not run when my phone sleep. Don't know that's because the service not called or something wrong with my params data, I generated the .apk and run it on my phone, so I cannot track the log. – Jacky Aug 10 '17 at 10:00
  • Use above posted code.Tested while device is in sleep mode it is working and it works on device reboot also.Time mentioned is (50*1000) is here u can reduce the time for testing.Note : Better u test it on unRooted devices becoz i noticed some problem with Rooted devices. – Jeelan Aug 10 '17 at 10:41
  • I tried your above code, but it didn't jump to onStartJob. – Jacky Aug 11 '17 at 04:38
  • Hope this link will help u : https://github.com/evant/JobSchedulerCompat. Recommended one is above mentioned links.Happy coding. – Jeelan Aug 11 '17 at 09:41
  • Is it working?Please let me know if your facing any problem. – Jeelan Aug 11 '17 at 11:06
  • I tested on my Asus Zenfone 3 Max, run android 7.1.1 and I realized minimum time periodic is 15 minutes, cannot set the timer shorter than this. Another thing, when I plugged in my phone to my laptop via cable to run debug, it works fine (repeat after every 15 minutes), but when I build apk release, and run (not plugged in my phone), it didn't work. – Jacky Aug 14 '17 at 02:14
  • Is your phone Asus Zenfone 3 Max is routed? Which one you implemented? compile 'me.tatarka.support:jobscheduler:0.1.1' or from links which i provided?Can you please uninstall and reinstall the apk of release and better u restart once try again. Becuase the answer is here https://stackoverflow.com/questions/29653885/android-jobscheduler-cant-create-a-persistent-job – Jeelan Aug 14 '17 at 06:14
  • I compile 'me.tatarka.support:jobscheduler:0.1.1' and use your code above. I modified setPeriodic (30*1000) for 30 seconds repeat, but it repeated after 15 minutes. – Jacky Aug 14 '17 at 08:01
  • I set to (5*1000) which is 5 secs it took 50 secs to complete one poll, i think there is a problem with timings it seems.Can you please try by setting (3*1000) it should take 30 sec for one polls.Let me know if this solves ur problem. – Jeelan Aug 14 '17 at 13:42
  • Which android version you use to test? I set to 3*1000 and it stills took 15 minutes to repeat. – Jacky Aug 15 '17 at 06:35
  • But that's ok, repeating time is not a big problem here. Problem is it didn't repeat when my phone sleep :( – Jacky Aug 15 '17 at 06:44
  • finally I think I found the reason, android automatically kill my app when it run on background to optimise battery performance. Remove the app from optimised list and it works. My stupid mistakes, thank you for your time, buddy. – Jacky Aug 15 '17 at 07:41
0

There were lots of behavior changes in Android 8.0 (O), we all should acknowledge about these issues here >> What's new in Android 8.0 ?

Check if you're targeting API Level 26 or not (I think you are)
app > build.gradle > targetSdkVersion

If then, I think you should check this link >> Background location limits

John Lee
  • 80
  • 10
0

Use WakeLock, A wakelock is a mechanism to indicate that your application needs to have the device stay on.

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

Note: wakelock will keep device on only for the duration of onRecieve method. If you want to keep the device one for long period this library may help

Amitabh Sarkar
  • 1,281
  • 1
  • 13
  • 26
0

use AlarmManager.ELAPSED_REALTIME_WAKEUP and use these condition for set alarm

if(Build.VERSION.SDK_INT < 23){
    if(Build.VERSION.SDK_INT >= 19){
        setExact(...);
    }
    else{
        set(...);
    }
}
else{
    setExactAndAllowWhileIdle(...);
}

and in broadcast receiver set next alarm to fire

Bipin Gawand
  • 521
  • 1
  • 6
  • 17