【问题标题】:Getting Current Location on Android - Currently crashing only on first app launch [Broadcast error]在 Android 上获取当前位置 - 目前仅在首次应用启动时崩溃 [广播错误]
【发布时间】:2017-10-25 12:58:01
【问题描述】:

所以我正在尝试向我的应用程序添加一些功能,以便它可以允许用户在编辑框中获取他的位置,而不必键入它。

目前我有一个“工作示例”,但其中有一个奇怪的错误:第一次启动应用程序并单击按钮获取位置时,应用程序崩溃。它不会再发生,除非您重新安装应用程序并且它只会崩溃一次。这似乎只发生在 Android 6.0 + 设备上(在 4.4 和 5.0 上根本不会崩溃)。 此外,有时它并没有真正获得位置,只是不断返回 null。

我想有更好的方法来获取位置,但这是我第一次尝试获取用户的位置,所以我不知道。

所以我的问题本质上是 2 个问题 - 有没有更好的方法来获取适用于 Android 4.4+ 的位置,以及为什么我的应用程序因非常奇怪的错误而崩溃。

错误:

system_process E/ActivityManager: Sending non-protected broadcast projekt.substratum.APP_CRASHED from system 820:system/1000 pkg android
                                                               java.lang.Throwable
                                                                   at com.android.server.am.ActivityManagerService.checkBroadcastFromSystem(ActivityManagerService.java:17973)
                                                                   at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:18545)
                                                                   at com.android.server.am.ActivityManagerService.broadcastIntent(ActivityManagerService.java:18636)
                                                                   at android.app.ContextImpl.sendBroadcast(ContextImpl.java:881)
                                                                   at com.android.server.am.AppErrors.crashApplicationInner(AppErrors.java:370)
                                                                   at com.android.server.am.AppErrors.crashApplication(AppErrors.java:305)
                                                                   at com.android.server.am.ActivityManagerService.handleApplicationCrashInner(ActivityManagerService.java:13554)
                                                                   at com.android.server.am.ActivityManagerService.handleApplicationCrash(ActivityManagerService.java:13536)
                                                                   at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:1660)
                                                                   at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2813)
                                                                   at android.os.Binder.execTransact(Binder.java:565)

我正在使用的 Location 类(不是我写的,只是做了一些小的编辑)

import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;

public class ProviderLocationTracker implements LocationListener,LocationTracker {

  // The minimum distance to change Updates in meters
  private static final long MIN_UPDATE_DISTANCE = 10;

  // The minimum time between updates in milliseconds
  private static final long MIN_UPDATE_TIME = 1000 * 60;

  private LocationManager lm;

  public enum ProviderType{
      NETWORK,
      GPS
  };
  private String provider;

  private Location lastLocation;
  private long lastTime;

  private boolean isRunning;

  private LocationUpdateListener listener;

  public ProviderLocationTracker(Context context, ProviderType type) {
    lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
    Criteria crit = new Criteria();
    crit.setAccuracy(Criteria.ACCURACY_FINE);

    if(type == ProviderType.NETWORK){
        provider = LocationManager.NETWORK_PROVIDER;
    }
    else{
        provider = LocationManager.GPS_PROVIDER;
    }

    provider = lm.getBestProvider(crit, true);

  }

  public String returnProvider(){
      return provider;
  }

  public void start(){
      if(isRunning){
          //Already running, do nothing
          return;
      }

      //The provider is on, so start getting updates.  Update current location
      isRunning = true;
      lm.requestLocationUpdates(provider, MIN_UPDATE_TIME,MIN_UPDATE_DISTANCE, this);
      lastLocation = null;
      lastTime = 0;
      return;
  }

  public void start(LocationUpdateListener update) {
      start();
      listener = update;

  }

  public void stop(){
      if(isRunning){
          lm.removeUpdates(this);
          isRunning = false;
          listener = null;
      }
  }

  public boolean hasLocation(){
      if(lastLocation == null){
          return false;
      }
      if(System.currentTimeMillis() - lastTime > 5 * MIN_UPDATE_TIME){
          return false; //stale
      }
      return true;
  }

  public boolean hasPossiblyStaleLocation(){
      if(lastLocation != null){
          return true;
      }
      return lm.getLastKnownLocation(provider)!= null;
  }

  public Location getLocation(){
      if(lastLocation == null){
          return null;
      }
      if(System.currentTimeMillis() - lastTime > 5 * MIN_UPDATE_TIME){
          return null; //stale
      }
      return lastLocation;
  }

  public Location getPossiblyStaleLocation(){
      if(lastLocation != null) {
          return lastLocation;
      }
      return lm.getLastKnownLocation(provider);
  }

  public void onLocationChanged(Location newLoc) {
      long now = System.currentTimeMillis();
      if(listener != null){
          listener.onUpdate(lastLocation, lastTime, newLoc, now);
      }
      lastLocation = newLoc;
      lastTime = now;
  }

  public void onProviderDisabled(String arg0) {
  }

  public void onProviderEnabled(String arg0) {
  }

  public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
  }

}

获取按钮点击监听器的位置:

if (checkLocationPermission()) {
  if (ContextCompat.checkSelfPermission(getContext(),
                        Manifest.permission.ACCESS_FINE_LOCATION)
                        == PackageManager.PERMISSION_GRANTED) {

     //Request location updates:
     getLocation();
   }
 }

getLocation 方法:

 public void getLocation(){

    //In case we havent started it somehow, just returns if we did
    location.start();

    double alti;
    double longti;

    if(location.hasLocation()){
        if (location.getLocation() != null) {
            alti = location.getLocation().getLatitude();
            longti = location.getLocation().getLongitude();

            locationText.setText(alti +","+longti);

        }else{
            locationText.setText("1Couldn't get location, check your GPS/NETWORK");
        }
    }else{
        if (location.getPossiblyStaleLocation() != null) {
            alti = location.getPossiblyStaleLocation().getLatitude();
            longti = location.getPossiblyStaleLocation().getLongitude();

            locationText.setText(alti + "," + longti);
        }else{
            locationText.setText("2Couldn't get location, check your GPS/NETWORK");
        }
    }
}

解决了崩溃,正如@Giovanni Terlingen 建议的那样,它是由我手机上的主题引擎引起的。仍然存在的问题是 GPS 位置获取并不总是有效 - 对于较旧的手机,它不会通过 GPS 获取位置,但标准将 GPS 指定为提供者。 有没有更好的方法来获取从 KitKat 到可能是 Oreo 的设备位置?

【问题讨论】:

  • 您提供的错误日志似乎不是来自您的Application,而是来自Substratum主题引擎。
  • 是的,很奇怪,因为它不仅仅在我的手机上崩溃。我想实际上有2个错误。

标签: java android location broadcast locationmanager


【解决方案1】:

这似乎只发生在 Android 6.0 + 设备上

从 Android 6.0 开始,引入了权限。确保您的应用在 Android 6.0+ 上具有位置访问权限。您应该通知用户您想要访问他/她的位置。查看这个有用的链接:

https://developer.android.com/training/permissions/requesting.html

【讨论】:

  • 我已经从用户那里获得了权限,正如我提到的应用程序运行良好(ish)- 仅在安装后第一次启动时崩溃。更大的问题实际上是获取位置 - 一个比现在更好的功能,并且适用于 Android 4.4+
  • 如果您提供正确的日志,我们只能帮助您,请搜索正确的堆栈跟踪。
猜你喜欢
  • 2015-08-01
  • 2022-01-08
  • 1970-01-01
  • 2012-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多