请求位置更新的时间间隔未在前台服务中获取位置更新?

问题描述 投票:0回答:2

我创建了一个前台服务,每 1 分钟获取一次位置,但不知何故,该服务在一分钟后就不再获取位置了。

我正在奥利奥前台服务之前创建一项服务,在服务中的奥利奥前台服务之后我正在尝试注册位置更新,但问题是在杀死应用程序后仅一分钟我就得到了位置更新,之后我无法获得其他服务比前台服务通知。

MainActivity.java

package com.practice.satya.foreground;

import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startService();
    }
    public void startService() {
        if(Build.VERSION.SDK_INT >25){
            startForegroundService(new Intent(this, LocationFetchInForeground.class));
        }else{
            startService(new Intent(this, LocationFetchInForeground.class));
        }
    }
}



LocationUpdatesReceiver.java

package com.practice.satya.foreground;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v4.app.NotificationCompat;

public class LocationUpdatesReceiver extends BroadcastReceiver {
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public void onReceive(Context context, Intent intent) {
        showNotification(context,"Location Changed","Updated location",intent);
    }
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public void showNotification(Context context, String title, String body, Intent intent) {
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        int notificationId = 93;
        String channelId = "testing";
        String channelName = "testing chanel";
        int importance = NotificationManager.IMPORTANCE_HIGH;

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel mChannel = new NotificationChannel(
                    channelId, channelName, importance);
            notificationManager.createNotificationChannel(mChannel);
        }

        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, channelId)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle(title)
                .setContentText(body);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
        stackBuilder.addNextIntent(intent);
        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
                0,
                PendingIntent.FLAG_UPDATE_CURRENT
        );
        mBuilder.setContentIntent(resultPendingIntent);

        notificationManager.notify(notificationId, mBuilder.build());
    }
}

LocationFetchInForeground.java

package com.practice.satya.foreground;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;

public class LocationFetchInForeground extends Service {
    private SensorManager sensorManager;
    private Sensor sensor;
    private TriggerEventListener triggerEventListener;

    /** indicates how to behave if the service is killed */
    int mStartMode;

    /** interface for clients that bind */
    IBinder mBinder;

    /** indicates whether onRebind should be used */
    boolean mAllowRebind;

    private static final String TAG = "MyLocationService";
    private LocationManager mLocationManager = null;
    private static final int LOCATION_INTERVAL = 1000;
    private static final float LOCATION_DISTANCE = 0f;

    private class LocationListener implements android.location.LocationListener {
        Location mLastLocation;

        public LocationListener(String provider) {
            Log.e(TAG, "LocationListener " + provider);
            mLastLocation = new Location(provider);
        }

        @Override
        public void onLocationChanged(Location location) {
            Log.e(TAG, "onLocationChanged: " + location);
            Toast.makeText(getApplicationContext(),"onLocationUpdated", Toast.LENGTH_LONG).show();
            Intent intent=new Intent();
            showNotification(getApplicationContext(),"Location Changed","Updated location",intent);
            mLastLocation.set(location);
        }

        @Override
        public void onProviderDisabled(String provider) {
            Log.e(TAG, "onProviderDisabled: " + provider);
        }

        @Override
        public void onProviderEnabled(String provider) {
            Log.e(TAG, "onProviderEnabled: " + provider);
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            Log.e(TAG, "onStatusChanged: " + provider);
        }
    }

    /*
    LocationListener[] mLocationListeners = new LocationListener[]{
            new LocationListener(LocationManager.GPS_PROVIDER),
            new LocationListener(LocationManager.NETWORK_PROVIDER)
    };
    */

    LocationListener[] mLocationListeners = new LocationListener[]{
            new LocationListener(LocationManager.GPS_PROVIDER)
    };



