如何在没有通知的情况下在后台或睡眠模式下运行服务甚至应用程序?

时间:2018-06-13 10:10:38

标签: android location

由于我想计算每两分钟的距离,但在奥利奥,当应用程序进入睡眠模式时,它无法正常工作。这就是为什么我在应用程序转到后台通知时会在服务中添加通知将发送给用户,因此当应用程序进入睡眠模式时它的工作正常。

如果没有通知如何在Android服务中做,请帮我解决我的问题。

服务代码:

/**
 * A bound and started service that is promoted to a foreground service when location updates have
 * been requested and all clients unbind.
 *
 * For apps running in the background on "O" devices, location is computed only once every 10
 * minutes and delivered batched every 30 minutes. This restriction applies even to apps
 * targeting "N" or lower which are run on "O" devices.
 *
 * This sample show how to use a long-running service for location updates. When an activity is
 * bound to this service, frequent location updates are permitted. When the activity is removed
 * from the foreground, the service promotes itself to a foreground service, and location updates
 * continue. When the activity comes back to the foreground, the foreground service stops, and the
 * notification assocaited with that service is removed.
 */
public class LocationUpdatesService extends Service {

    private static final String PACKAGE_NAME =
            "com.google.android.gms.location.sample.locationupdatesforegroundservice";
    Double mlastlocationlat,mlastlocationlong,mcurrentlocationlat,mcurrentlocationlong;
    SharedPreferences sharedPreferences,startdistance_preference;
    SharedPreferences.Editor editor;
    float f_TotDist ;
    int timercount;
    Database database;
    private static final String TAG = LocationUpdatesService.class.getSimpleName();

    /**
     * The name of the channel for notifications.
     */
    private static final String CHANNEL_ID = "channel_01";

    static final String ACTION_BROADCAST = PACKAGE_NAME + ".broadcast";

    static final String EXTRA_LOCATION = PACKAGE_NAME + ".location";
    private static final String EXTRA_STARTED_FROM_NOTIFICATION = PACKAGE_NAME +
            ".started_from_notification";

    private final IBinder mBinder = new LocalBinder();

    /**
     * The desired interval for location updates. Inexact. Updates may be more or less frequent.
     */
    private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;

    /**
     * The fastest rate for active location updates. Updates will never be more frequent
     * than this value.
     */
    private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
            UPDATE_INTERVAL_IN_MILLISECONDS;

    /**
     * The identifier for the notification displayed for the foreground service.
     */
    private static final int NOTIFICATION_ID = 12345678;

    /**
     * Used to check whether the bound activity has really gone away and not unbound as part of an
     * orientation change. We create a foreground service notification only if the former takes
     * place.
     */
    private boolean mChangingConfiguration = false;

    private NotificationManager mNotificationManager;

    /**
     * Contains parameters used by {@link com.google.android.gms.location.FusedLocationProviderApi}.
     */
    private LocationRequest mLocationRequest;

    /**
     * Provides access to the Fused Location Provider API.
     */
    private FusedLocationProviderClient mFusedLocationClient;

    /**
     * Callback for changes in location.
     */
    private LocationCallback mLocationCallback;

    private Handler mServiceHandler;

    /**
     * The current location.
     */
    private Location mLocation;

    public LocationUpdatesService() {
    }

