Android onStatusChanged 和 onProviderDisabled 上的 LocationListener、AbstractMethodError
Android LocationListener, AbstractMethodError on onStatusChanged and onProviderDisabled
我有一个带有按钮的简单 activity,它使用 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());
}
});
}
我在 Android Studio 中创建了一个 API 级别为 22 的模拟器,在授予权限后,在模拟器的 gps 开启的情况下,单击按钮时应用程序崩溃并出现此错误:
java.lang.AbstractMethodError: abstract method "void android.location.LocationListener.onStatusChanged(java.lang.String, int, android.os.Bundle)"
如果我在 gps 关闭的情况下按下按钮,则会收到此错误:
java.lang.AbstractMethodError: abstract method "void android.location.LocationListener.onProviderDisabled(java.lang.String)"
如果我在我的小米 Mi A1 上试用该应用程序,它只会在 gps 关闭并单击按钮时崩溃,当 gps 打开并按下按钮时它不会崩溃。
From the documentation,这些方法都标有默认值,所以我应该不需要实现它们。
这种行为有什么原因吗?
只需在代码末尾添加这三个函数:
@Override
public void onProviderEnabled(@NonNull String provider) {
}
@Override
public void onProviderDisabled(@NonNull String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
并编写您希望在状态更改时执行的代码
这是我的情况。在Android9(API28)和Android10(API29)上,在android.location.LocationManagerclass中有这个方法:
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();
}
这好像叫。此外,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) {}
}
很明显,“默认”这个词是有区别的。鉴于我和你有同样的问题,我现在需要找到解决方法。或者使用 mohit48 的响应。祝你好运!
我对上面的回答不是很满意,决定稍微详细一点。
正如@sunlover3 正确指出的那样,有问题的方法的实现已更改。在 API 30 之前,它们是抽象的,这意味着如果 compileSdk 不是 30,OP 的代码将给出编译错误(这些方法必须已经实现)。但是在API 30他们添加了空的默认方法的实现,这意味着如果compileSdk是30,编译器检查这些方法并没有报错,它们已经实现了。
但是,如果一个应用程序运行 compileSdk 30 和更旧的 OS 且版本低于 30,这些方法的实现仍然是旧的,i.o。有none,它们是抽象的!因此,错误。
老实说,这是一个明显的SDK开发错误,这种事情不能发生。在最坏的情况下应该有一个编译时警告,人们仍然应该覆盖这些方法以获得旧版本的兼容性。我希望在这个话题上没有我那么懒惰的人将此报告给 google 跟踪器!
重写代码中的方法。
...
override fun onProviderDisabled(provider: String) {}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}
...
我遇到了同样的问题,我设法通过覆盖上面建议的 onStatusChanged() 来解决它。
但是,Android 团队可能正在做一些事情,据我测试,我发现 this 界面可以解决问题而无需覆盖。
您可以查看 here androidx.core.location 软件包的摘要。
为了在您的项目中使用这个新的 类,您应该使用 androidx.core[= 的最新 beta 版本 24=]。阅读 here.
我有一个带有按钮的简单 activity,它使用 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());
}
});
}
我在 Android Studio 中创建了一个 API 级别为 22 的模拟器,在授予权限后,在模拟器的 gps 开启的情况下,单击按钮时应用程序崩溃并出现此错误:
java.lang.AbstractMethodError: abstract method "void android.location.LocationListener.onStatusChanged(java.lang.String, int, android.os.Bundle)"
如果我在 gps 关闭的情况下按下按钮,则会收到此错误:
java.lang.AbstractMethodError: abstract method "void android.location.LocationListener.onProviderDisabled(java.lang.String)"
如果我在我的小米 Mi A1 上试用该应用程序,它只会在 gps 关闭并单击按钮时崩溃,当 gps 打开并按下按钮时它不会崩溃。
From the documentation,这些方法都标有默认值,所以我应该不需要实现它们。
这种行为有什么原因吗?
只需在代码末尾添加这三个函数:
@Override
public void onProviderEnabled(@NonNull String provider) {
}
@Override
public void onProviderDisabled(@NonNull String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
并编写您希望在状态更改时执行的代码
这是我的情况。在Android9(API28)和Android10(API29)上,在android.location.LocationManagerclass中有这个方法:
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();
}
这好像叫。此外,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) {}
}
很明显,“默认”这个词是有区别的。鉴于我和你有同样的问题,我现在需要找到解决方法。或者使用 mohit48 的响应。祝你好运!
我对上面的回答不是很满意,决定稍微详细一点。
正如@sunlover3 正确指出的那样,有问题的方法的实现已更改。在 API 30 之前,它们是抽象的,这意味着如果 compileSdk 不是 30,OP 的代码将给出编译错误(这些方法必须已经实现)。但是在API 30他们添加了空的默认方法的实现,这意味着如果compileSdk是30,编译器检查这些方法并没有报错,它们已经实现了。
但是,如果一个应用程序运行 compileSdk 30 和更旧的 OS 且版本低于 30,这些方法的实现仍然是旧的,i.o。有none,它们是抽象的!因此,错误。
老实说,这是一个明显的SDK开发错误,这种事情不能发生。在最坏的情况下应该有一个编译时警告,人们仍然应该覆盖这些方法以获得旧版本的兼容性。我希望在这个话题上没有我那么懒惰的人将此报告给 google 跟踪器!
重写代码中的方法。 ...
override fun onProviderDisabled(provider: String) {}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}
...
我遇到了同样的问题,我设法通过覆盖上面建议的 onStatusChanged() 来解决它。
但是,Android 团队可能正在做一些事情,据我测试,我发现 this 界面可以解决问题而无需覆盖。
您可以查看 here androidx.core.location 软件包的摘要。
为了在您的项目中使用这个新的 类,您应该使用 androidx.core[= 的最新 beta 版本 24=]。阅读 here.