EventBus - Subscriber class and its super classes

2020-05-24 19:48发布

问题:

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?

回答1:

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



回答2:

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 { *; }


回答3:

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.


回答4:

ProGuard

ProGuard obfuscates method names and may remove methods, which are not called (dead code removal). Because Subscriber methods are not directly called, ProGuard assumes them to be unused. So if you enable ProGuard minification, you must tell ProGuard to keep those Subscriber methods.

Use the following rules in your ProGuard configuration file (proguard.cfg) to prevent Subscribers from being removed:

-keepattributes *Annotation*
-keepclassmembers class * {
   @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }

# Only required if you usenter code heree AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    <init>(java.lang.Throwable);
}


回答5:

Just in case your code is like mine :p

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



回答6:

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



回答7:

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.



回答8:

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 { *; }


回答9:

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.

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



回答10:

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.



回答11:

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

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



回答12:

I was using Subscribe annotation from wrong package.

It should be import org.greenrobot.eventbus.Subscribe

I was using import com.squareup.otto.Subscribe