EventBus - Subscriber class and its super classes have no public methods with the @subscribe annotation
Asked Answered
P

15

47

I'm creating an Android application using EventBus for posting asynchronous broadcasts to other classes, but I'm running into an error during execution.

MainActivity.java

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.google.android.gms.maps.model.LatLng;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;


public class MainActivity extends AppCompatActivity {

    //Globals
    public String uname = null;
    public double lat = 0;
    public double lng = 0;

    //Get GUI handles
    public Button sendButton; //
    public EditText username;
    public Button MapButton; //
    public EditText LatBox;
    public EditText LngBox;


    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        //register EventBus
        EventBus.getDefault().register(this);

        super.onCreate(savedInstanceState);
        //set GUI for MainActivity
        setContentView(R.layout.activity_main);

        //get handlers
        LatBox = (EditText)findViewById(R.id.LatBox);
        LngBox = (EditText)findViewById(R.id.LngBox);

        MapButton = (Button)findViewById(R.id.locationButton);
        //Call the class which will handle finding coordinates
        MapButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent MapIntent = new Intent(getApplicationContext(), MapClass.class);
                startActivityForResult(MapIntent, 0);
            }
        });

        sendButton = (Button)findViewById(R.id.Submit);
        //Set action for Button
        sendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                //Get username from user
                username  = (EditText)findViewById(R.id.UsernameText);
                uname = username.getText().toString();

                //Generate intent to start IntentService
                Intent i = new Intent(getApplicationContext(), Register.class);

                //Put the extra field of username
                i.putExtra("username", uname);
                i.putExtra("latitude", lat);
                i.putExtra("longitude", lng);
                i.putExtra("type", "meetup.be2015.gcm_meetup.MAIN_ACTIVITY");

                //Start the IntentService on a different thread
                startService(i);
            }
        });

    }


    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(LatLng currentPos){

        LatBox.setText(String.valueOf(currentPos.latitude));
        LngBox.setText(String.valueOf(currentPos.longitude));

        lat = currentPos.latitude;
        lng = currentPos.longitude;
    }
}

MapClass.java

import android.app.IntentService;
import android.content.Intent;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.google.android.gms.appindexing.Action;
import com.google.android.gms.appindexing.AppIndex;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.LatLng;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;

public class MapClass extends AppCompatActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

    private GoogleApiClient mGoogleApiClient;
    private GoogleMap mgoogleMap;
    private LatLng latLng;
    private GoogleApiClient client;

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mgoogleMap = googleMap;
        mgoogleMap.setMyLocationEnabled(true);      //Sets location to current position
        buildGoogleApiClient();
        mGoogleApiClient.connect();
    }

    protected synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
        }
    }

    @Override
    public void onConnected(Bundle bundle) {
        Location MLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
        if (MLastLocation != null) {
            latLng = new LatLng(MLastLocation.getLatitude(), MLastLocation.getLongitude());

            //Post the LatLng to MainActivity
            EventBus.getDefault().post(latLng);

            //Send sticky event to Register and MyGcmListenerService
            EventBus.getDefault().postSticky(latLng);

        } else {
            Log.d("onConnected", "Value of LatLng is NULL");
            latLng = new LatLng(0, 0);   //equator
        }
    }

    @Override
    public void onConnectionSuspended(int i) {
        //Notify
        Log.d("ConnectionSuspended", "Connection Suspended. Status: " +   i);
        mgoogleMap.clear();
        mGoogleApiClient.disconnect();
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        //Notify
        Log.d("ConnectionFailed", "Connection Failed. Status: " + connectionResult.toString());
        mgoogleMap.clear();
        mGoogleApiClient.disconnect();
    }

    @Subscribe
    public void onEvent() {
        Log.d("EVENT", "EVENT");
    }

    @Override
    public void onStart() {
        super.onStart();
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this);
        }


    @Override
    public void onStop() {
        super.onStop();
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
        }

    }
}

The LogCat shows the following:

