Is it possible to start the service on the Android platform even after locking the device?

We are working on the development of a service for the Android platform.

In our service, we need to send GPS data (Lat and Long) to any external REST service every one minute.

It works fine for almost 15 minutes after locking the device. But after that, it does not send any data.

After unlocking the device, it will again start sending data through the REST service.

My code is bye

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?

+5
source share
8 answers

You acquire a trail lock in your Activity . The problem here is that when the device is locked, your Activity falls into the background. After 15 minutes of inactivity, Android just kills the process. This releases the tracking lock. The device goes into sleep mode.

Now, when your alarm goes off, the device wakes up, BroadcastReceiver is called, onReceive() is onReceive() , it starts your Service , but then the device returns to sleep mode, because there is no alarm lock, therefore, β€œThe service does nothing”.


Another approach, if you want the phone to stay awake while your application is running, would be to acquire a track lock in Service . In this case, you do not want to call stopSelf() every time you run Runnable . You want your Service work until you want to stop it, and then you call stopService() . Thus, the Service will always be active (even if it does nothing), and this will prevent the device from sleeping through the tracking lock. However, this can lead to an unacceptable battery leak (you will have to test it).

You need to acquire a track lock in BroadcastReceiver and make sure that Service starts and receives a lock after the device falls asleep again. Check out the WakefulBroadcastReceiver , which you can use to implement this behavior.

+4
source

One approach might be to rely on AlarmManager : as soon as you sign up for AlarmManager, the system itself launches your code at the interval that you configured, even if your application is inactive. Each time it starts, you may decide to process some code ... Thus, you completely avoid the need to keep the service alive.

You need the Alarm class that will handle the AlarmManager intent.


