首页 > 解决方案 > 当应用程序在 Nougat(版本 25)事件中从后台清除时,服务未运行,尽管我使用了 startforegound 通知

问题描述

因为我想使用服务中的 googleapiclient 位置计算每两分钟的距离。

在版本 25 中(从缓存中清除应用程序时,牛轧糖服务不工作)

我在活动中启动了服务并在启动命令中给出了 start_sticky ,没有通知它也应该正常工作吗?低于奥利奥版本。

对于 oreo 版本,我添加了 startforeground 通知,因此在 oreo 版本中工作,即使应用程序从后台清除但在牛轧糖中相同的代码在有或没有通知的情况下都不起作用,当我从后台服务中清除应用程序时没有运行。请帮助我。

低于版本> 25 在没有通知的情况下工作,当应用程序也从缓存中清除时,服务正在运行。但在版本 25 中,我不知道为什么清除表单缓存时服务没有运行。请有人帮助我。

服务代码:

 public class ForegroundLocationService extends Service implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        LocationListener {
    Double mlastlocationlat,mlastlocationlong,mcurrentlocationlat,mcurrentlocationlong;
    SharedPreferences sharedPreferences,startdistance_preference;
    SharedPreferences.Editor editor;
    float f_TotDist ;
    int timercount;
    Database database;
    private static final String TAG = ForegroundLocationService.class.getSimpleName();

    // the notification id for the foreground notification
    public static final int GPS_NOTIFICATION = 1;

    // the interval in seconds that gps updates are requested
    private static final int UPDATE_INTERVAL_IN_SECONDS = 15;

    // is this service currently running in the foreground?
    private boolean isForeground = false;

    // the google api client
    private GoogleApiClient googleApiClient;

    // the wakelock used to keep the app alive while the screen is off
    private PowerManager.WakeLock wakeLock;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("KS", "oncreate " );

        // create google api client
        googleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();

        // get a wakelock from the power manager
        final PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
        Log.i("KS", "oncreate wakeLock"+wakeLock );

        database=new Database(this);

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

        database.getWritableDatabase();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("KS", "onstartcommand " );

        if (!isForeground) {

            Log.i("KS", "Starting the isForeground" + isForeground);

        startForeground(ForegroundLocationService.GPS_NOTIFICATION,
                  notifyUserThatLocationServiceStarted());
            isForeground = true;
            Utils.setRequestingLocationUpdates(this, true);

            // connect to google api client
            googleApiClient.connect();

            // acquire wakelock
            wakeLock.acquire();
        }

        return START_STICKY;
    }

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

    @Override
    public void onDestroy() {

        Log.i("KS", "ondestroy the " + this.getClass().getSimpleName());

     stopForeground(true);
        isForeground = false;

        // disconnect from google api client
        googleApiClient.disconnect();
        Utils.setRequestingLocationUpdates(this, false);

        // release wakelock if it is held
        if (null != wakeLock && wakeLock.isHeld()) {
            Log.i("KS", "if destroy" + wakeLock);

            wakeLock.release();
        }

        super.onDestroy();
    }

    private LocationRequest getLocationRequest() {
        Log.i("KS", "getLocationRequest " );

        LocationRequest locationRequest = LocationRequest.create();

        // we always want the highest accuracy
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        // we want to make sure that we get an updated location at the specified interval
        locationRequest.setInterval(5000);
        locationRequest.setSmallestDisplacement(0);

        // this sets the fastest interval that the app can receive updates from other apps accessing
        // the location service. for example, if Google Maps is running in the background
        // we can update our location from what it sees every five seconds
        locationRequest.setFastestInterval(5000);
        locationRequest.setMaxWaitTime(TimeUnit.SECONDS.toMillis(UPDATE_INTERVAL_IN_SECONDS));

        return locationRequest;
    }

    private Notification notifyUserThatLocationServiceStarted() {
        Log.i("KS", "notifyUserThatLocationServiceStarted " );

        // pop up a notification that the location service is running
        Intent notificationIntent = new Intent(this, NotificationActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);

        final Notification.Builder builder = new Notification.Builder(this)
                .setSmallIcon(R.drawable.getspot_logo)
                .setContentTitle(getString(R.string.foreground_location_service))
                .setContentText(getString(R.string.service_is_running))
                 .setWhen(System.currentTimeMillis());

        final Notification notification;

String CHANNEL_ID = "channel_01";
        Notification notification1= 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.
            notification1 = new Notification.Builder(this)

                    .setChannelId(CHANNEL_ID)

                    .setContentTitle(getString(R.string.foreground_location_service))
                    .setContentText(getString(R.string.service_is_running))
                    .setOngoing(true)
                    .setPriority(Notification.PRIORITY_HIGH)
                    .setSmallIcon(R.mipmap.ic_launcher)


                    .build();

            notification=notification1;
        }
        else
        {
            notification=builder.build();;

        }



        return notification;
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        Log.i("KS", "onConnected " );

        try {

            // request location updates from the fused location provider
            LocationServices.FusedLocationApi.requestLocationUpdates(
                    googleApiClient, getLocationRequest(), this);

        } catch (SecurityException securityException) {
            Log.e(TAG, "Exception while requesting location updates", securityException);
        }
    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.i(TAG, "Google API Client suspended.");
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        Log.e(TAG, "Failed to connect to Google API Client.");
    }

    @Override
    public void onLocationChanged(Location location) {
        Log.i("KS", "onLocationChanged: " + location.toString());
        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()));

        Log.e("RS","shared--" + sharedPreferences.getString("mlastlocationlat", null));


        if(sharedPreferences.getString("mlastlocationlat", null)==null && sharedPreferences.getString("mlastlocationlong", null)==null && sharedPreferences.getString("mcurrentlocationlat", null)==null && sharedPreferences.getString("mcurrentlocationlong", null)==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= Double.valueOf(sharedPreferences.getString("mcurrentlocationlat", null));
            mlastlocationlong=Double.valueOf(sharedPreferences.getString("mcurrentlocationlong", null));
            ;
            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);

    }
    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 SampleBackgroundServices extends AppCompatActivity implements
        SharedPreferences.OnSharedPreferenceChangeListener {


    // the identifier for the permissions request
    private static final int PERMISSION_REQUEST_ID = 1999;
    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;

    SharedPreferences sharedPreferences;
    SharedPreferences.Editor editor;
    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;
    TextView total_distance;
    // UI elements.
    private Button mRequestLocationUpdatesButton;
    private Button mRemoveLocationUpdatesButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.back_services);

        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) {
                startService(new Intent(getApplicationContext(), ForegroundLocationService.class));

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


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



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

                editor.commit();


            }
        });

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

                stopService(new Intent(getApplicationContext(), ForegroundLocationService.class));


            }
        });


    }

    @Override
    public void onResume() {



        super.onResume();
    }



}

