0

I would like to code my app in MVC. The problem is that I'm new in Android and I don't know how to have a listener/callback if the function is out of the main Class.

public void addNewUser(String firstname, String lastname, String email, Integer gender, String uid, String profileImageUrl){

        Map<String, Object> data = new HashMap<>();
        data.put("firstname", firstname);
        data.put("lastname", lastname);
        data.put("email", email);
        data.put("gender", gender);
        data.put("boxId", "independent");
        data.put("notificationsEnabled", true);
        data.put("profileImageUrl", profileImageUrl);

        mFirebaseFirestore.collection("usersP").add(data)
                .addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
                    @Override
                    public void onSuccess(DocumentReference documentReference) {
                        mProgressBar.setVisibility(View.GONE);

                        mIRegisterActivity.inflateFragment("Register Box", mHashMap);
                        Log.d(TAG, "DocumentSnapshot written with ID: " + documentReference.getId());
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        Log.d(TAG, "Error adding document", e);
                    }
                });

    }

I would like to have this function in a different Java Class. But if I do that I don't know how to still be able to launch an action only when the function is completed execution -> in other words, when it's addOnSuccessListener.

Do you know how I could do that?

I'm used to coding in swift, it would be something like that:

func addUser(id: String, completion: @escaping (User) -> Void) {
      // Code and then
      completion(user)
   }
Milind Mevada
  • 3,145
  • 1
  • 14
  • 22
KevinB
  • 2,454
  • 3
  • 25
  • 49
  • Just to clarify, you want to keep this function outside of activity class and perform operation on activity in `onSuccess()` method right? – adityakamble49 Jul 18 '18 at 05:47
  • I would like to have a class UserApi where I could have many functions like addNewUser(). And I would like to keep the listener so I can still ask mProgressBar.setVisibility(View.GONE); for example – KevinB Jul 18 '18 at 05:50
  • have a look at this class. https://github.com/AtifAbbAsi19/Firebase-Helper/blob/master/app/src/main/java/inc/droidflick/firebasetutorial/firebasenetwork/FireBaseHelper.java – Atif AbbAsi Jul 18 '18 at 05:51
  • You can also take a look at my answer from this **[post](https://stackoverflow.com/questions/48499310/firestore-object-with-inner-object/48500679)**. – Alex Mamo Jul 18 '18 at 09:04

5 Answers5

2

You should create your own custom Listener for that say MyFirebaseListener and update your things in activity by implementing this interface

public interface MyFirebaseListener {
    void onSuccess(DocumentReference documentReference)
    void onFailure(Exception e)
}

Now pass the Activity as parameter to MyFirebaseListener to addNewUser() method as below

public class UserApi{

    public void addNewUser(String firstname, 
                String lastname, 
                String email, 
                Integer gender, 
                String uid, 
                String profileImageUrl,
                MyFirebaseListener myFirebaseListener){

        Map<String, Object> data = new HashMap<>();
        data.put("firstname", firstname);
        data.put("lastname", lastname);
        data.put("email", email);
        data.put("gender", gender);
        data.put("boxId", "independent");
        data.put("notificationsEnabled", true);
        data.put("profileImageUrl", profileImageUrl);

        mFirebaseFirestore.collection("usersP").add(data)
                .addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
                    @Override
                    public void onSuccess(DocumentReference documentReference) {
                        myFirebaseListener.onSuccess(documentReference)
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        myFirebaseListener.onFailure(e)
                    }
                });

    }
}

Implement MyFirebaseListener interface in your Activity so you need to override following methods and perform your UI modification in those implemented methods as follows

public class MyActivity extends AppCompatActivity implements MyFirebaseListener {

    void someMethod(){
        addNewUser(firstname, 
                lastname, 
                email, 
                gender,
                uid,
                profileImageUrl,
                this) // <- This will be reference to Activity with Type of MyFirebaseListener
    }