Create your own alarm:

 public class Alarm extends BroadcastReceiver { private static final String TAG = "Alarm"; @Override public void onReceive(Context context, Intent intent) { PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, ""); wl.acquire(); /*************** Here you can do your stuff... This will be triggered every second. Send data from here, or better: call an IntentService that will take care of it. ****************/ wl.release(); } public void SetAlarm(Context context) { Intent i = new Intent(context, Alarm.class); boolean alarmUp = (PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_NO_CREATE) != null); if (alarmUp) { // The alarm is already running, do not set it twice } else { AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0); am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000, pi); // 1000 Millisec means it will trigger it every second... and RTC_WAKEUP means that it will wake up your device if needed. } } // later on, use this method if you want to manually cancel the AlarmManager : public void CancelAlarm(Context context) { Intent intent = new Intent(context, Alarm.class); PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0); AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); alarmManager.cancel(sender); } } 

In your manifest, declare this Alarm BroadcastReceiver

 <receiver android:name=".utils.Alarm" android:process=":remote" > </receiver> 

And where do you want to call this AlarmManager in your activity!

 Alarm alarm = new Alarm(); @Override protected void onCreate(Bundle savedInstanceState) { alarm.SetAlarm(this); } // or if elsewhere you need to stop the Alarm : alarm.CancelAlarm(this); 

This is the main idea. Now you need to deal with the screen on or off. For these 2 solutions: you can register for the intention of the device screen state and control the on / off of AlarmManager ... or you can let AlarmManager always work, but check if the device is turned on when sending data ...

Hope this helps!

+4
source

Yes, you can start any service, even if the device is locked. Even, you can resume the service after rebooting the device.

You can implement GCM Network Manager.

Required Code: -

 <service android:name=".MyTaskService" android:exported="true" android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE"> <intent-filter> <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" /> </intent-filter> </service> 

Java Code: -

 mGcmNetworkManager = GcmNetworkManager.getInstance(this); OneoffTask task = new OneoffTask.Builder() .setService(MyTaskService.class) .setTag(TASK_TAG_WIFI) .setExecutionWindow(0L, 3600L) .setRequiredNetwork(Task.NETWORK_STATE_UNMETERED) .build(); mGcmNetworkManager.schedule(task); 

For more information, you can visit https://developers.google.com/cloud-messaging/network-manager#run_tasks and read the documents.

You just need to include gcm services in the project to use the GCM network manager. Support 4.0+

Accept this answer if this is the solution you want. This may help other developers as well.

+1
source

Yes, you can implement a background service that will almost never be killed. But you must declare it launched in the foreground. you can see what the Android developer site says 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 of the hierarchy of importance and various types of processes in order of importance (the first process is most important and the last is killed):

  • Foreground Process :

The process necessary for the user to complete. A process is considered foreground if one of the following conditions is met:

  • It contains the action that the user interacts with (the onResume () method is called).
  • It contains a service associated with the activity with which the user interacts.
  • It hosts a service that runs "in the foreground" - the service called startForeground ().
  • It contains a service that performs one of its lifecycle callbacks (onCreate (), onStart (), or onDestroy ()).
  • It hosts the BroadcastReceiver, which executes its onReceive () method.

Typically, at any given time, there are only a few foreground processes. They are killed only as a last resort - if the memory is so low that they cannot continue to work. Typically, at this point, the device has reached a swap state in memory, so killing some foreground processes is required to prevent changes to the user interface.

So, you should start your service in the foreground. To do this, you implement the service, as shown below.

 public class MyForegroundService extends Service { @Override public void onCreate() { super.onCreate(); //your code goes here } @Override public IBinder onBind(Intent intent) { throw new UnsupportedOperationException("Not yet implemented"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { keepServiceAlive(); //your code goes here return(START_NOT_STICKY); } private void keepServiceAlive() { Intent notificationIntent = new Intent(this, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); Notification notification = new NotificationCompat.Builder(this).setContentTitle(getString(R.string.app_name)) .setContentText("Hello") .setSmallIcon(R.mipmap.ic_launcher) .setContentIntent(pendingIntent) .build(); startForeground(Notification.FLAG_ONGOING_EVENT, notification); } @Override public void onDestroy() { super.onDestroy(); Log.w(getClass().getName(), "Got to stop()!"); stopForeground(true); } } 

Thank you and good luck ..

+1
source

You must start the alarm again and again when the service is shutting down.

You can also implement BroadCastReceiver, which starts the service when the device boots.

Check out this tutorial: http://ncona.com/2014/04/schedule-your-android-app-to-do-something-periodically/

+1
source

I had the same problem in my application, but I solved the problem by first creating a service, using a periodic service. You can specify the time frame for updating the data. In my case, it was code.

UpdateService.java

 public class UpdateServices extends Service implements LocationListener { String id, latee, longee; // j private ProgressDialog pDialog; ProgressDialog progressDialog; JSONParser jsonParser = new JSONParser(); DBManager db; private static String url_create_locationupdate = "http://192.168.0.175/simple_demo3/classes/create_locationupdate.php"; private static final String TAG_SUCCESS = "success"; public static String LOG = "Log"; private final Context mContext; boolean isGPSEnabled = false; boolean isNetworkEnabled = false; boolean canGetLocation = false; Location location; // location double latitude; // latitude double longitude; // longitude private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 3; // 0 meters private long MIN_TIME_BW_UPDATES; // 10 second private long MIN_LENGTH_BW_UPDATES; SharedPreferences mPref; protected LocationManager locationManager; public UpdateServices(Context context) { this.mContext = context; } public UpdateServices() { super(); mContext = UpdateServices.this; } @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); Log.i(LOG, "Service started"); mPref = getSharedPreferences("mFile", 0); MIN_TIME_BW_UPDATES = mPref.getLong("mint", 1) * 1000 * 60; MIN_LENGTH_BW_UPDATES = mPref.getLong("kmeter", 1) * 1000; Log.i("asd", "This is sparta"); latitude = getLocation().getLatitude(); longitude = getLocation().getLongitude(); return START_STICKY; } @Override public void onCreate() { super.onCreate(); Log.i(LOG, "Service created"); } @Override public void onDestroy() { super.onDestroy(); Log.i(LOG, "Service destroyed"); } public Location getLocation() { try { locationManager = (LocationManager) mContext .getSystemService(LOCATION_SERVICE); isGPSEnabled = locationManager .isProviderEnabled(LocationManager.GPS_PROVIDER); isNetworkEnabled = locationManager .isProviderEnabled(LocationManager.NETWORK_PROVIDER); if (!isGPSEnabled && !isNetworkEnabled) { } else { this.canGetLocation = true; if (isNetworkEnabled) { locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 5000, MIN_DISTANCE_CHANGE_FOR_UPDATES, this); Log.d("Network", "Network"); if (locationManager != null) { location = locationManager .getLastKnownLocation(LocationManager.NETWORK_PROVIDER); if (location != null) { latitude = location.getLatitude(); longitude = location.getLongitude(); } } } // if GPS Enabled get lat/long using GPS Services if (isGPSEnabled) { if (location == null) { locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this); Log.d("GPS Enabled", "GPS Enabled"); if (locationManager != null) { location = locationManager .getLastKnownLocation(LocationManager.GPS_PROVIDER); if (location != null) { latitude = location.getLatitude(); longitude = location.getLongitude(); } } } } } } catch (Exception e) { e.printStackTrace(); } return location; } @Override public void onLocationChanged(Location location) { // this will be called every second String laty = Double.toString(getLocation().getLatitude()); String lagy = Double.toString(getLocation().getLongitude()); db = new DBManager(mContext); db.open(); db.mInsertGPSCor(laty, lagy); Toast.makeText( getApplicationContext(), "Your Location is - \nLat: " + location.getLatitude() + "\nLong: " + location.getLongitude(), Toast.LENGTH_LONG).show(); Toast.makeText(UpdateServices.this, "record entered", Toast.LENGTH_SHORT).show(); db.close(); // store in server new CreateNewProduct(this).execute(); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } class CreateNewProduct extends AsyncTask<String, String, String> { private Context mContext; public CreateNewProduct(Context context) { super(); mContext = context; } @Override protected void onPreExecute() { try { super.onPreExecute(); progressDialog = ProgressDialog.show(mContext, "Press Back to Cancel", "Sending Data to Server..", true, false); } catch (Exception e) { // TODO: handle exception } } /** * Creating product * */ protected String doInBackground(String... args) { List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("ID", id)); params.add(new BasicNameValuePair("LATITUDE", latee)); params.add(new BasicNameValuePair("LONGITUDE", longee)); JSONObject json = jsonParser.makeHttpRequest( url_create_locationupdate, "POST", params); try { int success = json.getInt(TAG_SUCCESS); if (success == 1) { return "done"; } else { // failed to create product return "fail"; } } catch (JSONException e) { e.printStackTrace(); return "exec"; } } /** * After completing background task Dismiss the progress dialog * **/ protected void onPostExecute(String file_url) { if (progressDialog.isShowing()) progressDialog.dismiss(); if (file_url.equalsIgnoreCase("done")) { show.message(mContext, "uploading successed"); } if (file_url.equalsIgnoreCase("fail") || file_url.equalsIgnoreCase("exec")) { try { show.message(mContext, "uploading failed"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public void onConnectionSuspended(int arg0) { // TODO Auto-generated method stub } } 

and Main.java

 public class Main extends Activity { Button btn_startGps, btn_stopGps; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.auto_gps_update); btn_startGps = (Button) findViewById(R.id.button_service); btn_stopGps = (Button) findViewById(R.id.button_stopservice); btn_startGps.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startService(new Intent(About.this, UpdateServices.class)); Toast.makeText(About.this, "Service Started", Toast.LENGTH_SHORT).show(); } }); btn_stopGps.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopService(new Intent(About.this, UpdateServices.class)); Log.e("sss", "ddddd"); Toast.makeText(About.this, "Service Stopped", Toast.LENGTH_SHORT).show(); } }); } 