03-08 22:54:56.970 8570-8570/meetup.be2015.gcm_meetup E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{meetup.be2015.gcm_meetup/meetup.be2015.gcm_meetup.MapClass}:
org.greenrobot.eventbus.EventBusException: Subscriber class meetup.be2015.gcm_meetup.MapClass 
and its super classes have no public methods with the @Subscribe annotation
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2118)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2143)
at android.app.ActivityThread.access$700(ActivityThread.java:140)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:174)
at android.app.ActivityThread.main(ActivityThread.java:4952)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
at dalvik.system.NativeStart.main(Native Method)
Caused by: org.greenrobot.eventbus.EventBusException: Subscriber class meetup.be2015.gcm_meetup.MapClass 
and its super classes have no public methods with the @Subscribe annotation
at org.greenrobot.eventbus.SubscriberMethodFinder.findSubscriberMethods(SubscriberMethodFinder.java:67)
at org.greenrobot.eventbus.EventBus.register(EventBus.java:136)
at meetup.be2015.gcm_meetup.MapClass.onStart(MapClass.java:91)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1178)
at android.app.Activity.performStart(Activity.java:5198)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2091)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2143) 
at android.app.ActivityThread.access$700(ActivityThread.java:140) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loop(Looper.java:174) 
at android.app.ActivityThread.main(ActivityThread.java:4952) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:511) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794) 
at dalvik.system.NativeStart.main(Native Method) 

Why is this happening? Am I doing something wrong?

Plutonian answered 8/3, 2016 at 17:30 Comment(1)
Using R8 we have the same issueUnderarm
D
21

i think it is because onEvent inside MapClass.java has no parameter. Could you try with the expected parameter?

Denunciatory answered 10/3, 2016 at 9:33 Comment(4)
What is the expected paramater? Actually, I don't want to receive anything in MapClass.javaPlutonian
If you don't want to receive anything in MapClass.java, then why you subscribe (register)? Just remove the register and unregister, also onEvent.Denunciatory
I just want to send the LatLng to MainActivity. I thought you had to register and unregister even if you wanted to send events using the EventBus. So, what you are saying is that I don't need to register & unregister to the EventBus if I'm not intending on receiving anything? Also, the converse. I'll need to register and unregister to the EventBus only when I need to receive the event, right? What if my class wants to do both? I'm sorry if these questions seem childish; I can't wrap my head around the concept of the EventBus. Thanks in advance, @elsennov! :)Plutonian
Yes you are right. The key is "As a subscriber you have to register to event bus to receive the event and unregister when it is done. But, if you are a publisher, you don't have to register"Denunciatory
R
156

Please ensure these lines are in your proguard config file if you are using proguard for your builds.

