首页 > 解决方案 > 如何防止服务在Android中退出?

问题描述

我的服务使用 ActivityRecognition API 和 LocationListener 在用户停止驾驶时保存当前位置。

应用程序打开时它工作正常,但我没有运气在应用程序关闭后继续检测。

这是检测活动和保存位置的服务:

public class ActivityRecognitionService extends IntentService implements LocationListener {

    public Location currentBestLocation;
    private LocationManager locationManager ;
    private String provider;

    private String TAG = this.getClass().getSimpleName();
    public ActivityRecognitionService() {
        super("ActivityRecognitionService");
    }

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

        try {
            locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
            Criteria criteria = new Criteria();
            provider = locationManager.getBestProvider(criteria, false);
            if (provider != null && !provider.equals("")) {
                Location location = locationManager.getLastKnownLocation(provider);
                locationManager.requestLocationUpdates(provider, 1000, 1, this);

                if (location != null)
                    onLocationChanged(location);
                else
                    Toast.makeText(this, "Location can't be retrieved", Toast.LENGTH_SHORT).show();

            } else {
                Toast.makeText(this, "No Provider Found", Toast.LENGTH_SHORT).show();
            }
        } catch(SecurityException e) {
            Toast.makeText(this, "Enable location permissions from settings", Toast.LENGTH_SHORT).show();
        }
    }


    @Override
    protected void onHandleIntent(Intent intent) {
        ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent);
        Log.i(TAG, "Detected activity being called... ");

        // Get the list of the probable activities associated with the current state of the
        // device. Each activity is associated with a confidence level, which is an int between
        // 0 and 100.
        ArrayList<DetectedActivity> detectedActivities = (ArrayList) result.getProbableActivities();

        for (final DetectedActivity activity : detectedActivities) {
            Log.i(TAG, "Detected activity: " +  getActivityString(activity.getType()) + ", " + activity.getConfidence());

            if(activity.getConfidence() < 60)
                continue;

            logActivity(getActivityString(activity.getType()), activity.getConfidence());

            List<UserActivity> userActivities = UserActivity.listAll(UserActivity.class);
            if(!userActivities.isEmpty()) {
                UserActivity last = userActivities.get(userActivities.size() - 1);
                if(last.activity.equals("in vehicle") && activity.getType() != DetectedActivity.IN_VEHICLE) {
                    logParking();
                }
            }


        }
    }



    private void logActivity(String type, int confidence) {
        UserActivity ua = new UserActivity(type, confidence, (System.currentTimeMillis() / 1000L));
        ua.save();
    }

    private void logParking() {
        Location l = currentBestLocation;
        CarLocation cl = new CarLocation(l.getLongitude(), l.getLatitude(), (System.currentTimeMillis() / 1000L));
        cl.save();
    }

    static String getActivityString( int detectedActivityType) {
        switch(detectedActivityType) {
            case DetectedActivity.IN_VEHICLE:
                return "in vehicle";
            case DetectedActivity.ON_BICYCLE:
                return "on bicycle";
            case DetectedActivity.ON_FOOT:
                return "on foot";
            case DetectedActivity.RUNNING:
                return "running";
            case DetectedActivity.STILL:
                return "still";
            case DetectedActivity.TILTING:
                return "tilting";
            case DetectedActivity.UNKNOWN:
                return "unknown";
            case DetectedActivity.WALKING:
                return "walking";
            default:
                return "unknown";
        }
    }

    /**
     * Only replaces current location if this reading is
     * more likely to be accurate
     * @param location
     * @return
     */
    private static final int TWO_MINUTES = 1000 * 60 * 2;
    protected boolean isBetterLocation(Location location) {
        if (currentBestLocation == null) {
            // A new location is always better than no location
            return true;
        }

        // Check whether the new location fix is newer or older
        long timeDelta = location.getTime() - currentBestLocation.getTime();
        boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
        boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
        boolean isNewer = timeDelta > 0;

        // If it's been more than two minutes since the current location, use the new location
        // because the user has likely moved
        if (isSignificantlyNewer) {
            return true;
            // If the new location is more than two minutes older, it must be worse
        } else if (isSignificantlyOlder) {
            return false;
        }

        // Check whether the new location fix is more or less accurate
        int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
        boolean isLessAccurate = accuracyDelta > 0;
        boolean isMoreAccurate = accuracyDelta < 0;
        boolean isSignificantlyLessAccurate = accuracyDelta > 200;

        // Check if the old and new location are from the same provider
        boolean isFromSameProvider = isSameProvider(location.getProvider(),
                currentBestLocation.getProvider());

        // Determine location quality using a combination of timeliness and accuracy
        if (isMoreAccurate) {
            return true;
        } else if (isNewer && !isLessAccurate) {
            return true;
        } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
            return true;
        }
        return false;
    }

    private boolean isSameProvider(String provider1, String provider2) {
        if (provider1 == null) {
            return provider2 == null;
        }
        return provider1.equals(provider2);
    }

    @Override
    public void onLocationChanged(Location location) {
        if(isBetterLocation(location)) {
            currentBestLocation = location;
        }
    }

    @Override
    public void onProviderDisabled(String provider) {
        permissionsCheck();
    }

    @Override
    public void onProviderEnabled(String provider) {
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
    }

    public void permissionsCheck() {
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                ) {

            // Check Permissions Now
            ActivityCompat.requestPermissions(
                    LocationScene.mActivity,
                    new String[] { Manifest.permission.ACCESS_FINE_LOCATION },
                    0);
        }
    }

}