    @Override
    public void onCreate() {
        Log.i("PL", "Service oncreated");

        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

        mLocationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                super.onLocationResult(locationResult);

                Log.i("PL", "onLocationResult");

                onNewLocation(locationResult.getLastLocation());
            }
        };

        createLocationRequest();
        getLastLocation();

        HandlerThread handlerThread = new HandlerThread(TAG);
        handlerThread.start();
        mServiceHandler = new Handler(handlerThread.getLooper());
        mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

        // Android O requires a Notification Channel.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = getString(R.string.app_name);
            // Create the channel for the notification
            NotificationChannel mChannel =
                    new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_DEFAULT);

            // Set the Notification Channel for the Notification Manager.
            mNotificationManager.createNotificationChannel(mChannel);
        }

        database=new Database(this);

        // this.deleteDatabase("EmployeeDatabase.db");

        database.getWritableDatabase();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("PL", "Service startedcommand");

        // Tells the system to not try to recreate the service after it has been killed.
        return START_STICKY;
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        mChangingConfiguration = true;

        Log.i("PL", "onConfigurationChanged");

    }

    @Override
    public IBinder onBind(Intent intent) {
        // Called when a client (MainActivity in case of this sample) comes to the foreground
        // and binds with this service. The service should cease to be a foreground service
        // when that happens.
        Log.i("PL", "in onBind()");
        stopForeground(true);
        mChangingConfiguration = false;
        return mBinder;
    }

    @Override
    public void onRebind(Intent intent) {
        // Called when a client (MainActivity in case of this sample) returns to the foreground
        // and binds once again with this service. The service should cease to be a foreground
        // service when that happens.
        Log.i("PL", "in onRebind()");
        stopForeground(true);
        mChangingConfiguration = false;
        super.onRebind(intent);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i("PL", "unbind--Last client unbound from service");

        // Called when the last client (MainActivity in case of this sample) unbinds from this
        // service. If this method is called due to a configuration change in MainActivity, we
        // do nothing. Otherwise, we make this service a foreground service.
        if (!mChangingConfiguration && Utils.requestingLocationUpdates(this)) {
            Log.i("PL", "unbind--Starting foreground service");

            startForeground(NOTIFICATION_ID, getNotification());
        }
        return true; // Ensures onRebind() is called when a client re-binds.
    }

    @Override
    public void onDestroy() {
        mServiceHandler.removeCallbacksAndMessages(null);
    }

    /**
     * Makes a request for location updates. Note that in this sample we merely log the
     * {@link SecurityException}.
     */
    public void requestLocationUpdates() {
        Log.i("PL", "Requesting location updates");
        Utils.setRequestingLocationUpdates(this, true);
        startService(new Intent(getApplicationContext(), LocationUpdatesService.class));
        try {
            mFusedLocationClient.requestLocationUpdates(mLocationRequest,
                    mLocationCallback, Looper.myLooper());
        } catch (SecurityException unlikely) {
            Utils.setRequestingLocationUpdates(this, false);
            Log.e("PL", "Lost location permission. Could not request updates. " + unlikely);
        }
    }

    /**
     * Removes location updates. Note that in this sample we merely log the
     * {@link SecurityException}.
     */
    public void removeLocationUpdates() {
        Log.i("PL", "Removing location updates");
        try {
            mFusedLocationClient.removeLocationUpdates(mLocationCallback);
            Utils.setRequestingLocationUpdates(this, false);
            stopSelf();
        } catch (SecurityException unlikely) {
            Utils.setRequestingLocationUpdates(this, true);
            Log.e("PL", "Lost location permission. Could not remove updates. " + unlikely);
        }
    }

    /**
     * Returns the {@link NotificationCompat} used as part of the foreground service.
     */
    private Notification getNotification() {


        Intent intent = new Intent(this, LocationUpdatesService.class);

        Log.i("PL", "getNotification");

        CharSequence text = Utils.getLocationText(mLocation,f_TotDist);

        // Extra to help us figure out if we arrived in onStartCommand via the notification or not.
        intent.putExtra(EXTRA_STARTED_FROM_NOTIFICATION, true);

        // The PendingIntent that leads to a call to onStartCommand() in this service.
        PendingIntent servicePendingIntent = PendingIntent.getService(this, 0, intent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        // The PendingIntent to launch activity.
        PendingIntent activityPendingIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, MainActivity.class), 0);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)

                .setContentText(text)
                .setContentTitle(Utils.getLocationTitle(this))
                .setOngoing(true)
                .setPriority(Notification.PRIORITY_HIGH)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setTicker(text)
                .setWhen(System.currentTimeMillis());
        Notification notification = null;
        // Set the Channel ID for Android O.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
          //  builder.setChannelId(CHANNEL_ID); // Channel ID

            // Create a notification and set the notification channel.
             notification = new Notification.Builder(this)

                    .setChannelId(CHANNEL_ID)

                    .setContentText(text)
                    .setContentTitle(Utils.getLocationTitle(this))
                    .setOngoing(true)
                    .setPriority(Notification.PRIORITY_HIGH)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setTicker(text)

                    .build();
        }
        else
        {

        }






        return builder.build();
    }

    private void getLastLocation() {
        try {
            mFusedLocationClient.getLastLocation()
                    .addOnCompleteListener(new OnCompleteListener<Location>() {
                        @Override
                        public void onComplete(@NonNull Task<Location> task) {
                            if (task.isSuccessful() && task.getResult() != null) {
                                mLocation = task.getResult();
                                Log.w("PL", "mLocation lastknow.");

                            } else {
                                Log.w("PL", "Failed to get location.");
                            }
                        }
                    });
        } catch (SecurityException unlikely) {
            Log.e("PL", "Lost location permission." + unlikely);
        }
    }

    private void onNewLocation(Location location) {
        Log.i("PL", "New location: " + location);

        mLocation = location;
        startdistance_preference = getSharedPreferences("startLessonPref",
                Context.MODE_PRIVATE);

        sharedPreferences = getSharedPreferences("myprefer", MODE_PRIVATE);
        editor = sharedPreferences.edit();



        editor.putString("dest_Lat", String.valueOf(location.getLatitude()));
        editor.putString("dest_Long", String.valueOf(location.getLongitude()));

        editor.putString("Lat", String.valueOf(location.getLatitude()));
        editor.putString("Long", String.valueOf(location.getLongitude()));
        if(mlastlocationlat==null && mlastlocationlong==null && mcurrentlocationlat==null && mcurrentlocationlong==null)
        {


            editor.putString("mlastlocationlat", String.valueOf(location.getLatitude()));
            editor.putString("mlastlocationlong", String.valueOf(location.getLongitude()));

            editor.putString("mcurrentlocationlat", String.valueOf(location.getLatitude()));
            editor.putString("mcurrentlocationlong", String.valueOf(location.getLongitude()));

            mlastlocationlat=location.getLatitude();

            mlastlocationlong=location.getLongitude();

            mcurrentlocationlat=location.getLatitude();

            mcurrentlocationlong=location.getLongitude();
            Log.e("RS","mlastlocationlat" + mlastlocationlat);
            Log.e("RS","mlastlocationlong" + mlastlocationlong);
            Log.e("RS","mcurrentlocationlat" + mcurrentlocationlat);
            Log.e("RS","mcurrentlocationlong" + mcurrentlocationlong);


        }
        else
        {
            mlastlocationlat=mcurrentlocationlat;
            mlastlocationlong=mcurrentlocationlong;
            mcurrentlocationlat=location.getLatitude();
            mcurrentlocationlong=location.getLongitude();

            editor.putString("mlastlocationlat", String.valueOf(mcurrentlocationlat));
            editor.putString("mlastlocationlong", String.valueOf(mcurrentlocationlong));

            editor.putString("mcurrentlocationlat", String.valueOf(location.getLatitude()));
            editor.putString("mcurrentlocationlong", String.valueOf(location.getLongitude()));

               /* mcurrentlocationlat=Double.valueOf(String.format("%.4f", location.getLatitude()));
                mcurrentlocationlong=Double.valueOf(String.format("%.4f", location.getLongitude()));
               */ Log.e("RS","else--mlastlocationlat" + mlastlocationlat);
            Log.e("RS","else-mlastlocationlong" + mlastlocationlong);
            Log.e("RS","else-mcurrentlocationlat--" + mcurrentlocationlat);
            Log.e("RS","else-mcurrentlocationlong--" + mcurrentlocationlong);

        }
        editor.commit();
        Float dist = distanceCal(mlastlocationlat, mlastlocationlong,mcurrentlocationlat, mcurrentlocationlong);

        // Notify anyone listening for broadcasts about the new location.
        Intent intent = new Intent(ACTION_BROADCAST);
        intent.putExtra(EXTRA_LOCATION, location);
        LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);

        // Update notification content if running as a foreground service.
        if (serviceIsRunningInForeground(this)) {



            mNotificationManager.notify(NOTIFICATION_ID, getNotification());


        }
    }

    /**
     * Sets the location request parameters.
     */
    private void createLocationRequest() {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
        mLocationRequest.setSmallestDisplacement(0);
        mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

    /**
     * Class used for the client Binder.  Since this service runs in the same process as its
     * clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        LocationUpdatesService getService() {
            return LocationUpdatesService.this;
        }
    }

    /**
     * Returns true if this is a foreground service.
     *
     * @param context The {@link Context}.
     */
    public boolean serviceIsRunningInForeground(Context context) {
        ActivityManager manager = (ActivityManager) context.getSystemService(
                Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(
                Integer.MAX_VALUE)) {
            if (getClass().getName().equals(service.service.getClassName())) {
                if (service.foreground) {
                    Log.i("PL", "if--serviceisruningforegroun"+service.foreground);

                    return true;
                }
                else
                {
                    Log.i("PL", "elsee--serviceisruningforegroun"+service.foreground);

                }
            }
            else {
                //Log.i("PL", "elsee-main-serviceisruningforegroun"+service.foreground);

            }
        }
        return false;
    }


    private float distanceCal(double lat1, double lon1, double lat2, double lon2) {


        Location loc1 = new Location("");
        loc1.setLatitude(lat1);
        loc1.setLongitude(lon1);

        Location loc2 = new Location("");
        loc2.setLatitude(lat2);
        loc2.setLongitude(lon2);

        float distanceInMeters = loc1.distanceTo(loc2);
        float distanceinmeter= Float.parseFloat(String.format("%.2f", distanceInMeters));
        Log.e("RS--first--","-distanceInMeters-" +distanceInMeters);

        Log.e("RS---#####-1-" + lat1, "--" + lon1);
        Log.e("RS---#####-2-" + lat2, "--" + lon2);

        startdistance_preference = getSharedPreferences("startLessonPref",
                Context.MODE_PRIVATE);
        f_TotDist = startdistance_preference.getFloat("str_TotalDist", 0);
        Log.e("RS","-f_TotDist-first-" +f_TotDist);
        timercount = Integer.parseInt(startdistance_preference.getString("timerstart", null));

        database.insertData(String.valueOf(timercount),mcurrentlocationlat,mcurrentlocationlong,f_TotDist);

        // startLesson_preference = getSharedPreferences("startLessonPref", Context.MODE_PRIVATE);

        f_TotDist+=(distanceinmeter);
        timercount=timercount+3;
        Log.e("RS","-f_TotDist--if-" +f_TotDist);


        SharedPreferences.Editor editor1 = startdistance_preference.edit();


        editor1.putFloat("str_TotalDist", (float) f_TotDist);

        editor1.putString("timerstart", String.valueOf(timercount));
        editor1.commit();



        return distanceInMeters;
    }

}

