We have been working on developing service for android platform.
In our service we need to send GPS data (Lat and Long) of device to some external REST service after every one minute.
It is running fine for almost 15 minutes after locking of device. But after that it does not send any data.
After unlocking the device, it start again to send data over REST service.
My Code So far
public class MainActivity extends AppCompatActivity {
private PendingIntent pendingIntent;
private PowerManager.WakeLock wakeLock;
public static final String USER_NAME = "USERNAME";
String username;
String password;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent alarm = new Intent(this, AlarmReceiver.class);
boolean alarmRunning = (PendingIntent.getBroadcast(this, 0, alarm, PendingIntent.FLAG_NO_CREATE) != null);
if(alarmRunning == false) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarm, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), 30000, pendingIntent);
}
PowerManager mgr = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakeLock");
wakeLock.acquire();
}
public class BackgroundService extends Service {
private boolean isRunning;
private Context context;
private Thread backgroundThread;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
this.context = this;
this.isRunning = false;
this.backgroundThread = new Thread(myTask);
}
private Runnable myTask = new Runnable() {
public void run() {
// Do something here
login("admin","admin");
stopSelf();
}
};
@Override
public void onDestroy() {
this.isRunning = false;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(!this.isRunning) {
this.isRunning = true;
this.backgroundThread.start();
}
return START_STICKY;
}
private void login(final String strLatitude, final String strLongitude) {
class LoginAsync extends AsyncTask<String, Void, String> {
String charset = "UTF-8";
HttpURLConnection conn;
DataOutputStream wr;
StringBuilder result = new StringBuilder();
URL urlObj;
JSONObject jObj = null;
StringBuilder sbParams;
String paramsString;
@Override
protected void onPreExecute() {
super.onPreExecute();
// loadingDialog = ProgressDialog.show(MainActivity.this, "Please wait", "Loading...");
}
@Override
protected String doInBackground(String... params) {
String uname = params[0];
String pass = params[1];
sbParams = new StringBuilder();
try {
sbParams.append("name").append("=")
.append(URLEncoder.encode(uname, charset));
sbParams.append("&");
sbParams.append("password").append("=")
.append(URLEncoder.encode(pass, charset));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
String url="http://192.168.0.122:1234/YegoService.svc/AddVehicleMovement";
URL object=new URL(url);
HttpURLConnection con = (HttpURLConnection) object.openConnection();
con.setDoOutput(true);
con.setDoInput(true);
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
con.setRequestMethod("POST");
JSONObject parent = new JSONObject();
parent.put("strValidatorID","111");
parent.put("TXT_LAT", "28.25252525");
parent.put("TXT_LONG", "77.7777777");
parent.put("DAT_DATE", "");
con.connect();
OutputStreamWriter wr = new OutputStreamWriter(con.getOutputStream());
wr.write(parent.toString());
wr.flush();
wr.close();
InputStream input = con.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
con.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
catch (Exception ex) {
ex.printStackTrace();
}
return result.toString();
}
@Override
protected void onPostExecute(String result){
String s = result.trim();
}
}
LoginAsync la = new LoginAsync();
la.execute("admin", "admin");
}
}
public class AlarmReceiver extends BroadcastReceiver {
String strLatitude;
String strLongitude;
@Override
public void onReceive(Context context, Intent intent) {
Intent background = new Intent(context, BackgroundService.class);
context.startService(background);
}
}
What to do?
One approach could be for you to rely on the AlarmManager : once you subscribe to an AlarmManager the system itself runs your code at the interval you setup, even if your app is not active. Each time it runs you can decide to process some code... So you completely avoid the need to keep a service alive.
What you need is an Alarm class that will handle the AlarmManager intent.
Create your Alarm :
In your Manifest declare this Alarm BroadcastReceiver
And from where you want in your Activity call this AlarmManager !
This is the main idea. Now you need to deal with screen on or off. For this 2 solutions : you can register for the device screen state intent and manage the AlarmManager on/off... or you can let the AlarmManager always running but checking if the device is on/off before sending data...
Hope this will help !
I had the same problem in my app but i solved my issue first create service, use Periodic service. you are able to specify time limit for updating the data. In my case this was the code.
UpdateService.java
and Main.java
Because i have return
in
onStartCommand(...)
read more at START_STICKY and START_NOT_STICKY
and Official docs
MyService.java
to run the service, add this to your Activity,
If you run your app on API 21+, using JobScheduler which is described in Google documentation is also a best approach.
Also, if you don't want to change your code structure, you can use your service to keep the CPU ON even if screen is off. Read how to keep CPU On from Google Documentation. Just add permission in your manifest
<uses-permission android:name="android.permission.WAKE_LOCK" />
and in yourService.onCreate
, put :And release in
Service.onDestroy
withwakelock.release()
. But be aware that it drains your battery. But if you said that the device will be always plugged in a source power, I think it will not be a problem. Just in case, it will be better to have an admin UI in the app to stop the service manually.Yes you can implement a background service that it will almost never be killed. But you have to declare it to run in the foreground. you can see what Android Developer site says, by referring to this url(http://developer.android.com/guide/components/services.html) also in this article (http://developer.android.com/guide/components/processes-and-threads.html) they say,
There are five levels in the importance hierarchy and the different types of processes in order of importance (the first process is most important and is killed last):
A process that is required for what the user is currently doing. A process is considered to be in the foreground if any of the following conditions are true:
Generally, only a few foreground processes exist at any given time. They are killed only as a last resort—if memory is so low that they cannot all continue to run. Generally, at that point, the device has reached a memory paging state, so killing some foreground processes is required to keep the user interface responsive.
So you have to start your service in the foreground. In order to do this you have implement the service as below.
Thanks and gud luck..
You are acquiring the wake lock in your
Activity
. The problem here is that when the device is locked, yourActivity
gets pushed to the background. After 15 minutes of inactivity, Android is simply killing the process. This releases the wake lock. The device goes to sleep.Now, the next time your alarm goes off, the device wakes up, your
BroadcastReceiver
is triggered,onReceive()
is called, it starts yourService
, but then the device goes back to sleep because there is no wake lock, so the `Service doesn't do anything.Another approach, if you want to prevent the phone from going to sleep while your app is running, would be to acquire the wake lock in the
Service
. In this case, you don't want to callstopSelf()
every time yourRunnable
runs. You would want to keep yourService
running until you want to stop it, at which time you would callstopService()
. This way, theService
would always be active (even though it isn't doing anything) and it would prevent the device from sleeping through the wake lock. This may, however, put an unacceptable drain on the battery (you'll have to test it).You need to acquire the wake lock in the
BroadcastReceiver
and make sure that theService
gets started and acquires a wake lock before the device goes back to sleep. Have a look atWakefulBroadcastReceiver
, which you can use to implement this behaviour.