Is it possible to run service in android platform continuously even after locking the device?

后端 未结 8 976
小鲜肉
小鲜肉 2020-12-16 05:44

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 afte

相关标签:
8条回答
  • 2020-12-16 06:26

    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 your Service.onCreate, put :

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

    And release in Service.onDestroy with wakelock.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.

    0 讨论(0)
  • 2020-12-16 06:31

    You have to fire the alarm over and over again when the service completes running.

    Also you can implement a BroadCastReceiver that starts the service on the device boot.

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

    0 讨论(0)
  • 2020-12-16 06:35

    You are acquiring the wake lock in your Activity. The problem here is that when the device is locked, your Activity 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 your Service, 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 call stopSelf() every time your Runnable runs. You would want to keep your Service running until you want to stop it, at which time you would call stopService(). This way, the Service 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 the Service gets started and acquires a wake lock before the device goes back to sleep. Have a look at WakefulBroadcastReceiver, which you can use to implement this behaviour.

    0 讨论(0)
  • 2020-12-16 06:36

    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 :

    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 from where you want in your Activity call this AlarmManager !

    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 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 !

    0 讨论(0)
  • 2020-12-16 06:36

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

    You can implement GCM Network Manager.

    Sample code required:-

    <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);
    

    Fore more info you can visit https://developers.google.com/cloud-messaging/network-manager#run_tasks and read the docs.

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

    Please accept this answer if this is the solution you want. This may help other developers also.

    0 讨论(0)
  • 2020-12-16 06:40

    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

    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", "ffffffffd");
                    Toast.makeText(About.this, "Service Stopped",
                            Toast.LENGTH_SHORT).show();
    
                }
            });
    }
    

    but here an issue service is not stop here to stop service

    Because i have return

     return START_STICKY;
    

    in onStartCommand(...)

    read more at START_STICKY and START_NOT_STICKY

    and Official docs

    0 讨论(0)
提交回复
热议问题