Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/192.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在后台接收位置更新?(API 26)_Java_Android_Geolocation_Updates - Fatal编程技术网

Java 如何在后台接收位置更新?(API 26)

Java 如何在后台接收位置更新?(API 26),java,android,geolocation,updates,Java,Android,Geolocation,Updates,我需要从应用程序中获取我的应用程序的连续位置更新。为此,我遵循了获取位置更新的步骤。因为在API 26中无法在后台接收位置更新,所以我添加了一个前台服务()。但是,我仍然只在前台有其他请求位置更新的活动时接收更新 定位服务: public class LocationUpdateService extends Service { private static final String TAG = LocationUpdateService.class.getSimpleName(); pri

我需要从应用程序中获取我的应用程序的连续位置更新。为此,我遵循了获取位置更新的步骤。因为在API 26中无法在后台接收位置更新,所以我添加了一个前台服务()。但是,我仍然只在前台有其他请求位置更新的活动时接收更新

定位服务:

public class LocationUpdateService extends Service {

private static final String TAG = LocationUpdateService.class.getSimpleName();

private static final String NOTIFICATION_CHANNEL_ID = "TrackNotification";
private static final int FOREGROUND_SERVICE_ID = 1;
private static final int NOTIFICATION_ID = 1;
public static final String STATUS_INTENT = "status";
private static final int CONFIG_CACHE_EXPIRY = 600;

private NotificationManager mNotificationManager;
private NotificationCompat.Builder mNotificationBuilder;

private DatabaseReference mDatabaseReference;

private FusedLocationProviderClient mFusedLocationProviderClient;
private LocationRequest mLocationRequest;

private FirebaseRemoteConfig mFirebaseRemoteConfig;

private String uid;

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

    uid = FirebaseAuth.getInstance().getUid();
    if(uid == null)
        stopSelf();

    mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
    FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder().build();
    mFirebaseRemoteConfig.setConfigSettings(configSettings);
    mFirebaseRemoteConfig.setDefaults(R.xml.remode_config_defaults);
    fetchRemoteConfig();

    mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
    mDatabaseReference = FirebaseDatabase.getInstance().getReference();

    mLocationRequest = new LocationRequest()
            .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
            .setFastestInterval(mFirebaseRemoteConfig.getLong("LOCATION_REQUEST_INTERVAL"))
            .setFastestInterval(mFirebaseRemoteConfig.getLong("LOCATION_REQUEST_INTERVAL_FASTEST"));

    bindNotification();
    setStatusMessage(R.string.connecting);


    startLocationTracking();
}

private LocationCallback mLocationCallback = new LocationCallback() {
    @Override
    public void onLocationResult(LocationResult locationResult) {
        Log.d(TAG,"Got location update!");
        if(locationResult == null)
            return;
        for(Location location : locationResult.getLocations()) {

            CustomLocation customLocation = LocationAdapter.toDatabaseLocation(location);
            mDatabaseReference.child("locations").child(uid).setValue(customLocation);
        }

    }

    @Override
    public void onLocationAvailability(LocationAvailability locationAvailability) {
        locationAvailability.isLocationAvailable();
        // TODO handle no location here
        super.onLocationAvailability(locationAvailability);
    }
};

@SuppressWarnings({"MissingPermission"})
private void startLocationTracking() {
    mFusedLocationProviderClient.requestLocationUpdates(mLocationRequest,mLocationCallback, Looper.myLooper());
}


private void fetchRemoteConfig() {
    mFirebaseRemoteConfig.fetch(CONFIG_CACHE_EXPIRY)
            .addOnCompleteListener(new OnCompleteListener<Void>() {
        @Override
        public void onComplete(@NonNull Task<Void> task) {
            Log.i(TAG,"Remote config fetched");
            mFirebaseRemoteConfig.activateFetched();
        }
    });
}

@Override
public void onDestroy() {
    setStatusMessage(R.string.not_tracking);
    mNotificationManager.cancel(NOTIFICATION_ID);
    mFusedLocationProviderClient.removeLocationUpdates(mLocationCallback);
    super.onDestroy();
}

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

private void bindNotification() {
    mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    PendingIntent resultPendingIntent = PendingIntent.getActivity(this,0,
            new Intent(this, MainActivity.class),PendingIntent.FLAG_UPDATE_CURRENT);

    mNotificationBuilder = new NotificationCompat.Builder(this,NOTIFICATION_CHANNEL_ID)
            .setCategory(NotificationCompat.CATEGORY_STATUS)
            .setShowWhen(false)
            .setSmallIcon(R.drawable.ic_car)
    //        .setColor(getColor(R.color.colorPrimary))
            .setContentTitle(getString(R.string.app_name))
            .setOngoing(true)
            .setContentIntent(resultPendingIntent);
    startForeground(FOREGROUND_SERVICE_ID, mNotificationBuilder.build());
}

/**
 *
 * @param message Status message to display
 */
private void setStatusMessage(String message) {
    mNotificationBuilder.setContentText(message);
    mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());

    Intent intent = new Intent(STATUS_INTENT);
    intent.putExtra(getString(R.string.status),message);
    LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}

private void setStatusMessage(int resID) {
    setStatusMessage(getString(resID));
}
}
Android清单:

<service android:name=".LocationUpdateService" />

