我目前正在测试ValueEventListener的 onCancelled() 方法,以实现正确的firebase错误管理 . 到目前为止,我取得了成功,onCancelled()很好 . 我已为特定节点设置firebase规则以返回权限被拒绝错误 .

但我对如何在onCancelled()方法中管理全局变量感到困惑 . 为什么在 onCancelled() 中调用时全局变量似乎保持其默认初始状态?来自外部的变量更新不反映何时在此方法中调用它们,但在从 onDataChange() 和其他活动中方法调用时会反映出来 .

UPDATE NO. 2: 插入了firebase auth代码,添加了测试流程执行 . 还添加了@Doug Stevenson建议的日志输出 . 从日志中看来,onCancelled()只被调用一次(在app onCreate()期间) . 我认为这给了我一个错误的印象,即 currentSynId 从未改变,因为它的 Value 仍然是 Hello!!! 那里,我之前没有看过后记录 .

但是现在我看到有一个日志 W/RepoOperation: updateChildren at /2014 failed: DatabaseError: Permission denied ,每次调用时都会触发 R.id.btn_sync (并且再也不会记录 onCancelled 的日志,其中更新的 currentSyncId 应该是) . 也许我应该重新解释一下我的问题?我想捕获当前取消日志被触发的实例 . 谢谢 .

UPDATE NO. 1 我从完整的代码中取出了相关的部分并替换了之前的代码:

...

public class Demo extends AppCompatActivity {

    // Database reference
    private DatabaseReference mFirebaseMain2014;

    //
    private FirebaseAuth mAuth;

    public String currentSyncId = "Hello!!!";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo);

        // Initialize firebase auth
        mAuth = FirebaseAuth.getInstance();
        mAuth.addAuthStateListener(new FirebaseAuth.AuthStateListener() {
            @Override
            public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
                if(mAuth.getCurrentUser() != null) {
                    Log.d("MAIN", "A user was logged in: " + mAuth.getCurrentUser().getUid());
                    initDatabase(mAuth.getCurrentUser().getUid());
                }


                findViewById(R.id.btn_sync).setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        syncData();
                    }
                });

                findViewById(R.id.btn_echovalue).setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        printId();
                    }
                });
            }
        });
    }


    /**
     * Initialize database and listeners
     * @param userid
     */
    public void initDatabase(String userid){
        Log.d("MAIN", "Initialized databases");
        // Initialize database references
        mFirebaseMain2014 = FirebaseDatabase.getInstance().getReference("2014");
        mFirebaseMain2014.child("app_final/" + userid).addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                // data processing here..
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {
                Log.d("MAIN-ON-CANCELLED-EVENT", "An error occurred while syncing data: " +
                        databaseError.getMessage() + "\n id: " + currentSyncId);
            }
        });
    }


    /**
     * Initiate firebase syncing (which will lead to Permission-Denied
     */
    public void syncData(){
        // Log values
        Log.d("MAIN", "Initiating sync...");
        currentSyncId = "00001";

        // Set the dummy data that will be sent to firebase
        HashMap map = new HashMap();
        map.put(currentSyncId, "Hello, world!");

        // Sync dummy data to firebase
        mFirebaseMain2014.updateChildren(map);

        Log.d("MAIN", "Sync called.");
    }


    /**
     * Print the contents of global currentSyncId
     */
    public void printId(){
        Log.d("MAIN", "PRINTING CURRENT id value: " + currentSyncId + ", userid: " + getAuthUserId());
    }


    public String getAuthUserId(){
        return mAuth.getCurrentUser().getUid();
    }
}

TEST FLOW

  • 加载了应用程序

  • 按下 R.id.btn_echovalue 按钮

  • 按下 R.id.btn_sync 按钮

  • 按下 R.id.btn_echovalue 按钮

LOG OUTPUT

D/FirebaseAuth: Notifying id token listeners about user ( WN1b3pJyggNOvaoHDdtPsHrFLmG3 ).
I/FirebaseInitProvider: FirebaseApp initialization successful
D/FirebaseApp: Notifying auth state listeners.
               Notified 0 auth state listeners.
D/MAIN: A user was logged in: WN1b3pJyggNOvaoHDdtPsHrFLmG3
D/MAIN: Initialized databases
W/SyncTree: Listen at /2014/app_final/WN1b3pJyggNOvaoHDdtPsHrFLmG3 failed: DatabaseError: Permission denied
D/MAIN-ON-CANCELLED-EVENT: An error occurred while syncing data: Permission denied
                            id: Hello!!!
I/FirebaseAuth: [FirebaseAuth:] Loading module via FirebaseOptions.
                [FirebaseAuth:] Preparing to create service connection to gms implementation
D/FirebaseAuth: Notifying id token listeners about user ( WN1b3pJyggNOvaoHDdtPsHrFLmG3 ).
D/FirebaseApp: Notifying auth state listeners.
               Notified 1 auth state listeners.
D/MAIN: PRINTING CURRENT id value: Hello!!!, userid: WN1b3pJyggNOvaoHDdtPsHrFLmG3
D/MAIN: Initiating sync...
D/MAIN: Sync called.
W/RepoOperation: updateChildren at /2014 failed: DatabaseError: Permission denied
D/MAIN: PRINTING CURRENT id value: 00001, userid: WN1b3pJyggNOvaoHDdtPsHrFLmG3

里面的日志 onCancelled() 射得很好 . 我期待看到

MAIN: An error occurred while syncing data: Permission denied.
Sync ID: 0001

但相反,我看到:

MAIN: An error occurred while syncing data: Permission denied.
Sync ID: Hello!!!

我需要在 onCancelled() 被触发时跟踪 currentSyncId ,以便我可以将应用程序中的本地同步状态引用重置为 false .

我找了类似的案例和问题,但我找到的最接近的线程是如何调用 onCancelled herehere,以及一些对onDataChange的引用 . 我在@vincrichaud here找到了一个有趣的答案,但我不确定这是否也适用于firebase android .

TIA!