Android LocationListener, AbstractMethodError on onStatusChanged and onProviderDisabled
Asked Answered
C

6

31

I have a simple activity with a button, that uses the LocationManager to try to get the current location:

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());
        }
    });
}

I created an emulator in Android Studio with the API level 22, and after giving the permission, and with the gps of emulator on, the app crashes with this error when clicking the button:

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

If I press the button with the gps turned off, I get this error instead:

java.lang.AbstractMethodError: abstract method "void android.location.LocationListener.onProviderDisabled(java.lang.String)"

If I try the app on my Xiaomi Mi A1, it only crashes when the gps is off and the button is clicked, it does not crash when the gps is on and the button is pressed.

From the documentation, those methods are marked with default, so I should not need to implement them.

Is there any reason for this behavior?

Curve answered 2/11, 2020 at 0:4 Comment(0)
M
52

Just add these three function at the end of your code:

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

}

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

}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
    
}

and write your code that you would like to execute when status changes

Marlysmarmaduke answered 2/11, 2020 at 10:1 Comment(17)
Yes, I know that works, but what I wanted to know is why I need to implement those methods, when the documentation says they have a default implementation, since the code compiles without them. And why the error behavior is different on different phones.Curve
Not sure about it, buy I guess it is due to the changes in location listner class. Old android versions needed to define these functions in order to make them not abstract. Recently Android has made all three functions as non abstract and deprecated onStatusChaged(). See developer.android.com/sdk/api_diff/30/changes/…Marlysmarmaduke
I hadn't implemented onProviderEnabled method and I got the same error (AbstractMethodError), I have implemented it and cleared the super method and now no more crashesWeatherboarding
@ahmet locationListner class is an interface. So i dont think you should be using super in its functions.Marlysmarmaduke
where to implement these ones? In Activity or Service class? I cannot implement these.Sandi
You need to implement these in the class which implements locationListener. It can be an activity, fragment or service.Marlysmarmaduke
@Marlysmarmaduke somehow i lost your response. The thing is that wherever i put these methods it won't let me.It marks red the @Override annotation and says: "Method does not override method from its superclass". I have made a similar post with the exact same problem. Even tho the difference is only 2 months i have the same problem and i cannot override these methods. See here #65700639Sandi
I saw your post. The problem is, you can override these methods only when you implement following class: implements LocationListener like public class MainActivity extends AppCompatActivity implements LocationListener and wherever you have used "locationListener" variable, you can simply use this pointer. Then only you will be able to override above mentioned methodsMarlysmarmaduke
@Marlysmarmaduke what should i write instead of my local locationListener ? I have implemented the Interface and override the methods. But haven't changed something else.....Sandi
@Marlysmarmaduke what i have done now is to change my locationListener variable with this. But that wasn't enough. I wanted from me to write something on onProviderDisabled otherwise it would crash even if it was overridden! The thing is that when it get to the locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 2, this); it will only trigger onProviderDisabled and that's it.... nothing else.Sandi
So at it seems i have to enable manually the GPS on my phone before trying to use my app. Otherwise even when i grant permissions it won't enable GPS on my phone. That was the problemSandi
This is how I deal with this situation: boolean checkGps() { locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); assert locationManager != null; if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { showGPSDisabledAlertToUser(); return false; } return true; }Marlysmarmaduke
//This method configures the Alert Dialog box. private void showGPSDisabledAlertToUser() { //in alert dialog on OK click Intent callGPSSettingIntent = new Intent( android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivity(callGPSSettingIntent); }Marlysmarmaduke
get the result from checkgps() and if it is true then only ask for location updateMarlysmarmaduke
i have updated my thread to help others with a solution. #65700639 Thanks @MarlysmarmadukeSandi
No idea why this answer is at the bottom. THis solves my problem on SDK 26. (Android 8)Domesday
To clarify, these methods can (and often should) be empty. As this other answer explains, they're empty by default in SDK version 30, which is why not having them throws a runtime error instead of a compiler error.Battery
R
28

I was not completely satisfied with the answers above and decided to elaborate a little.

As @sunlover3 rightfully stated, the problematic methods' implementation was changed. Before API 30 they were abstract, which means that if the compileSdk would be anything but 30 the OP's code would give compile error (these methods must have been implemented). But in the API 30 they added empty default methods' implementation, which means that if the compileSdk is 30, the compiler checks these methods and gives no error, they are already implemented.

BUT, if one runs an app with compileSdk 30 on an older OS with the version below 30, these methods' implementation is still old, i.o. there is none, they are abstract! Hence, the error.

Honestly, that's an obvious SDK's devs error, such things must not happen. At worst there should've been a compile-time warning that one should still override these methods for the older versions compatibility. I hope someone less lazy than I am on this topic will report this to google tracker :)

Redundant answered 9/6, 2021 at 8:51 Comment(0)
U
7

Here's my situation. On Android 9 (API 28) and Android 10 (API 29), in the android.location.LocationManager class there is this method:

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();
}

which seems to be called. Also, the difference of implementation for LocationListener between Android 29 and Android 30 is this:

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) {}
}

It's obvious that the word "default" is the difference. Given that I have the same problem as you, I need to find a workaround now. Or use the response of mohit48. Good luck!

Ursa answered 25/1, 2021 at 18:6 Comment(0)
F
4

Override the methods in your code. ...

override fun onProviderDisabled(provider: String) {}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}
...
Fraise answered 10/9, 2021 at 5:31 Comment(0)
S
3

I faced the same issue and I managed to solve it by overriding the onStatusChanged() as suggested above.

However, the Android team might be working on something and I found that there is this interface that solves the problem without overriding, as far as I have tested.

You can see here the summary for the androidx.core.location package.

In order to use these new classes in your project you should use the latest beta version of the androidx.core. Read here.

Schofield answered 12/10, 2021 at 11:5 Comment(0)
A
2

Just Add implement LocationListener

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

}

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

}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
    
}
Alleenallegation answered 21/11, 2022 at 21:59 Comment(2)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Edsel
How does your answer differ from https://mcmap.net/q/459264/-android-locationlistener-abstractmethoderror-on-onstatuschanged-and-onproviderdisabled? Please do not post duplicates or add more details/explanations.Schonfield

© 2022 - 2024 — McMap. All rights reserved.