EDIT1:我现在在较旧的API版本(22)上测试了它,但问题仍然是一样的:只要一些带有位置请求的应用在前台,它就可以工作,否则就不行。
也许FusedLocationProviderClient有问题,但我不知道是什么问题。我只找到了使用旧FusedLocationProvider API的代码示例,该API现在已被弃用。

您是否尝试过调试以确保您的服务被命中

这听起来可能很愚蠢,但您是否检查过您的服务是否已在您的清单中注册?我知道我肯定遇到过这个问题

<service android:name=".LocationService"
        android:label="Location Service"
        android:exported="true"
        android:enabled="true"
        android:process=":location_background_service"/>
可以为不同的提供程序创建多个实例。在我的例子中,我最终使用了2

LocationListener[] mLocationListeners = new LocationListener[]{
        new LocationListener(LocationManager.GPS_PROVIDER),
        new LocationListener(LocationManager.NETWORK_PROVIDER)
};
然后我初始化了一个LocationManager,它可以为LocationListener中的每个节点设置轮询速率

private void initializeLocationManager() {
    Log.e(TAG, "initializeLocationManager");
    if (mLocationManager == null) {
        mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
    }
}
然后在ServiceOnCreate函数中,初始化LocationManager,并将其中一个侦听器用作主要源,另一个用作备用源

try {
        mLocationManager.requestLocationUpdates(
                LocationManager.NETWORK_PROVIDER,
                5 * 60 * 1000, //5 Minutes
                1F /*METERS*/,
                mLocationListeners[0]
        );
    } catch (java.lang.SecurityException ex) {
        Log.e(TAG, "failed to request location update. Insufficient permissions. ", ex);
        try {
            mLocationManager.requestLocationUpdates(
                    LocationManager.NETWORK_PROVIDER,
                    5 * 60 * 1000, //5 Minutes
                    1F /*METERS*/,
                    mLocationListeners[1]
            );
        } catch (java.lang.SecurityException e) {
            Log.e(TAG, "failed to request location update. Insufficient permissions. ", e);
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "Network provider does not exist.", e);
        }
    } catch (IllegalArgumentException ex) {
        Log.e(TAG, "Network provider does not exist.", ex);
    }
}

(很抱歉,如果此代码很糟糕,这是一个快速而肮脏的示例。)

您是否尝试过调试以确保您的服务被命中

这听起来可能很愚蠢,但您是否检查过您的服务是否已在您的清单中注册?我知道我肯定遇到过这个问题

<service android:name=".LocationService"
        android:label="Location Service"
        android:exported="true"
        android:enabled="true"
        android:process=":location_background_service"/>
可以为不同的提供程序创建多个实例。在我的例子中,我最终使用了2

LocationListener[] mLocationListeners = new LocationListener[]{
        new LocationListener(LocationManager.GPS_PROVIDER),
        new LocationListener(LocationManager.NETWORK_PROVIDER)
};
然后我初始化了一个LocationManager,它可以为LocationListener中的每个节点设置轮询速率

private void initializeLocationManager() {
    Log.e(TAG, "initializeLocationManager");
    if (mLocationManager == null) {
        mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
    }
}
然后在ServiceOnCreate函数中,初始化LocationManager,并将其中一个侦听器用作主要源,另一个用作备用源

try {
        mLocationManager.requestLocationUpdates(
                LocationManager.NETWORK_PROVIDER,
                5 * 60 * 1000, //5 Minutes
                1F /*METERS*/,
                mLocationListeners[0]
        );
    } catch (java.lang.SecurityException ex) {
        Log.e(TAG, "failed to request location update. Insufficient permissions. ", ex);
        try {
            mLocationManager.requestLocationUpdates(
                    LocationManager.NETWORK_PROVIDER,
                    5 * 60 * 1000, //5 Minutes
                    1F /*METERS*/,
                    mLocationListeners[1]
            );
        } catch (java.lang.SecurityException e) {
            Log.e(TAG, "failed to request location update. Insufficient permissions. ", e);
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "Network provider does not exist.", e);
        }
    } catch (IllegalArgumentException ex) {
        Log.e(TAG, "Network provider does not exist.", ex);
    }
}

(很抱歉,如果此代码很糟糕,这是一个快速而肮脏的示例。)

您可以尝试此问题的答案:您可以尝试此问题的答案:是。通知会显示出来,如果我在前台运行像Google maps这样的应用程序,我会得到位置更新。那么进程属性是什么呢?据我所知,由于服务与实际应用程序是分开的,这是一个任意的名字,你给你的前台服务,这样你可以调试它更容易。我在控制台上得到所有调试信息。如果我在前台运行“地图”,我会收到消息“获取位置更新”。但只有到那时。看起来问题出在Android的后台限制上,但我不确定。你试过用这个调试它吗?控制台不会显示来自前台服务的消息,除非您更改正在侦听的进程,因为它们在技术上是独立的进程。是的。通知会显示出来,如果我在前台运行像Google maps这样的应用程序,我会得到位置更新。那么进程属性是什么呢?据我所知,由于服务与实际应用程序是分开的,这是一个任意的名字,你给你的前台服务,这样你可以调试它更容易。我在控制台上得到所有调试信息。如果我在前台运行“地图”,我会收到消息“获取位置更新”。但只有到那时。看起来问题出在Android的后台限制上,但我不确定。你试过用这个调试它吗?控制台不会显示来自前台服务的消息,除非您更改正在侦听的进程,因为它们在技术上是独立的进程。