Android LocationListener、onStatusChanged 和 onProviderDisabled 上的 AbstractMethodError

Bsa*_*sa0 7 android locationmanager

我有一个带有按钮的简单活动,它使用 LocationManager 来尝试获取当前位置:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button buttonGps = findViewById(R.id.buttonGps);

    final Context activity = this;

    buttonGps.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (!checkForPhonePermission()) {
                return;
            }

            LocationManager locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);

            locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, new LocationListener() {
                @Override
                public void onLocationChanged(@NonNull Location location) {
                    Log.d(TAG, location.getLatitude() + "");
                }
            }, Looper.myLooper());
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

我在 Android Studio 中创建了一个 API 级别为 22 的模拟器,在授予权限后,在模拟器的 GPS 开启的情况下,应用程序在单击按钮时崩溃并出现此错误:

java.lang.AbstractMethodError: abstract method "void android.location.LocationListener.onStatusChanged(java.lang.String, int, android.os.Bundle)"
Run Code Online (Sandbox Code Playgroud)

如果我在 GPS 关闭的情况下按下按钮,则会出现此错误:

java.lang.AbstractMethodError: abstract method "void android.location.LocationListener.onProviderDisabled(java.lang.String)"
Run Code Online (Sandbox Code Playgroud)

如果我在小米 A1 上试用该应用程序,它只会在 GPS 关闭并单击按钮时崩溃,而在 GPS 开启并按下按钮时它不会崩溃。

从文档中,这些方法被标记为默认值,所以我不需要实现它们。

这种行为有什么原因吗?

Kir*_*tin 24

我对上面的答案并不完全满意,决定详细说明一下。

正如 @sunlover3 正确指出的那样,有问题的方法的实现已更改。在 API 30 之前,它们是抽象的,这意味着如果compileSdk 不是 30,OP 的代码将给出编译错误(这些方法必须已实现)。但在API 30中,他们添加了空的默认方法的实现,这意味着如果compileSdk是30,编译器会检查这些方法并且不会给出错误,它们已经实现了。

但是,如果在版本低于 30 的旧操作系统上运行带有compileSdk 30的应用程序,这些方法的实现仍然是旧的,io没有,它们是抽象的!因此,出现错误。

老实说,这是一个明显的 SDK 开发错误,这样的事情绝对不能发生。最坏的情况应该是出现编译时警告,表明仍应重写这些方法以实现旧版本的兼容性。我希望在这个话题上比我不那么懒的人能够向 google tracker 报告这个问题:)


moh*_*t48 16

只需在代码末尾添加这三个函数:

@Override
public void onProviderEnabled(@NonNull String provider) {

}

@Override
public void onProviderDisabled(@NonNull String provider) {

}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
    
}
Run Code Online (Sandbox Code Playgroud)

并编写您希望在状态更改时执行的代码

  • 不确定,购买我猜这是由于位置监听器类的变化造成的。旧的 Android 版本需要定义这些函数,以使它们不抽象。最近,Android 已将所有三个函数设为非抽象函数,并弃用了 onStatusChaged()。请参阅 https://developer.android.com/sdk/api_diff/30/changes/android.location.LocationListener (2认同)
  • 我没有实现 onProviderEnabled 方法,并且得到了相同的错误(AbstractMethodError),我已经实现了它并清除了 super 方法,现在不再崩溃 (2认同)
  • 我已经更新了我的线程以帮助其他人找到解决方案。/sf/ask/4599009761/#65807111谢谢@mohit48 (2认同)

sun*_*er3 7

这是我的情况。在Android 9(API 28)和Android 10(API 29)上,在android.location.LocationManager类中有这个方法:

private void _handleMessage(Message msg) {
    switch (msg.what) {
        case TYPE_LOCATION_CHANGED:
            Location location = new Location((Location) msg.obj);
            mListener.onLocationChanged(location);
            break;
        case TYPE_STATUS_CHANGED:
            Bundle b = (Bundle) msg.obj;
            String provider = b.getString("provider");
            int status = b.getInt("status");
            Bundle extras = b.getBundle("extras");
            mListener.onStatusChanged(provider, status, extras);
            break;
        case TYPE_PROVIDER_ENABLED:
            mListener.onProviderEnabled((String) msg.obj);
            break;
        case TYPE_PROVIDER_DISABLED:
            mListener.onProviderDisabled((String) msg.obj);
            break;
    }
    locationCallbackFinished();
}
Run Code Online (Sandbox Code Playgroud)

这似乎被称为。另外,Android 29 和 Android 30 之间 LocationListener 的实现差异是这样的:

Android 29:
public interface LocationListener {
    void onLocationChanged(Location location);
    
    @Deprecated
    void onStatusChanged(String provider, int status, Bundle extras);

    void onProviderEnabled(String provider);

    void onProviderDisabled(String provider);
}

Android 30:
public interface LocationListener {
    void onLocationChanged(@NonNull Location location);

    @Deprecated
    default void onStatusChanged(String provider, int status, Bundle extras) {}

    default void onProviderEnabled(@NonNull String provider) {}

    default void onProviderDisabled(@NonNull String provider) {}
}
Run Code Online (Sandbox Code Playgroud)

很明显,“默认”二字就是区别。鉴于我和你有同样的问题,我现在需要找到解决方法。或者使用 mohit48 的响应。祝你好运!