2

I have some fully functional lines of code retrieving each single data, but failed to retrieve them using class. Eg: These lines are working perfectly.

double value = (double) ds.child("player1score").getValue();
long value = (long) ds.child("point").getValue();

Yet, when retrieving using class, error occurs. Here are the whole picture of my codes, not sure if it is sufficient for solving the question, feel free to let me know what else is needed, appreciate so much for any advice, thanks!

Round().class

public class Round {
public double player1score;
public double player2score;
public double player3score;
public double player4score;
public long point;

//Constructor
public Round(double player1score, double player2score, double player3score, double player4score, long point) {
    this.player1score = player1score;
    this.player2score = player2score;
    this.player3score = player3score;
    this.player4score = player4score;
    this.point = point;

//Below are All the getter and setter etc
}

My MainActivity.class.onCreate()

//Declare Variables
UserId = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference gameInfoRef = rootRef.child("user").child(UserId).child("gameInfo");
DatabaseReference gameRecordRef = rootRef.child("user").child(UserId).child("gameRecord");

String gameKey = "-LLyXhetqj9mj5fgh9bn";

Under onCreate():

gameRecordRef.child(gameKey).addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot ds : dataSnapshot.getChildren()) {
                ListView lv_history = (ListView) findViewById(R.id.lv_history);

                ArrayList<Round> ResultList = new ArrayList<>();

                //This line is where the error pointed to
                Round round = (Round) ds.getValue(Round.class);

                ResultList.add(round);

                ivd_HistoryAdapter adapter = new ivd_HistoryAdapter(id_History.this, ResultList);
                lv_history.setAdapter(adapter);
            }
        }

Firebase structure in text:

  "user": 
       "5xGKRXeHgThQy70lduPEp3mosTj1": 
             "gameRecord": 
                   "-LLyXhetqj9mj5fgh9bn": 
                        "player1score": 0.5,
                        "player2score": 0.5,
                        "player3score": 0.5,
                        "player4score": 0.5,
                        "point": 5

Logcat Error:

com.google.firebase.database.DatabaseException: Class viwil.mahjongcal.Round does not define a no-argument constructor. If you are using ProGuard, make sure these constructors are not stripped. at com.google.android.gms.internal.zzelx.zze(Unknown Source) at com.google.android.gms.internal.zzelw.zzb(Unknown Source) at com.google.android.gms.internal.zzelw.zza(Unknown Source) at com.google.firebase.database.DataSnapshot.getValue(Unknown Source) at viwil.mahjongcal.id_History$1.onDataChange(id_History.java:51) at com.google.android.gms.internal.zzegf.zza(Unknown Source) at com.google.android.gms.internal.zzeia.zzbyc(Unknown Source) at com.google.android.gms.internal.zzeig.run(Unknown Source) at android.os.Handler.handleCallback(Handler.java:761) at android.os.Handler.dispatchMessage(Handler.java:98) at android.os.Looper.loop(Looper.java:156) at android.app.ActivityThread.main(ActivityThread.java:6523) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)

Error pointed to this line: (id_History.java:51)

    Round round = ds.getValue(Round.class);

Firebase screenshot:

enter image description here

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193

1 Answers1

2

You are getting the following error:

FATAL EXCEPTION: ... does not define a no-argument constructor

Because your Round class does not define a no-argument constructor.

JavaBeans require a no-argument constructor to be present in the model class.

In Java, when a class has no constructors at all, there is a default no-argument constructor automatically added by the Java compiler. The moment you define any constructor in the class, the default no-argument constructor goes away.

In your code, your Round class defines such a constructor that contains five arguments:

public Round(double player1score, double player2score, double player3score, double player4score, long point) {}

As long as this constructor is present and you don't define a no-argument constructor, that class will not have one.

To solve this, you either remove that constructor from the class, or manually add a no-argument constructor as shown below:

public Round() {}

When the Firebase Realtime database SDK deserializes objects that are coming from the database, it requires that any objects in use, to have this constructor, so it can use it to instantiate the object. Fields in the objects are set by using public setter methods or direct access to public members.

Your Round class dosen't have a public no-arg constructor, the SDK doesn't really know how to create an instance of it. So it is mandatory to have it.

Also please note that setters and getter are not required. Setters are always optional because if there is no setter for a JSON property, the Firebase client will set the value directly onto the field. A constructor-with-arguments is also not required. Both are idiomatic and there are good cases to have classes without them. If you make the fields public, the getters are optional too.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193