Firebase Database: Getting "No-Argument Constructor" Error Despite Having It - java

I am trying to writing data in an activity and then reading it in another activity. My writing part is working. For my reading part, I am trying to use getValue with parameter of a class I wrote. But I keep getting this error:
com.google.firebase.database.DatabaseException: Class ozhan.climb.MainActivity$User does not define a no-argument constructor. If you are using ProGuard, make sure these constructors are not stripped.
My class that used in getValue():
class User {
public String Server,
NeededRole,
Role,
SummonerName;
User() {}
public String get_Server() {
return Server;
}
public String get_NeededRole() {
return NeededRole;
}
public String get_Role() {
return Role;
}
public String get_SummonerName() {
return SummonerName;
}
}
and here is the code that should get data:
public void getUserData(){
final TextView tv_sumName = findViewById(R.id.tv_sumName),
tv_neededRole = findViewById(R.id.tv_neededrole),
tv_userRole = findViewById(R.id.tv_userrole),
tv_server = findViewById(R.id.tv_server);
final String uid = Objects.requireNonNull(mAuth.getCurrentUser()).getUid();
DatabaseReference usersDataRef = databaseRef.child("Users").child(uid);
usersDataRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
if (u != null) {
tv_server.setText(u.Server);
tv_neededRole.setText(u.NeededRole);
tv_userRole.setText(u.Role);
tv_sumName.setText(u.SummonerName);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}

The exception says your class is ozhan.climb.MainActivity$User - i.e., it is an inner class of MainActivity.
Inner classes require an instance of their outer class to construct. This won't work with Firebase Database, although the error message could definitely be improved.
Your User class should be a static class, which does not have the same requirement to exist only within the instance of a containing class:
static class User {
...
}

Related

Return updated value in getter function of model class in android studio java

I am calculating the number of units available base on the units sold in "Sale" table. I am using Firebase Datastore. My code looks like below inside the Post Model
public String getUnits() {
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("Sale").child(this.postid);
databaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
Long count = Long.parseLong(units) - snapshot.getChildrenCount();
units = count.toString();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
return units;
}
I need to return the value inside onDataChange(). It is showing exception.
I am trying to get this value inside a Adapter in Android Studio.
private void getCardCount( Post post){
cardCount.setText("Remaining " + post.getUnits());
}
If I put return inside onDataChange(), it gives the error : Cannot return a value from a method with void result type
and when I change the return type to String, it gives the error: 'onDataChange(DataSnapshot)' in 'Anonymous class derived from com.google.firebase.database.ValueEventListener' clashes with 'onDataChange(DataSnapshot)' in 'com.google.firebase.database.ValueEventListener'; attempting to use incompatible return type
I am new to android studio and some help will be much appreciated. Thank you in advance.

Android Java - Pass Class and Callback as parameter and instantiate object inside function

I need your help in understanding the best way of doing this. Given the sample code below, I need to know how to pass a Class and a Callback via parameter and use them internally to instantiate an object of type Class and use the method Class.setId, and then pass the instantiated object to the Callback function. Is that possible?
private void loadreading(String nodeType, String tableName, String deviceId, Class ReadingSubClass, Callback updateFields) {
readingQuery = fbDB.child(nodeType).child(tableName).child(deviceId).orderByChild("timestamp").limitToLast(1);
readingEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot ds : snapshot.getChildren()) {
// Create new reading
readingSubClass r = ds.getValue(ReadingSubClass.class);
r.setId(snapshot.getKey());
// Update fields
updateFields(r);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
logMsg(getContext(), "Load Reading: " + error.getMessage(), true, false, false, false);
}
};
readingQuery.addValueEventListener(readingEventListener);
}

instanceof does not work for extracting child class from a list of parent class objects in Firebase Realtime Database

