Размещение обратных вызовов событий значения Firebase в одном месте - PullRequest
0 голосов
/ 07 февраля 2020

Я часто нахожу себя пишущим этот кусок кода снова и снова в нескольких действиях, когда использую firebase realtime db:

        ValueEventListener v =new ValueEventListener() {
            @Override
            public void onDataChange (@NonNull DataSnapshot dbSnapshot){
                String ourKey="";
                String ourValueID="";

                for (DataSnapshot childSnap : dbSnapshot.getChildren()) {

                    String childKey = childSnap.getKey();
                    if (childKey == null) {
                        //do some stuff 1 // and break/Continue/return
                    }

                    //or we can directly do something here, as we already assured  key is present


                    else  if(childKey.equals(ourKey)){
                        //do some stuff 2 // and break/Continue/return

                        MyClass myClass =childSnap.getValue(MyClass.class);
                        if(myClass==null){
                            //do some stuff 3 // and break/Continue/return
                        }
                        else if(myClass.getID().equals(ourValueID)){
                            //do some stuff 4 // and break/Continue/return

                        }
                        else {
                            //do some stuff 5 // and break/Continue/return

                        }
                    }
                    else {
                        //do some stuff 6 // and break/Continue/return
                    }

                }


            }

            @Override
            public void onCancelled (@NonNull DatabaseError databaseError){
                //do some stuff 7
            }
        };

, хотя предполагается, что именно так работает firebase, это делает мой код намного более нечитаемый и сложный для отладки. Что может быть хорошим подходом для использования этих обратных вызовов таким образом, что я пишу этот код один раз и снимаю помехи с моей базы кода? Пример был бы великолепен.

Ответы [ 3 ]

1 голос
/ 07 февраля 2020

Насколько я понимаю, вы хотите хранить все методы БД в отдельном классе, чтобы вы могли повторно использовать эти методы, чтобы код выглядел чище , и вы пытаетесь получить значения обратного вызова, когда они возвращаются из firebase.

Существует множество способов обработки обратных вызовов для событий, которые я рекомендую использовать интерфейс , он будет модульным, и ваш код будет выглядеть чище, так что вы можете сделать это чтобы хранить методы DB в отдельном классе (скажем, FirebaseDB), создайте там свои методы и используйте интерфейс для получения обратных вызовов. Пример того, как вы можете это сделать: -

Создать интерфейс в классе или отдельно от класса

public class FirebaseDB {

//This is your interface
public interface DBCallbacklistner {
    void onCallback(Map<String, Object> keyMap);
 }

public void getkeys(String any_value_you_need_to_pass, DBCallbacklistner dbCallbacklistner){
//I have used a different method here you can use your releveant method here
    database.somemethod(any_value_you_need_to_pass, new EventListener<DocumentSnapshot>() {
        @Override
        public void onEvent(@Nullable DocumentSnapshot documentSnapshot) {
       //Suppose you receive the callback here
            if(documentSnapshot.exists()){
                Map<String, Object> keysMap = (HashMap<String, Object>) documentSnapshot.getData();
              //Pass the callback in your interface
                dbCallbacklistner.onCallback(keysMap);
            }
        }
    });
}

}

Используйте этот интерфейс везде, где вы хотите

Используя функцию из класса, вызовите этот интерфейс и используйте значения

mFirebaseDBObject.getkeys(value, new FirebaseDB.DBCallbacklistner() {
        @Override
        public void onCallback(Map<String, Object> keyMap) {
            if (keyMap != null) {
                //Use your keymap here
            }
        }
    });

Еще одна вещь, которую я хочу отметить, заключается в том, что Если для разных вызовов слишком много обратных вызовов, я предлагаю создать отдельные интерфейсы, основанные на логическом разделении обратных вызовов. Потому что, если в одном интерфейсе много обратных вызовов, вам придется переопределить каждый из них, требуется вам это или нет.

1 голос
/ 07 февраля 2020

Внутри onDataChange(), вы можете просто вызвать метод:

ValueEventListener v =new ValueEventListener() {
            @Override
            public void onDataChange (@NonNull DataSnapshot dbSnapshot){
                String ourKey="";
                String ourValueID="";
                retrieveDataFromFb(dbSnapshot);

public void retrieveDataFromFb(DataSnapshot dataSnapshot){
          for (DataSnapshot childSnap : dbSnapshot.getChildren()) {
                    String childKey = childSnap.getKey();
                    if (childKey == null) {
                        //do some stuff 1 // and break/Continue/return
                    }

                    else  if(childKey.equals(ourKey)){
                        MyClass myClass =childSnap.getValue(MyClass.class);
                    }
}
0 голосов
/ 09 февраля 2020

В настоящее время я использую следующий подход:

Предположим, моя база данных firebase состоит из списка объектов, которые можно десериализовать в следующем формате:

 class MyClass{
        public String myClassUniqueID;
        ... other attributes;
    }

Для db i будет обрабатывать весь жизненный цикл слушателя события-значения в моей собственной деятельности (то есть присоединяться к ссылке на db через dbRef.addValueEventListener(dbListener); или dbRef.removeEventListener(dbListener);, но процесс создания этого dbListener и передачи ему необходимых задач будет управляться с помощью следующей служебной функции:

public interface DbListenerActions {
        void onMyClassObjFound(@NonNull MyClass matchedObj);

        default void onMyClassObjNOTFound() {

        }
    }



    public static ValueEventListener getMyClassObjectFinderListener(String id, DbListenerActions actions) {

        Log.e(TAG, "onDataChange:  our id:" + id);

        ValueEventListener dbListener = new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dbSnapshot) {

                for (DataSnapshot currChildSnap : dbSnapshot.getChildren()) {
                    String currChildKey = currChildSnap.getKey();
                    MyClass currChildValue = currChildSnap.getValue(MyClass.class);

                    if (currChildKey == null) {
                        Log.e(TAG, "onDataChange: currChildKey is null. continuing");
                        continue;
                    }
                    if (currChildValue == null) {
                        Log.e(TAG, "onDataChange: currChildValue is null.continuing");
                        continue;
                    }

                    if (currChildValue.myClassUniqueID.equals(id)) {
                        Log.e(TAG, "onDataChange: currChildValue id matches our id ");
                        Log.e(TAG, "onDataChange: performing action and RETURNING(i.e  getting out of this callback)");
                        //do stuff here
                        actions.onMyClassObjFound(currChildValue);
                        return;

                    } else {
                        Log.e(TAG, "onDataChange:  current obj DOES NOT matches our id. continuing");
                        Log.e(TAG, "onDataChange: current object ID :" + currChildValue.myClassUniqueID);
                        Log.e(TAG, "onDataChange: --------------------------------------------------------------");
                        continue;
                    }
                }
                Log.e(TAG, "onDataChange: user not found, performing not found action" );
                actions.onMyClassObjNOTFound();
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        };
        return dbListener;
    }

Таким образом, я могу получить необходимую информацию журнала, которую я хочу во время отладки, и так как есть только 2 возможных действия, которые я хочу выполнить, я получаю гораздо больше уверенности в работе моего слушателя: 50 строк необходимого, но избыточного кода из 11 операций, объединенных в одну служебную функцию!

Теперь все, что мне нужно написать, - это небольшая, более простая для отладки кусок кода в каждом из моих действий:

  ValueEventListener dbListener=getMyClassObjectFinderListener("some_id", new DbListenerActions() {
            @Override
            public void onMyClassObjFound(@NonNull MyClass matchedObj) {
                //callSomeFunction()
                // callSomeOtherFunction(matchedObj)
                //...
            }
        });

Так как я сделал onMyClassObjNOTFound(..) функцию default, мне даже не нужно пров Я думаю, что если я действительно не хочу выполнять какие-то действия там. Так что все это хорошо работает для меня: D

Я тоже спросил в твиттере об этом, кто-то сказал мне, что абстрактный класс также может быть использован для такой вещи. Мне не пришлось больше там исследовать, но если кто-то тоже знает об этом подходе, то дайте мне знать!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...