此服务用于启动上述服务并使其保持运行:

public class BackgroundDetectedActivitiesService extends Service {
    private static final String TAG = BackgroundDetectedActivitiesService.class.getSimpleName();
    IBinder mBinder = new BackgroundDetectedActivitiesService.LocalBinder();
    private Intent mIntentService;
    private PendingIntent mPendingIntent;
    private ActivityRecognitionClient mActivityRecognitionClient;

    public BackgroundDetectedActivitiesService() {

    }

    @Override
    public void onCreate() {

        super.onCreate();

        mActivityRecognitionClient = new ActivityRecognitionClient(this);
        mIntentService = new Intent(this, uk.co.appoly.wheres_my_car.services.ActivityRecognitionService.class);
        mPendingIntent = PendingIntent.getService(this, 1, mIntentService, PendingIntent.FLAG_UPDATE_CURRENT);
        requestActivityUpdatesButtonHandler();
    }

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        return START_STICKY;
    }

    public void requestActivityUpdatesButtonHandler() {
        Task<Void> task = mActivityRecognitionClient.requestActivityUpdates(
                20000,
                mPendingIntent);

        task.addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void result) {
                Toast.makeText(getApplicationContext(),
                        "Successfully requested activity updates",
                        Toast.LENGTH_SHORT)
                        .show();
            }
        });

        task.addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Toast.makeText(getApplicationContext(),
                        "Requesting activity updates failed to start",
                        Toast.LENGTH_SHORT)
                        .show();
            }
        });
    }

    public void removeActivityUpdatesButtonHandler() {
        Task<Void> task = mActivityRecognitionClient.removeActivityUpdates(
                mPendingIntent);
        task.addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void result) {
                Toast.makeText(getApplicationContext(),
                        "Removed activity updates successfully!",
                        Toast.LENGTH_SHORT)
                        .show();
            }
        });

        task.addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Toast.makeText(getApplicationContext(), "Failed to remove activity updates!",
                        Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public void onDestroy() {


        super.onDestroy();
        //removeActivityUpdatesButtonHandler();
        /**/
    }

    public class LocalBinder extends Binder {
        public BackgroundDetectedActivitiesService getServerInstance() {
            return BackgroundDetectedActivitiesService.this;
        }
    }
}

我在我的 android 清单中有这个:

<service
    android:name="uk.co.appoly.wheres_my_car.services.ActivityRecognitionService"
    android:exported="false" />

<service android:name="uk.co.appoly.wheres_my_car.services.BackgroundDetectedActivitiesService"></service>

(加上正确的权限)

我从我的 MainActivity 开始服务,如下所示:

activityRecognitionClient = ActivityRecognition.getClient(mContext);
        transitionIntent = new Intent(MainActivity.this, BackgroundDetectedActivitiesService.class);
        startService(transitionIntent);

我一直试图解决这个问题大约一天,但无济于事。我究竟做错了什么?

标签: android

解决方案


推荐阅读