I have the following three classes:
Parent
class Parent{
public String title;
public Parent(){}
public void setTitle(String title){
this.title = title;
}
public String getTitle(){
return this.title;
}
}
Child 1
class Child1 extends Parent{
public String c1title;
public Child1(){}
public void setC1title(String title){
this.c1title = title;
}
public String getC1itle(){
return this.c1title;
}
}
Child 2
class Child2 extends Parent{
public String c2title;
public Child2(){}
public void setC2title(String title){
this.c2title = title;
}
public String getC2itle(){
return this.c2title;
}
}
I stored the instances of child classes in an ArrayList <Parent> list and uploaded the ArrayList to the RealtimeDatabase. I can successfully retrieve the ArrayList, however this piece of code fails to work as intended for the ArrayList retrieved from Firebase but works for the local ArrayList:
for(Parent p : list){ //list is the ArrayList<Parent> obtained from Firebase
if(p instanceof Child1){
Log.d("Activity1", "1st child");
}
if(p instanceof Child2){
Log.d("Activity1", "2nd child");
}
else{
Log.d("Activity1", "No match found");
}
}
I am unable to understand the reason behind it. Does the locally stored ArrayList has some additional information about the stored objects which gets lost when stored in the Firebase? What should be the ideal workaround for filtering out the child objects?
Edit: Code to retrieve ArrayList from Firebase
mDatabaseReference = FirebaseDatabase.getInstance().getReference("test");
mDatabaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
GenericTypeIndicator<ArrayList<Parent>> t = new GenericTypeIndicator<ArrayList<Parent>>() {};
ArrayList<Parent> yourStringArray = dataSnapshot.getValue(t);
List<Parent> list = dataSnapshot.getValue(t);
Log.d(TAG, "Successfully obtained the test list");
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
To read the data from the database you're using this:
GenericTypeIndicator<ArrayList<Parent>> t = new GenericTypeIndicator<ArrayList<Parent>>() {};
ArrayList<Parent> yourStringArray = dataSnapshot.getValue(t);
List<Parent> list = dataSnapshot.getValue(t);
In this code you're telling Firebase to read a Parent instance from the snapshot, so that's precisely what it does.
If you want it to read the specific child that you wrote into the database, you will have to do two things:
Write information on the type of class to the database.
Ask Firebase for an instance of that specific class when reading from the database.
So when writing, this could be something like:
if (object instanceof "Child1") {
ref.child("type").set("Child");
}...
And then when reading back, you'd read the data, loop over the results and instantiate the correct class based on the type property:
mDatabaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child: dataSnapshot.getChildren()) {
String type = child.getChild("type").getValue(String.class);
if ("Child1".equals(type)) {
Child1 child1 = child.getValue(Child1.class);
}...
}
}
I don't think there's any way to do this on an entire list of children with a single API call.

Reading an object from a Firebase database in android studio

Using Android Studio and Firebase, i'm trying to write and read some data.
I have a Pub Class which contains the folowing:
package com.example.jef.pubbuddy.Database;
import java.util.ArrayList;
public class Pub {
private String name;
private float longitude;
private float lattitude;
private ArrayList<Pub> Pubs = new ArrayList<>();
public Pub() {}
public void setName(String name)
{this.name = name;}
public void setLongitude(float longitude)
{this.longitude = longitude;}
public void setLatitude(float lattitude)
{this.lattitude = lattitude;}
public String getName()
{return name;}
public float getLatitude()
{return lattitude;}
public float getLongitude()
{return longitude;}
I write my Pub object to the database using the .push() method. Below is how i write it to the database. It appears just fine in the Firebase console, so I believe the problem doesn't lie here:
Pub p1 = new Pub();
p1.setName("The name of the pub");
p1.setLatitude((float) 4.699545);
p1.setLongitude((float) 50.878267);
myRef.child("PUSH_TEST").push().setValue(p1);
Afterwards I try to read it using the following code. Please note the message method is just used to append some information to a TextView, so i'm able to debug on my physical device. However, none of the listener events get triggered.
Does anyone knows what i'm doing wrong here? Already followed the official firebase documentation and the "Firebase in a weekend" training videos. Also looked up countless answers here on Stackoverflow, but I can't seem to make it work.
Thanks in advance.
public class Database extends AppCompatActivity {
private TextView tv;
int messages;
private ArrayList<Pub> pubList = new ArrayList();
private FirebaseDatabase database;
private DatabaseReference myRef;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_database);
database = FirebaseDatabase.getInstance();
myRef = database.getReference();
init();
writeData();
message("creating and attaching the listener");
ChildEventListener myListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s)
{
message("The childEvent triggered");
Pub p = dataSnapshot.getValue(Pub.class);
message("The name of this pub = " + p.getName());
pubList.add(p);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
myRef.child("PUSHTEST").addChildEventListener(myListener);
}
Everything is correct, except this:
Here you set the value:
myRef.child("PUSH_TEST").push().setValue(p1);
and here you retrieve the value:
myRef.child("PUSHTEST").addChildEventListener(myListener);
the child that you wrote is wrong as it is not in your database. So just change it into this:
myRef.child("PUSH_TEST").addChildEventListener(myListener);
the name inside child(..) needs to be the same as in your database
You write data to "PUSH_TEST" child and trying to read from "PUSHTEST". Make it same.
For not getting similar errors in future, create a class called "Constants.java" and add constant strings inside it. Like,
public class Constants {
public static final String CHILD_NODE="PUSH_TEST";
}
So that , you can use this constant, where ever u need. Just call Constants.CHILD_NODE. So there will not be such errors.

How to reuse a method from a different class

