【问题标题】:Track user location like Google does像 Google 一样跟踪用户位置
【发布时间】:2015-04-24 18:55:13
【问题描述】:

我正在开发一个必须跟踪用户位置并将其发送到远程服务器的应用程序。我知道这里已经有很多关于此的其他问题,但我无法找到我需要的确切内容。

基本上我使用FusedLocationProviderApi 来接收位置更新。它非常有用且易于使用。问题是我需要经常查询位置并且它会很快耗尽电池(尽管电池使用的一部分可能来自网络操作以将位置发送到服务器)。但是,我只需要在用户移动时频繁更新。

所以我正在寻找类似于 Google 的东西来跟踪 Android 用户(正如我们在 LocationHistory 中看到的那样)。有谁知道谷歌从智能手机获得的位置是否在某处可用?或者也许是实施类似的策略?

【问题讨论】:

  • 降低电池消耗的建议,您可以使用活动检测来确定您需要多久确定一次位置。在这方面,我可以推荐github.com/mcharmas/Android-ReactiveLocation,我在活动检测部分做出了贡献。该库还大大减少了获取融合位置所需的编码行数。
  • 我必须说我不知道​​ ActivityRecognitionApi 似乎正是我需要的。会尝试的。谢谢!
  • 没问题 :) 根据我的经验,尽管电池消耗低,但它的表现出奇地好
  • @cYrixmorten 我在查找 ActivityDetectionApi 的示例和文档时遇到了一些麻烦。 Everywhere 似乎都指向此链接 (developer.android.com/training/location/index.html),但我在任何地方都找不到示例……你知道我在哪里可以找到它吗?

标签: android fusedlocationproviderapi


【解决方案1】:

关于降低电池消耗的建议,您可以使用活动检测来确定您需要多久确定一次位置。在这方面,我可以推荐https://github.com/mcharmas/Android-ReactiveLocation,我在活动检测部分做出了贡献。该库还大大减少了获取融合位置所需的编码行数。

该库在此处包含一个简单的使用示例:https://github.com/mcharmas/Android-ReactiveLocation/blob/master/sample/src/main/java/pl/charmas/android/reactivelocation/sample/MainActivity.java

正如您在评论中所写,要找到使用 ActivityDetectionApi 的好例子并不容易。这也是我将其添加到库中的原因之一。事实上,当时 google 提供的文档已经过时,因为他们更新了 Google Play Services API,但没有更新教程。

对于不使用该库的教程,我没有任何好的指导,但我可以使用 ReactiveLocation 提供我的代码的 sn-p。此代码在服务中运行,因此无论应用是否处于焦点,它都会跟踪当前活动:

private void requestFilteredActivityUpdates() {

    ReactiveLocationProvider locationProvider = new ReactiveLocationProvider(getApplicationContext());
    filteredActivitySubscription = locationProvider.getDetectedActivity(0).doOnError(new Action1<Throwable>() {
        @Override
        public void call(Throwable throwable) {
            String message = "Error on activitySubscription: " + throwable.getMessage();
            Log.e(TAG, message, throwable);
            Crashlytics.logException(throwable);
        }
    }).onErrorReturn(new Func1<Throwable, ActivityRecognitionResult>() {
        @Override
        public ActivityRecognitionResult call(Throwable throwable) {
            List<DetectedActivity> list = new ArrayList<DetectedActivity>();
            list.add(new DetectedActivity(DetectedActivity.UNKNOWN, 0));
            return new ActivityRecognitionResult(list, System.currentTimeMillis(), SystemClock.elapsedRealtime());
        }
    }).filter(new Func1<ActivityRecognitionResult, Boolean>() {
        @Override
        public Boolean call(ActivityRecognitionResult activityRecognitionResult) {

            DetectedActivity detectedActivity = activityRecognitionResult.getMostProbableActivity();

            boolean highConfidence =  detectedActivity.getConfidence() > 75;


            DetectedActivity previousActivity = ActivityDetectionModule.Recent.getDetectedActivity();
            boolean isNewActivity = detectedActivity.getType() != previousActivity.getType();
            boolean hasHigherConfidence = detectedActivity.getConfidence() > previousActivity.getConfidence();


            return mJustStarted || (highConfidence && (isNewActivity || hasHigherConfidence)); 
        }
    }).subscribe(new Action1<ActivityRecognitionResult>() {
        @Override
        public void call(ActivityRecognitionResult activityRecognitionResult) {

            DetectedActivity detectedActivity = activityRecognitionResult.getMostProbableActivity();

            Log.i(TAG, "Activity changed or increased in confidence:");

            Log.i(TAG, "New: " + ActivityDetectionModule.getNameFromType(detectedActivity.getType()) + " confidence: " + detectedActivity.getConfidence());

        }
    });
}