    /** Called when the service is being created. */
    @Override
    public void onCreate() {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //For creating the Foreground Service
            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            String channelId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? getNotificationChannel(notificationManager) : "";
            NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId);
            Notification notification = notificationBuilder.setOngoing(true)
                    .setContentTitle("Location service")
                    .setContentText("This service is used to fetch location in background")
                    .setSmallIcon(R.mipmap.ic_launcher)
                    // .setPriority(PRIORITY_MIN)
                    .setCategory(NotificationCompat.CATEGORY_SERVICE)
                    .build();
            startForeground(1, notification);
        }
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        sensor = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);

        triggerEventListener = new TriggerEventListener() {
            @Override
            public void onTrigger(TriggerEvent event) {
                // Do work
                Toast.makeText(getApplicationContext(), "Location Updated", Toast.LENGTH_LONG).show();
                Intent intent = new Intent();
                showNotification(getApplicationContext(), "Motion Changed", "Updated location", intent);
            }
        };
        if (sensor != null) {
            sensorManager.requestTriggerSensor(triggerEventListener, sensor);
        }


        Log.e(TAG, "onCreate");

        initializeLocationManager();
    }

    /** The service is starting, due to a call to startService() */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Let it continue running until it is stopped.
        Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
            try {

//                Intent intenter = new Intent(this,LocationUpdatesReceiver.class);
//                PendingIntent proximityIntent = PendingIntent.getBroadcast(this, 0, intenter, PendingIntent.FLAG_UPDATE_CURRENT);
//                mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
//                        LOCATION_INTERVAL,
//                        LOCATION_DISTANCE,
//                        proximityIntent);
                Intent intenter2 = new Intent(this,LocationUpdatesReceiver.class);
                PendingIntent proximityIntent2 = PendingIntent.getBroadcast(this, 0, intenter2, PendingIntent.FLAG_UPDATE_CURRENT);
                mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                        LOCATION_INTERVAL,
                        LOCATION_DISTANCE,
                        proximityIntent2);
//
//            mLocationManager.requestLocationUpdates(
//                    LocationManager.GPS_PROVIDER,
//                    LOCATION_INTERVAL,
//                    LOCATION_DISTANCE,
//                    mLocationListeners[0]
//            );

            } catch (java.lang.SecurityException ex) {
                Log.i(TAG, "fail to request location update, ignore", ex);
            } catch (IllegalArgumentException ex) {
                Log.d(TAG, "network provider does not exist, " + ex.getMessage());
            }
        return START_STICKY;
    }

    /** A client is binding to the service with bindService() */
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    /** Called when all clients have unbound with unbindService() */
    @Override
    public boolean onUnbind(Intent intent) {
        return mAllowRebind;
    }

    /** Called when a client is binding to the service with bindService()*/
    @Override
    public void onRebind(Intent intent) {

    }

    /** Called when The service is no longer used and is being destroyed */

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
        Log.e(TAG, "onDestroy");
        super.onDestroy();
        if (mLocationManager != null) {
            for (int i = 0; i < mLocationListeners.length; i++) {
                try {
                    if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                        return;
                    }
                    mLocationManager.removeUpdates(mLocationListeners[i]);
                } catch (Exception ex) {
                    Log.i(TAG, "fail to remove location listener, ignore", ex);
                }
            }
        }
    }
    private void initializeLocationManager() {
        Log.e(TAG, "initializeLocationManager - LOCATION_INTERVAL: "+ LOCATION_INTERVAL + " LOCATION_DISTANCE: " + LOCATION_DISTANCE);
        if (mLocationManager == null) {
            mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
        }
    }
    @RequiresApi(Build.VERSION_CODES.O)
    private String getNotificationChannel(NotificationManager notificationManager){
        String channelId = "ForegroundLocationFetch";
        String channelName = getResources().getString(R.string.app_name);
        NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
        channel.setImportance(NotificationManager.IMPORTANCE_NONE);
        channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
        notificationManager.createNotificationChannel(channel);
        return channelId;
    }

    public void showNotification(Context context, String title, String body, Intent intent) {
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        int notificationId = 234;
        String channelId = "testing";
        String channelName = "testing chanel";
        int importance = NotificationManager.IMPORTANCE_HIGH;

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel mChannel = new NotificationChannel(
                    channelId, channelName, importance);
            notificationManager.createNotificationChannel(mChannel);
        }

        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, channelId)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle(title)
                .setContentText(body);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
        stackBuilder.addNextIntent(intent);
        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
                0,
                PendingIntent.FLAG_UPDATE_CURRENT
        );
        mBuilder.setContentIntent(resultPendingIntent);

        notificationManager.notify(notificationId, mBuilder.build());
    }
}


AndroidManifest.xml

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

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-feature android:name="android.hardware.location.network"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".LocationFetchInForeground" />
        <receiver android:name=".LocationUpdatesReceiver"/>
    </application>

</manifest>



android service location locationlistener foreground-service
2个回答
1
投票