    void onSuccess(DocumentReference documentReference){
        mProgressBar.setVisibility(View.GONE);
        mIRegisterActivity.inflateFragment("Register Box", mHashMap);
        Log.d(TAG, "DocumentSnapshot written with ID: " + documentReference.getId());
    }
    void onFailure(Exception e){
        Log.d(TAG, "Error adding document", e);
    }
}

This is how you can separate UI Logic and service logic using Custom Interfaces

adityakamble49
  • 1,971
  • 18
  • 27
0

Refer this link for custom Listener: https://guides.codepath.com/android/Creating-Custom-Listeners

If you want keep listener always call, For firebase listener, Use application class for listener.

If you want method global(where you need response of Firebase), Put that function Either in Application class, or Use BroadcastReceiver or Listener or EventBus.

Comment here if you have any query.

GreenFlash
  • 163
  • 1
  • 10
0

just add an interface ...

public interface IFirebaseTask {
    void OnSuccess(DocumentReference reference);
    void OnFailure(Exception e);
}

and then implement that interface, where it may be required to listen for:

public SomeActivity extends FragmentActivity implements IFirebaseTask {

}

one can also pass the listener into constructors:

public SomeFirebaseTask(Context context, IFirebaseTask listener){
    this.setContext(context);
    this.listener = listener;
}

... into order to notify the listener defined above from elsewhere.

alternatively, one can let just any class implement the interface methods:

... implements OnSuccessListener<DocumentReference>, OnFailureListener

and then bind the listener alike:

mFirebaseFirestore
  .collection("usersP")
  .add(data)
  .addOnSuccessListener(SomeActivity.this)
  .addOnFailureListener(SomeActivity.this);

the Firebase documentation (in case someone would bother to read) has this answered, as well...

see section Detaching Callbacks.

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
0

First add listenerInterface

public interface FirebaseResponse {
     void onSuccess();
     void onFailure();
}

Create separate class like below

public class ResponseHandler implements
    OnSuccessListener<DocumentReference>() , OnFailureListener() {

            private FirebaseListener listener;

            public ResponseHandler(FirebaseListener listener){
                 this.listener = listener;
            }     


             @Override
             public void onSuccess(DocumentReference documentReference) {
              //Todo handle onSuccess
                 listener.onSuccess();
             }

             @Override
             public void onFailure(@NonNull Exception e) {
                //Todo handle onFailure
                 listener.onFailure();
             }
    }

Then add this class as response handler in your class that implements FirebaseListener

ResponseHandler responseHandler = new ResponseHandler(this);

mFirestore.collection("usersP").add(data)
                .addOnSuccessListener(responseHandler).
                .addOnFailureListener(responseHandler)
Jonik
  • 141
  • 3
  • 14
0

There are two different approaches which you can use... First: U can make a callback interface just like we do in case of RecyclerView click callbacks...

Second: U can use livedata observers if this u must have little bit idea about rxJava2, arch life or Agera....

So lets consider the first approch

Consider ur class is

class otherClass{
callbackInterface mCallBackInterface;

public(callbackInterface mCallBackInterface){
this.mCallBackInterface=mCallBackInterface;
}

interface callbackInterface{
void onSucuss(DocumentReference documentReference);
}


public void addNewUser(String firstname, String lastname, String email, Integer gender, String uid, String profileImageUrl){

        Map<String, Object> data = new HashMap<>();
        data.put("firstname", firstname);
        data.put("lastname", lastname);
        data.put("email", email);
        data.put("gender", gender);
        data.put("boxId", "independent");
        data.put("notificationsEnabled", true);
        data.put("profileImageUrl", profileImageUrl);

        mFirebaseFirestore.collection("usersP").add(data)
                .addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
                    @Override
                    public void onSuccess(DocumentReference documentReference) {

mCallBackInterface.onSucuss(decumentReference);


                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        Log.d(TAG, "Error adding document", e);
                    }
                });

    }

}

///The Class which will be calling it will be something like this

class CallingClass implements CallBackInterface{

@Override
void CallBackINterface(DocumentReference documentReference){

//Your code goes here
}

}

This will do the job broadcast receivers can also be used but above solution is best for beginners...