的活动:

public class MainActivity extends AppCompatActivity 
     SharedPreferences  startdistance_preference;
    ArrayList arrayList;
    Timer timer,timer1;
    private static final String TAG = MainActivity.class.getSimpleName();

    // Used in checking for runtime permissions.
    private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;

    // The BroadcastReceiver used to listen from broadcasts from the service.
    private MyReceiver myReceiver;
    ListView listView;
    // A reference to the service used to get location updates.
    private LocationUpdatesService mService = null;
    Database database;
    // Tracks the bound state of the service.
    private boolean mBound = false;

    // UI elements.
    private Button mRequestLocationUpdatesButton;
    private Button mRemoveLocationUpdatesButton;

    // Monitors the state of the connection to the service.
    private final ServiceConnection mServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            LocationUpdatesService.LocalBinder binder = (LocationUpdatesService.LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mService = null;
            mBound = false;
        }
    };

    TextView total_distance;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        myReceiver = new MyReceiver();
        setContentView(R.layout.back_services);


        database=new Database(this);

        // this.deleteDatabase("EmployeeDatabase.db");

        database.getWritableDatabase();

        total_distance=(TextView)findViewById(R.id.total_distance);


        listView=(ListView)findViewById(R.id.listView);

        // schedule the task to RUN every hour
        timer = new Timer();
        TimerTask hourlyTask = new TimerTask() {
            @Override
            public void run() {
                MainActivity.this.runOnUiThread(new Runnable() {
                    public void run() {
                        // check if GPS enabled


                            startdistance_preference = getSharedPreferences("startLessonPref", Context.MODE_PRIVATE);

                            String stringLatitude1 = startdistance_preference.getString("mlastlocationlat", null);
                            String stringLongitude1 = startdistance_preference.getString("mlastlocationlong", null);
                            // String totaldistance = startdistance_preference.getString("str_TotalDist", null);
                            float f_TotDist = startdistance_preference.getFloat("str_TotalDist", 0);
                            Log.e("RS","-runnin--f_TotDist-first-" +f_TotDist);
                            total_distance.setText("Total Distance-"+f_TotDist/1000 + " km");
                            //Log.e("RS","running---stringLatitude1-----" + stringLatitude1);

                            Toast.makeText(MainActivity.this, "distance-**-" + f_TotDist , Toast.LENGTH_LONG).show();


                            if(database.fetchData()!=null) {
                                arrayList = database.fetchData();
                                Log.e("RS","---arrayList-----" + arrayList);


                                DistanceAdap adapter = new DistanceAdap(getApplicationContext(), android.R.layout.activity_list_item, android.R.id.text1, arrayList);

                                listView.setAdapter(adapter);
                            }

                    }
                });

            }
        };
        timer.schedule(hourlyTask, 0l, 1000 * 1 * 10);

        startdistance_preference = getSharedPreferences("startLessonPref", Context.MODE_PRIVATE);

    }

    @Override
    protected void onStart() {
        super.onStart();
        PreferenceManager.getDefaultSharedPreferences(this)
                .registerOnSharedPreferenceChangeListener(this);

        mRequestLocationUpdatesButton = (Button) findViewById(R.id.request_location_updates_button);
        mRemoveLocationUpdatesButton = (Button) findViewById(R.id.remove_location_updates_button);

        mRequestLocationUpdatesButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                startdistance_preference = getSharedPreferences("startLessonPref",
                        Context.MODE_PRIVATE);
                SharedPreferences.Editor editor1 = startdistance_preference.edit();


                editor1.putFloat("str_TotalDist", (float) 0.0);

                editor1.putString("timerstart",  "0");
                editor1.commit();

                if (!checkPermissions()) {
                    requestPermissions();
                } else {
                    mService.requestLocationUpdates();
                }
            }
        });

        mRemoveLocationUpdatesButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startdistance_preference = getSharedPreferences("startLessonPref", Context.MODE_PRIVATE);

              float f_TotDist = startdistance_preference.getFloat("str_TotalDist", 0);
                Log.e("RS","-runnin--f_TotDist-first-" +f_TotDist);
                total_distance.setText("Total distance"+f_TotDist/   1000+"km");
                mService.removeLocationUpdates();
            }
        });

        // Restore the state of the buttons when the activity (re)launches.
        setButtonsState(Utils.requestingLocationUpdates(this));

        // Bind to the service. If the service is in foreground mode, this signals to the service
        // that since this activity is in the foreground, the service can exit foreground mode.
        bindService(new Intent(this, LocationUpdatesService.class), mServiceConnection,
                Context.BIND_AUTO_CREATE);
    }


    @Override
    protected void onStop() {
        if (mBound) {
            // Unbind from the service. This signals to the service that this activity is no longer
            // in the foreground, and the service can respond by promoting itself to a foreground
            // service.
            unbindService(mServiceConnection);
            mBound = false;
        }
        PreferenceManager.getDefaultSharedPreferences(this)
                .unregisterOnSharedPreferenceChangeListener(this);
        super.onStop();
    }



    private void setButtonsState(boolean requestingLocationUpdates) {
        if (requestingLocationUpdates) {
            mRequestLocationUpdatesButton.setEnabled(false);
            mRemoveLocationUpdatesButton.setEnabled(true);
        } else {
            mRequestLocationUpdatesButton.setEnabled(true);
            mRemoveLocationUpdatesButton.setEnabled(false);
        }
    }
}

注意:我引用了这个链接,只是我使用的相同代码,但当我删除startforeground的通知意味着当app清除堆栈时,位置没有在所有版本中更新。我想计算每2分钟的距离

  

https://github.com/googlesamples/android-play-location/tree/master/LocationUpdatesForegroundService/app/src/main/java/com/google/android/gms/location/sample/locationupdatesforegroundservice

0 个答案:

没有答案
相关问题