I have an authenticateID method which searches in the database to find a match and does something. I guess it will take long to explain so here is my code:
public boolean authenticateStudentID() {
boolean success = true;
final String studentID = etStudentID.getText().toString().trim();
final String module = etModule.getText().toString().trim();
final String degree = etDegree.getText().toString().trim();
final String room = etRoom.getText().toString().trim();
final String email = etEmail.getText().toString().trim();
final String fullname = etfullname.getText().toString().trim();
final String loginID = etLoginID.getText().toString().trim();
if (success) {
databaseRef.addListenerForSingleValueEvent(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) { // wtf is this advanecd for loop
//map string string because our key is a string and value is a string, map has a key and value object
Map<String, String> map = (Map) snapshot.getValue();
if (map != null) { //if the values and keys are not null
String studentIDMatch = map.get("studentID");
// Log.v("E_VALUE", "students ID entered : " + studentIDMatch);
// Log.v("E_VALUE", "students ID from db: " + studentID);
if (studentID.equals(studentIDMatch)) {
String uniqueKey = databaseRef.push().getKey();
NewStudentAccounts sam = new NewStudentAccounts
(studentID, loginID, email, fullname, module, degree, room);
databaseRef.child(uniqueKey).setValue(sam);
Toast.makeText(getApplicationContext(), "Your account registration has been successful!", Toast.LENGTH_SHORT).show();
startActivity(new Intent(getApplicationContext(), LoginActivity.class));
} else {
Toast.makeText(getApplicationContext(), "Invalid Student Credentials Entered!!", Toast.LENGTH_SHORT).show();
}
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
return success;
I want to know how I can reuse this method for another class instead of copy and pasting code. Please guide me, I really appreciate it.
private void addNewStudent() {
findViewById(R.id.buttonAddStudent).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
View addStudentActivityDialog = LayoutInflater.from(LecturerAccount.this).inflate(R.layout.activity_add_student,null);
etStudentName = addStudentActivityDialog.findViewById(R.id.editTextStudentName);
etStudentUserID = addStudentActivityDialog.findViewById(R.id.editTextStudentUserID);
AlertDialog.Builder addStudentBuilder = new AlertDialog.Builder(LecturerAccount.this);
addStudentBuilder.setMessage("STAR").setView(addStudentActivityDialog).setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
String studentName = etStudentName.getText().toString();
String studentID = etStudentUserID.getText().toString();
registerActivity = new RegisterActivity(); //calling the instance of the class here
if (registerActivity.authenticateStudentID() == true){
studentarray.add(studentName);
}
}
}).setNegativeButton("cancel", null).setCancelable(false);
AlertDialog newStudentDialog = addStudentBuilder.create();
newStudentDialog.show();
}
});
}
My if statement here calling the function, I am totally clueless here.
Since onDataChange(DataSnapshot dataSnapshot) is an asynchronous callback event from firebase you must implement your own callback method to get notified of the result.
One approach would be to use interfaces.
create a separate class Auth
public class Auth {
public static void authenticateStudentID(final String studentID, final AuthListener listener) {
DatabaseReference databaseRef = FirebaseDatabase.getInstance().getReference("your reference");
databaseRef.addListenerForSingleValueEvent(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) { // wtf is this advanecd for loop
//map string string because our key is a string and value is a string, map has a key and value object
Map<String, String> map = (Map) snapshot.getValue();
if (map != null) { //if the values and keys are not null
String studentIDMatch = map.get("studentID");
if (studentID.equals(studentIDMatch)) {
if (listener != null)
listener.onAuthSuccess();
} else {
if (listener != null)
listener.onAuthFailure();
}
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
if (listener != null)
listener.onAuthFailure();
}
});
}
public interface AuthListener {
void onAuthSuccess();
void onAuthFailure();
}
}
And then call it by
Auth.authenticateStudentID(studentId, new Auth.AuthListener() {
#Override
public void onAuthSuccess() {
}
#Override
public void onAuthFailure() {
}
});
wherever required
As the method you want to reuse should be "public" first of all. It simply means that it can be publically accessed among other classes of that project. And after making it public you can simply refer it using the class name.
Here is an example of this :
Class2 instance = new Class2();
instance.publicMehtodToBeAcessedInThisClass(any parameters);
But in your case, you will have to copy and paste the code to another class file only.
Reason: Because you are fetching data from the layout file of your Java file and this will crash the app. Either you should further modularize your code and handle this by making a separate function for fetching all this data. Otherwise, copy pasting only a method from one class to another will not make your application run into any performance issue or lags.
Access modifier is incorrect. Good old java doc will explain better than me:
access modifiers
In order to access it, you have to create an instance like so:
YourClass yourClass = new YourClass();
yourCLass.authenticateStudentID();
The YourClass is usually the name of the file where this code you pasted located in.
From what you've shown, there are two issues you need to deal with:
As noted, having it private doesn't do you much good when it comes to reuse.
It looks like the databaseRef object is a class property. So you'll need to pass this in, rather than rely on the class property for that class, since you want to use it from another class. (Or you can put this method, and the databaseRef property, in a superclass and have your two classes inherit from it.)
In general - think about what your method needs to do, and then what it needs to do that. Those should shape how you make the method more usable from other parts of your code.

Categories

Resources