【问题标题】:App crashes when removing data from Firebase从 Firebase 中删除数据时应用崩溃
【发布时间】:2020-01-15 22:57:49
【问题描述】:

我正在为我的应用程序开发事件功能,我已经被这个错误困扰了 2 天。

总而言之,我登录应用程序并从 Firebase 检索一个 eventid,我将其设置为静态 User.eventid。当应用切换到 MainActivity 时,静态 User.eventid 用于决定使用哪个片段:ViewEventsFragment 或 DefaultEventFragment(带有 2 个按钮的空片段)。 如果 User.eventid="null",转到DefaultEventFragment否则转到ViewEventsFragment

最初,用户处于一个事件中,所以 User.eventid="LyfLmM...." 因此 MainActivity 会将用户带到 ViewEventsFragment。 现在,在 ViewEventsFragment 中,我可以选择删除一个事件。这样做后,我会更新 firebase eventid="null" 以供将来登录更新要在 MainActivity 中使用的静态 User.eventid="null"。然后启动意图并将用户带到 MainActivity,应用程序将根据 User.eventid 决定切换到哪个片段。由于我刚刚更改了静态 User.eventid="null",因此我应该转到 DefaultEventsActivity。

但这不起作用,我的应用程序反而崩溃了。我包含了从头到尾的代码和错误日志。

LoginActivity.class

// Retrieve information about the user from Firebase. One important field is eventid which represents 
// the event that the user is part of. If eventid=="null", then the user is not in any event.

JSONObject obj = new JSONObject(s);
eventid = obj.getJSONObject(id).getString("eventid");
User.eventid = eventid;
...
startActivity(new Intent(SignIn.this, MainActivity.class));

MainActivity.class

 // Once the user is taken to MainActivity, there is a bottom navigation that loads a fragment 
 // depending on the User.eventid retrieved in Login. If the user is an event, take them to 
 // ViewEventsFragment. if user is NOT in event, take them to DefaultEventsFragment

 @Override
 public boolean onNavigationItemSelected(@NonNull MenuItem item) {
     Fragment fragment;
     switch (item.getItemId()) {
                case R.id.event_button:

                    Log.i("ViewEventsFragment", "MainActivity: "+User.eventid);

                    if(User.eventid.equals("null")) {
                        fragment = fragmentA;
                    }
                    else {
                        fragment = fragmentB;
                    }
                    break;
            ...
            fragmentManager.beginTransaction().replace(R.id.frame_layout, fragment).commit();
            return true;
        }
    });

假设用户是事件的一部分。然后我们加载:

ViewEventsFragment.java

// In this fragment, the user is part of an event. This means that User.eventid is NOT "null" and 
// user was redirected here from MainActivity. So first pull all the
// data from firebase to populate the fields

Firebase.setAndroidContext(getActivity());
pullFirebaseData();

// Pull data from firebase and populate fields
// This function should only be called if eventid is NOT null
// But for some reason, it's being called while it's null and gets an error
public void pullFirebaseData(){

    eventid = User.eventid;    
    if((eventid==null) || (eventid.equals("null"))){
        User.eventid = "null";
        startActivity(new Intent(getActivity(), MainActivity.class));
    }  

    Firebase reference = new Firebase("https://...firebaseio.com/events");
    reference.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            **Line144** name = dataSnapshot.child(eventid).child("eventName").getValue().toString();
            date = dataSnapshot.child(eventid).child("eventDate").getValue().toString();
            time = dataSnapshot.child(eventid).child("eventTime").getValue().toString();
            ...
 }

// Suppose now user wants to delete the event. 
leaveGroupButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            // (1) First update Firebase by changing each users eventid to "null". This works. 
            // (2) Now, change User.eventid="null" since user is leaving the event and switch to 
            //     MainActivity. Since the User.eventid="null", the user SHOULd be taken to 
            //     DefaultEventsFragment and NOT back here. 
            // (3) Finally, delete the event from Firebase

                (1) changeAllUserFirebase();
                (2) User.eventid = "null"
                    startActivity(new Intent(getActivity(), MainActivity.class));
                (3) deleteEvent();
            }
        }
    });

// Remove the entire event from Firebase
public void deleteEvent(){
    Firebase reference = new Firebase("https://grouptracker-ef84c.firebaseio.com/events");
    reference.child(User.eventid).removeValue();
}

现在问题开始了。从日志中可以看出,我在 MainActivity 中成功获取了 eventid 并切换到 ViewEventFragment。现在,当我尝试删除它时,它会带我回到 ViewEventsFragments,而它应该带我去 MainActivity。

2020-01-15 17:40:15.514 18350-18350/com.package.appname I/ViewEventsFragment: MainActivity: -LyfLmMmO1mkB0gvB9P7

2020-01-15 16:38:24.905 17166-17166/com.package.appname E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.package.appname, PID: 17166
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference
    at com.package.appname.Fragments.ViewEventsFragment$4.onDataChange(ViewEventsFragment.java:144)
    at com.firebase.client.core.ValueEventRegistration.fireEvent(ValueEventRegistration.java:56)
    at com.firebase.client.core.view.DataEvent.fire(DataEvent.java:45)
    at com.firebase.client.core.view.EventRaiser$1.run(EventRaiser.java:38)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6669)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

所以我通过删除 deleteEvent() 对其进行了测试,它运行良好。我切换到 MainACtivity ==> DefaultEventFragment。现在我很困惑为什么从firebase中删除事件会使我的应用程序崩溃。

尝试:所以我尝试将 deleteEvent() 函数移至 Main。因此,一旦用户离开事件,它就会从 ViewEventsFragment 转到 Main。然后在 Main 中,它应该删除该事件。但是,该应用程序只是返回到 ViewEventsFragment 并崩溃。不确定是什么导致它强制转到 ViewEventsFragment。

【问题讨论】:

  • 这条线ViewEventsFragment.java:144在哪里?错误在这一行,toString()
  • 请指出发生错误的确切代码行。
  • 我更新了这些行。代码甚至不应该转到这一行,因为我正在删除事件并调用意图切换到另一个活动。但是由于某种原因,它并没有转到 MainActivity,而是重新加载 Activity 并导致错误。
  • 该错误是预期的,因为它试图从不存在的东西中检索字符串。

标签: android firebase firebase-realtime-database


【解决方案1】:

"当您使用 reference.addValueEventListener 注册侦听器时,它将在每次您正在侦听的数据发生更改时调用 onDataChange,包括当该数据被删除时,这意味着它将以 null 调用。您应该处理数据消失的可能性,或者在使用 removeEventListener 删除数据并传入同一个 ValueEventListener 实例之前取消注册侦听器。"

-来自 Reddit 的 AngusMcBurger


自从我删除数据以来,我的听众一直在读取新的更改,并且随着数据的消失,它正在获取一些不存在的东西。根据上面的逻辑,我重构了我的代码并做了一个新的监听器:

final Firebase reference = new Firebase("https://....firebaseio.com/...");

final ValueEventListener eventListener = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            name = dataSnapshot.child(eventid).child("eventName").getValue().toString();
            ...
            nameTextView.setText(name);
            ...
        }
    };
    // Here, I'm registering the listener
    reference.addValueEventListener(eventListener);
}

// *IMPORTANT*
leaveGroupButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
           ...
           // I'm done with the listener so now I'm removing it
           reference.removeEventListener(eventListener);                 
        }
}

【讨论】:

    猜你喜欢
    • 2020-01-19
    • 2019-08-16
    • 1970-01-01
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    相关资源
    最近更新 更多