-keepattributes *Annotation*
-keepclassmembers class ** {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
Ramer answered 8/9, 2016 at 9:39 Comment(1)
The double ** after class on second line is showing syntax error in recent versions of tools. Has syntax changed? What does double ** mean anyway?Enright
D
21

i think it is because onEvent inside MapClass.java has no parameter. Could you try with the expected parameter?

Denunciatory answered 10/3, 2016 at 9:33 Comment(4)
What is the expected paramater? Actually, I don't want to receive anything in MapClass.javaPlutonian
If you don't want to receive anything in MapClass.java, then why you subscribe (register)? Just remove the register and unregister, also onEvent.Denunciatory
I just want to send the LatLng to MainActivity. I thought you had to register and unregister even if you wanted to send events using the EventBus. So, what you are saying is that I don't need to register & unregister to the EventBus if I'm not intending on receiving anything? Also, the converse. I'll need to register and unregister to the EventBus only when I need to receive the event, right? What if my class wants to do both? I'm sorry if these questions seem childish; I can't wrap my head around the concept of the EventBus. Thanks in advance, @elsennov! :)Plutonian
Yes you are right. The key is "As a subscriber you have to register to event bus to receive the event and unregister when it is done. But, if you are a publisher, you don't have to register"Denunciatory
B
17

I faced the same issue and after a long research got the solution for every case. This problem is due to absence of @Subscribe public method onEvent() inside the class which you are trying to register Event bus as EventBus.getDefault().register(this). Presence of this function is mandatory if you register a class with Event bus

This can be in two situations

  1. using progruad : progruad may modify name of method onEvent() due to which event bus is not able to find it. Put these lines inide your progruad rules

    -keepattributes Annotation

    -keepclassmembers class ** {

    @org.greenrobot.eventbus.Subscribe ;

    }

    -keep enum org.greenrobot.eventbus.ThreadMode { *;

}

  1. if you are not using progruard then definitely your class is missing the method onEvent() with @Subscribe annotation. This annotation with method is mandatory with EventBus version 3.0.0 so double check presence of this method inside your class.
Burdelle answered 10/5, 2017 at 11:17 Comment(0)
C
12

Just in case your code is like mine :p

I had to set the method as public because it's currently private.

Cardiganshire answered 24/6, 2017 at 12:20 Comment(0)
U
5

In my situation,I got this error for I did't write @Subscribe on the class where i register EventBus.

Uproot answered 21/10, 2016 at 3:14 Comment(0)
F
5

In my case onEvent() was private and placed in child class.

But register() and unregister() were called in parent class.

Solution was to made onEvent() public.

Forewent answered 11/10, 2018 at 11:3 Comment(1)
Same here. I had the function as private and then had to make it public and this worked.Biological
U
4

If you are using proguard, You will not face this problem in debug mode. I faced this problem in release version. after adding this below code in proguard-rules.pro files, solved my problem.

-keepattributes *Annotation*
-keepclassmembers class ** {
    @org.greenrobot.eventbus.Subscribe <methods>;
 }
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
Unilobed answered 17/8, 2019 at 6:12 Comment(0)
K
3

On a sidenote, I got the same error after switching from Google's implementation of the EventBus to this one. This error drove me crazy, because Google's EventBus also has a @Subscribe annotation and I was using that one instead of the one provided by greenrobot.

enter image description here

OK, it's a very silly error on my part, but if I can help even 1 person like me, I'm happy.

Kickstand answered 5/11, 2018 at 22:19 Comment(1)
It was my case. Thank you.Roundsman
B
3

Can be help for someone! My situation, I forgot add line below into buildTypes

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

Bum answered 13/5, 2020 at 3:23 Comment(0)
F
2

Just incase it would help some one, in my case I forgot to pass arguments to the receiving method, everything else was fine. When there is no argument passed to the receiving function/method, in that case this exception is thrown.

Funicle answered 13/12, 2018 at 9:48 Comment(0)
E
2

Just switch from private fun to public, and you will see magic.

Emetine answered 9/12, 2020 at 20:36 Comment(0)
M
1

If you are using flutter, add this to the release build type in your app build.gradle

minifyEnabled false
shrinkResources false
Manasseh answered 6/4, 2022 at 6:34 Comment(1)
thx Jafari. I got a configuration error when I tried to add these parameters to root level in the app/build.gradle. Correct parent path is android.buildTypes.releaseDeci
S
0

Update from the answer, since proguard is not the default anymore. Its change into R8. Turn off the R8 to make sure. In flutter this will be:

flutter build apk --no-shrink ...

Sextuplet answered 6/11, 2020 at 14:45 Comment(0)
T
0

1. Go to imports and remove this line:
import com.google.common.eventbus.Subscribe;
2. and add this:
import org.greenrobot.eventbus.Subscribe;
3. Remove @Subscribe and add it again.
4. While adding make sure you are using org.greenrobot.eventbus to import @Subscribe.

Trisomic answered 12/1, 2022 at 6:15 Comment(0)
R
-3

I was using Subscribe annotation from wrong package.

It should be import org.greenrobot.eventbus.Subscribe

I was using import com.squareup.otto.Subscribe

Roundsman answered 14/2, 2020 at 7:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.