在单个位置放置Firebase值事件回调

问题描述 投票:0回答:3

[我经常发现自己在使用Firebase实时数据库时在多个活动中一次又一次地编写这段代码:

        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的工作方式,但它使我的代码更加难以阅读和调试。以某种方式使用这些回调的好方法是,我只编写一次此代码并整理我的代码库?一个示例将是很好的。

android firebase firebase-realtime-database
3个回答
0
投票

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
投票

据我了解,您希望将所有数据库方法存储在单独的类中,以便可以重用这些方法,这将使代码看起来更整洁,并且您尝试从Firebase返回它们时获取回调值。

有很多方法可以处理事件的回调,我建议是使用接口,它将使您的代码模块化并使其看起来更简洁,因此您可以将数据库方法存储在单独的类中(例如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
            }
        }
    });

我想指出的另一件事是,如果不同的调用有太多的回调,我建议根据回调的逻辑分隔来创建单独的接口。因为如果单个接口中有很多回调,那么无论是否需要,都必须覆盖它们中的每个回调。


0
投票

目前,我正在使用以下方法:

假设我的firebase数据库由可以反序列化为以下格式的对象列表组成:

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

对于数据库,我将在自己的活动中处理所有值事件侦听器的生命周期(即通过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种可能的操作,因此我对监听器的工作有了更多的保证。将11个活动中的50行必要但冗余的代码组合在一起,只有1个实用程序功能!

现在我需要写的只是这个小巧的代码,在我的每个活动中都更易于调试:

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

因为我做了onMyClassObjNOTFound(..)函数default,所以我什至不需要提供它,除非我真的想在那里执行一些操作。所以整个事情对我来说都很好:D

我也在Twitter上问了这件事,有人告诉我,抽象类也可以用于这件事。我在那里不需要做更多的研究,但是如果有人也知道这种方法,那么请告诉我!

© www.soinside.com 2019 - 2024. All rights reserved.