如果您的代码工作正常,有时 Android 会因为省电而限制位置更新,因此请确保您的手机已充电 超过 30%,您的位置处于“高精度”状态:

package de.conlance.kotlinclean.stackoverflow

import android.annotation.SuppressLint
import android.app.Notification.EXTRA_NOTIFICATION_ID
import android.content.Intent
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import android.app.*
import android.content.Context
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
import de.conlance.kotlinclean.R


class ForGroundService : Service() {
    companion object {
        val CHANNEL_ID = "1956"
        val notificationId = 252
        val ACTION_SNOOZE = "de.conlance.kotlinclean.stopservice"
        var cnt = 0

    }

    var locationListener: LocationListener? = null
    var locationManager: LocationManager? = null
    override fun onBind(intent: Intent?): IBinder? = null
    override fun onCreate() {
        // Start up the thread running the service
        createCh()
        startForeground(notificationId, NotificationCompat.Builder(this, CHANNEL_ID).build())


    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {

        // If we get killed, after returning from here, restart
        //Main Thread
        showNotification("Service is Running")
        doWork()
        return START_NOT_STICKY
    }

    fun doWork() {
        getLocation() {
            showNotification(it)
        }
    }

    override fun onDestroy() {
        Log.v("ForService", "Service Is Dead")
        RemoveUpdates()
        showNotification("Service is Destroyed restart app .")
        stopForeground(true)


    }

    //Create Notification Channel ID .

    @SuppressLint("InlinedApi")
    private fun showNotification(msg: String) {
        val stopintent = Intent(this, MyBroadcastReceiver::class.java).apply {
            ACTION_SNOOZE
            putExtra(EXTRA_NOTIFICATION_ID, 0)
        }

        val stoppendingintent: PendingIntent =
            PendingIntent.getBroadcast(this, 0, stopintent, 0)

        val builder = NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle("My notification")
            .setContentText(msg)
            .setStyle(
                NotificationCompat.BigTextStyle()
                    .bigText(msg)
            )
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .addAction(
                R.mipmap.ic_launcher_round, "StopService",
                stoppendingintent
            )

        with(NotificationManagerCompat.from(this)) {
            // notificationId is a unique int for each notification that you must define
            notify(notificationId, builder.build())
        }
    }

    fun Context.getLocation(onResult: (String) -> Unit = {}) {
        val context = this
        locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager?

        locationListener = object : LocationListener {
            override fun onLocationChanged(location: Location?) {
                location?.let {
                    onResult("cntrefresh {${++cnt}} lat-> ${it.latitude} , lng ${it.longitude} ")
                    //send Location To Activity and then send it to Parse Location Function......

                }
            }

            override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
                //   Timber.tag(MyTag).v("on Status Changed $provider  $status")
            }

            override fun onProviderEnabled(provider: String?) {
                //  Timber.tag(MyTag).v("on Provider Enabled $provider")
            }

            override fun onProviderDisabled(provider: String?) {
                //   Timber.tag(MyTag).v("on Provider Disabled $provider")
            }
        }// location Listner
        try {
            locationManager?.let {
                if (it.isProviderEnabled(LocationManager.GPS_PROVIDER) && it.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
                    it.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 0f, locationListener)
                else {
                    //fail.value = Failure.GPSError
                    onResult("Gps Error")

                }

            }
        } catch (ex: SecurityException) {
            //  fail.value = Failure.SecurityError
            onResult("Permission")

        }
    }

    private fun RemoveUpdates() {
        locationListener?.let {
            locationManager?.removeUpdates(it)

        }
    }

    fun createCh() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // Create the NotificationChannel
            val name = "randname"
            val descriptionText = "dumdum"
            val importance = NotificationManager.IMPORTANCE_DEFAULT
            val mChannel = NotificationChannel(CHANNEL_ID, name, importance)
            mChannel.description = descriptionText
            // Register the channel with the system; you can't change the importance
            // or other notification behaviors after this
            val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(mChannel)
        }
    }

}

0
投票

根据我使用 Expo Go 的 React Native 项目的经验,我注意到了类似的问题。使用 Android 手机时,无论我构建应用程序还是使用 Expo Go 启动它,我只会在主动移动时收到位置更新。此行为不会发生在 iOS 上。

似乎在Android上,除非您在运动,否则更新位置的后台任务不会触发。它会在更新位置之前等待移动。

希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.