注意:我不知道如何在牛轧糖中解决这个问题,请给我解决方案。奥利奥版本只会停止,所以我们使用通知,牛轧糖现在也有问题。

清单文件:

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.getspot.getspot">

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <application

        android:allowBackup="true"
        android:hardwareAccelerated="false"
        android:icon="@drawable/getspot_logo"
        android:label="@string/app_name"
        android:largeHeap="true"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".activities.SplashScreen"
            android:screenOrientation="portrait"
            android:configChanges="keyboardHidden|orientation|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".background_services.ForegroundLocationService"
            android:enabled="true" />


    </application>

</manifest>

标签: androidservicelocation

解决方案


在 Android 7.0(API 级别 25)、Android 8.0(API 级别 26)中,后台服务和执行由 android 限制。由于应用程序在后台运行,它会消耗设备的一些有限资源,例如 RAM。更多细节

迁移指南

默认情况下,这些更改仅影响面向 Android 8.0(API 级别 26)或更高版本的应用。但是,用户可以从“设置”屏幕为任何应用启用这些限制,即使应用的目标 API 级别低于 26。您可能需要更新应用以符合新限制。

检查您的应用如何使用服务。如果您的应用程序依赖于在您的应用程序空闲时在后台运行的服务,您将需要替换它们。可能的解决方案包括:

如果您的应用需要在应用处于后台时创建前台服务,请使用startForegroundService()方法而不是startService()。 如果用户注意到该服务,则将其设为前台服务。例如,播放音频的服务应该始终是前台服务。使用startForegroundService()方法而不是startService()创建服务. 找到一种方法来使用计划的作业复制服务的功能。如果服务没有做用户立即注意到的事情,您通常应该能够使用计划的作业来代替。当网络事件发生时,使用 FCM 选择性地唤醒您的应用程序,而不是在后台轮询。推迟后台工作,直到应用程序自然处于前台。查看应用清单中定义的广播接收器。如果您的清单声明了隐式广播的接收器,则必须替换它。可能的解决方案包括:

通过调用Context.registerReceiver() 在运行时创建接收器,而不是在清单中声明接收器。使用计划作业检查会触发隐式广播的条件。


推荐阅读