but here the problem service does not stop here to stop the service

Because I have return

  return START_STICKY; 

in onStartCommand(...)

read more START_STICKY and START_NOT_STICKY

and white papers

+1
source

If you run the application in API 21+, use JobScheduler , which is described in the Google documentation, is also a better approach.

In addition, if you do not want to change the structure of the code, you can use your service to support the CPU, even if the screen is off. Read how to save CPU On in Google documentation. Just add permission to your manifest <uses-permission android:name="android.permission.WAKE_LOCK" /> and in Service.onCreate , put:

 PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag"); wakeLock.acquire(); 

And release Service.onDestroy with wakelock.release() . But keep in mind that it discharges the battery. But if you said that the device will always be connected to a power source, I think this is not a problem. Just in case, it would be better to have an admin user interface in the application to stop the service manually.

+1
source
 In Manifest file, <service android:name=".MyService"></service> 

MyService.java

 public class MyService extends Service { @Override public void onCreate() { super.onCreate(); // your code here } @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; } @Override public void onDestroy() { super.onDestroy(); Intent it = new Intent(MyService.this, MyService.class); getApplication().startService(it); // If service will destroy, Start the service again } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } } 

to start the service, add it to your activity,

  Intent it = new Intent(getApplication(), MyService.class); getApplicationContext().startService(it); 
+1
source

Source: https://habr.com/ru/post/1246392/


All Articles