我打电话给onDestroy()

public void unsubscribeActivityUpdates() {
    unsubscribe(filteredActivitySubscription);
}

private void unsubscribe(Subscription subscription) {
    if (subscription != null && !subscription.isUnsubscribed()) {
        Log.i(TAG, "Unsubscribe activity updates");
        try {
            subscription.unsubscribe();
        } catch (Exception e) {
            e.printStackTrace();
        }
        subscription = null;
    }
}

我希望这足以说明如何使用该库,否则请随时提问。

【讨论】:

    【解决方案2】:

    您可以根据需要使用 LocationRequest..

    LocationRequest location= new LocationRequest();
    

    我确定构造函数接受了一个值..检查 android 文档。

    因此,对于位置请求,您有类似的功能,

    设置间隔,设置最小位移,每隔几秒或他移动几米获取位置。

    您还可以为此实现一个位置侦听器,每次获取新位置时都会调用它。

    最后你要做的就是从融合的 api 请求位置更新并将请求作为参数传递。

    【讨论】:

    • 我知道 LocationRequest。正如我所说,我正在使用 FusedLocationProviderApi 来获取位置。这意味着我已经使用具有指定间隔的请求来获取位置更新。我想要的是一些聪明的策略来根据用户的移动改变请求更新间隔,就像谷歌一样(用户移动时更新更快,用户停止时更新更慢等)。
    • 糟糕!抱歉..我有一个想法,但请让我为您提供一些资源来确定。
    • 等等!正如我在答案中提到的......你是否尝试设置最小位移,这就是你正在寻找的那个。当你快速旅行时它不会发送更多更新,只是当你快速移动时你会更快地满足距离参数,比如如果它是 50 米..如果我在车里,我会很快得到我的更新,而不是走路
    • 确实如此。我没有使用最小位移,因为我认为更新间隔优先于位移。真正发生的是,我使用了非常小的位移,即使我站着不动,gps 的变化也比我的位移阈值大。也许最小的位移方法可以是我所需要的。我会再做一些测试让你知道
    【解决方案3】:

    您可以使用FusedLocationProviderApi 通知您位置更改,而不是查询当前位置。

    您可能想要使用 requestLocationUpdates,特别是 this version,它最适合用于后台任务。 在 LocationRequest 中,您可以使用setInterval 来定义更新间隔。

    关于电池消耗:显然,不断打开网络套接字(或保持它们打开)以发送您的位置数据并不是最佳解决方案。您的应用应确定何时需要向您的服务器发送更新。

    Google 不提供直接提取 LocationHistory 的 API,这是他们自己保留的。你可以查询kml位置文件并读取它,但这更不适合实时监控。

    【讨论】:

    • 正如我所说,我已经在使用 FusedLocationApi。不过,您说得对,不断打开网络套接字不是一个好主意。我将在应用程序的未来版本中更改它。
    • 是的,您这样做了,但是您是否按照我描述的方式使用 requestLocationUpdates() ?正如您所写,您经常查询,这听起来像是您经常请求当前位置,而不是使用 PendingIntent 接收广播。
    • 是的。这正是我正在做的。我通过 PendingIntent 获得更新。我正在寻找的是一种更智能的方式来调整更新频率,而不是请求更新的方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-04
    相关资源
    最近更新 更多