How to run service 24x7 in android in background to get location of user

∥☆過路亽.° 提交于 2019-12-08 12:00:31

问题


I have tried so many different ways to run background service to get location of user but android system automatically kills service after some time. Though it works on some devices but not working on most of the devices. I am building app similar to UBER. I want driver's location to be updated after some interval of time even if app is in background or Foreground until user does not set status to offline


回答1:


You can use Foreground Service, which is just a normal service with an ongoing notification in the foreground, which stops the OS to stop/kill your service process.

By the way, this does not gurantee that your service will be give CPU/processing time when device goes into Doze or App Standby modes.

Although you cannot bypass these doze, standby and battery optimizations, but I've tested a hack to avoid these by creating a wake lock in your foreground service and starting that service in a separate process.

Hope it helps.




回答2:


Yes, you can do it but maybe it will consume more battery power. Find below code it will help you,

There is an alternative way to use mobile location, Google has release fused location provider which are more helpful in your case.

1.Add Google Location gradle line in your Build.gradle file

implementation 'com.google.android.gms:play-services-location:15.0.1'

2.Get User Location Using Location Service

import android.Manifest;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.NotificationCompat;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationAvailability;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.uffizio.taskeye.BuildConfig;
import com.uffizio.taskeye.R;
import com.uffizio.taskeye.extra.Constants;
import com.uffizio.taskeye.ui.activity.MainActivity;


/**
 * Created by Kintan on 16/8/18.
 */

public class LocationServiceDemo extends Service implements GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {

    public static LocationServiceDemo locationService;
    private static GoogleApiClient mGoogleApiClient;
    private static LocationRequest mLocationRequest;
    private FusedLocationProviderClient mFusedProviderClient;
    private MyLocationCallback mMyLocationCallback;
    private Location curLocation;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    @Override
    public void onCreate() {
        super.onCreate();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            showNotificationAndStartForegroundService();

        locationService = this;
        init();
    }

    //Google location Api build
    protected synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    }

    protected void createLocationRequest() {
        mMyLocationCallback = new MyLocationCallback();
        mLocationRequest = LocationRequest.create();
        mLocationRequest.setInterval(5000);
        mLocationRequest.setFastestInterval(3000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationRequest.setSmallestDisplacement(5.0f);

        requestUpdate();

    }

    //Start Foreground Service and Show Notification to user for Android O and higher Version
    private void showNotificationAndStartForegroundService() {

        final String CHANNEL_ID = BuildConfig.APPLICATION_ID.concat("_notification_id");
        final int REQUEST_CODE = 1;

        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                REQUEST_CODE, new Intent(this, MainActivity.class),
                PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this,
                CHANNEL_ID)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle(getString(R.string.app_name))
                .setAutoCancel(false)
                .setContentIntent(pendingIntent);

        startForeground(Constants.NOTIFICATION_ID, notificationBuilder.build());
    }

    public void requestUpdate() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        mFusedProviderClient.requestLocationUpdates(mLocationRequest, mMyLocationCallback,
                Looper.myLooper());
    }

    public void removeUpdate() {
        mFusedProviderClient.removeLocationUpdates(mMyLocationCallback);
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        createLocationRequest();
    }

    @Override
    public void onConnectionSuspended(int i) {
        buildGoogleApiClient();
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

        buildGoogleApiClient();
    }

    private void init() {
        buildGoogleApiClient();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mFusedProviderClient = LocationServices.getFusedLocationProviderClient(LocationServiceDemo.this);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
                        != PackageManager.PERMISSION_GRANTED) {
            return START_STICKY;
        }
        mFusedProviderClient.getLastLocation().addOnSuccessListener(location -> {
            if (location != null) {

                curLocation = location;

            }
        });
        if (mGoogleApiClient.isConnected()) {
            createLocationRequest();
        } else {
            buildGoogleApiClient();
        }
        return START_STICKY;
    }


    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        startService();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        startService();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        startService();
    }

    public void startService() {
        startService(new Intent(LocationServiceDemo.this, LocationServiceDemo.class));
    }

    public class MyLocationCallback extends LocationCallback {
        @Override
        public void onLocationResult(LocationResult locationResult) {
            //get your location here
            if (locationResult.getLastLocation() != null) {
                for (Location location : locationResult.getLocations()) {
                    curLocation = location;
                }
            }
        }

        @Override
        public void onLocationAvailability(LocationAvailability locationAvailability) {
            super.onLocationAvailability(locationAvailability);
        }
    }

    private class MyBinder extends Binder {
        LocationServiceDemo getService() {
            return LocationServiceDemo.this;
        }
    }
}

3.Finaly Grant Access the admin permission so,android system will not automatically kills service after some time.

import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;


public class LocationHome extends AppCompatActivity {
    private static final int REQUEST_CODE = 0;
    private DevicePolicyManager mDPM;
    private ComponentName mAdminName;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
        mAdminName = new ComponentName(this, DeviceAdmin.class);

        Button button = new Button();
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Grant Admin Permission
                if (mDPM.isAdminActive(mAdminName)) {
                    startService(new Intent(this, LocationService.class));
                } else {
                    adminPermission();
                }
            }
        });
    }


    public void adminPermission() {
        try {
            if (!mDPM.isAdminActive(mAdminName)) {
                try {
                    Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
                    intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mAdminName);
                    intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "Click on Activate button to secure your application.");
                    startActivityForResult(intent, REQUEST_CODE);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        //Check Permission is granted or not
        if (requestCode == REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                startService(new Intent(this, LocationService.class));
            } else {
                if (!mDPM.isAdminActive(mAdminName)) {
                    adminPermission();
                }
            }
        }
    }


}

Create XMl folder add device_admin.xml

<device-admin>
    <uses-policies>

    </uses-policies>
</device-admin>

And Finaly Modify Your Manifest and Enjoy.

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-feature
        android:name="android.hardware.location.gps"
        android:required="false" />
<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:name=".common.MyApplication"
        android:theme="@style/AppTheme">

        <receiver
            android:name=".ui.DeviceAdmin"
            android:permission="android.permission.BIND_DEVICE_ADMIN">
            <meta-data
                android:name="android.app.device_admin"
                android:resource="@xml/device_admin" />
            <intent-filter>
                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
            </intent-filter>
        </receiver>
    </application>



回答3:


You could use a few mechanisms provided by Android.

  1. For devices running pre-Oreo, you could just use background service as it is and it should live most of the time, keep it on a separate process by declaring it in the manifest file. You can also register to device boot complete broadcast, so you will get a call back when device reboots, you will then have a chance to restart you background service. For devices running oreo+, the most reliable way to go is using a foreground service. Make sure your service is sticky in any case.
  2. Set up fire base schedule job to restart your service in case it stops
  3. Geo fence policy to get additional feedback
  4. Schedule with alarm manager to restart your service in case it stops
  5. Use google activity recognition api you can also get callback to have additional chances to pull more location info
  6. Push notifications

I’d suggest using a combination of all with policy tailored to your application, they together should give you enough about a users location at any time.



来源:https://stackoverflow.com/questions/51872590/how-to-run-service-24x7-in-android-in-background-to-get-location-of-user

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!