【问题标题】:Setting Boolean in datasnapshot returns null after setting it to true在 datasnapshot 中设置 Boolean 设置为 true 后返回 null
【发布时间】:2023-04-03 01:39:01
【问题描述】:

这是我的代码:

public class ChatActivity extends AppCompatActivity {

private String titleString, userID, uploadID, imageURL, userOnlineString;
private Boolean userOnlineBoolean;
private int imageRotation;
private TextView titleCustomBar, lastSeenCustomBar;
private ImageView imageCustomBar;
private DatabaseReference mDatabaseRefUser;
private FirebaseAuth mAuth;

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

    mAuth = FirebaseAuth.getInstance();
    mDatabaseRefUser = FirebaseDatabase.getInstance().getReference("Users");
    //Log.e("Lol", userOnlineString);

    mDatabaseRefUser.child(mAuth.getCurrentUser().getUid()).child("Online").addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            userOnlineBoolean = dataSnapshot.getValue(Boolean.class);
            Log.e("lol ", ""+userOnlineBoolean);

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            Toast.makeText(ChatActivity.this, "some error", Toast.LENGTH_SHORT).show();
        }
    });


    Intent intent = getIntent();
    titleString = intent.getStringExtra("TITLE");
    userID = intent.getStringExtra("USERID");
    uploadID = intent.getStringExtra("UPLOADID");
    imageRotation = intent.getIntExtra("IMAGEROTATION", 0);
    imageURL = intent.getStringExtra("IMAGEURL");



    ActionBar actionBar = getSupportActionBar();
    actionBar.setDisplayShowCustomEnabled(true);

    LayoutInflater layoutInflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
    View customActionBar = layoutInflater.inflate(R.layout.chat_custombar, null);

    actionBar.setCustomView(customActionBar);

    titleCustomBar = findViewById(R.id.title_textview_id);
    lastSeenCustomBar = findViewById(R.id.last_seen_textview_id);
    imageCustomBar = findViewById(R.id.custom_image_id);

    titleCustomBar.setText(titleString);

    //getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    Glide.with(this).load(imageURL)
            .into(imageCustomBar);
    imageCustomBar.setRotation(imageRotation);
   if(userOnlineBoolean){
       userOnlineString = "Online";
    }
    lastSeenCustomBar.setText(userOnlineString);



}

@Override
protected void onStart() {
    super.onStart();

    if(mAuth.getCurrentUser() == null){
        Intent mainActivityIntent = new Intent(this, MainActivity.class);
        startActivity(mainActivityIntent);
        finish();
    }
    else {
        mDatabaseRefUser.child(mAuth.getCurrentUser().getUid()).child("Online").setValue(true);

    }
}

}

在日志中,userOnlineBoolean 正在返回 true。再往下,if-statement中的userOnlineBoolean为null,这是为什么呢?

我尝试了很多更改,但没有任何效果。为什么返回true后为null。

我已经尝试解决这个问题几个小时,但我没有找到问题,或者没有看到问题。如果您知道我的代码有什么问题,请随时与您分享。

【问题讨论】:

  • 只是一个快速的猜测,您在匿名侦听器中打印变量,该侦听器通常以异步方式执行。可能是 if 子句中的代码被调用 before 它被记录在onDataChange 方法中?此外,您看到日志输出的时间可能比实际发生的时间要晚很多。
  • 我该如何解决这个问题?
  • 我已经发布了答案

标签: java nullpointerexception boolean


【解决方案1】:

虽然我没有运行代码,但我怀疑问题是由匿名内部类引起的。

我们看一下方法“onCreate”的执行情况:

你打电话给超级, 你打了几个静态电话。 您向对象添加事件侦听器(这是匿名内部类,创建此实例但未执行方法) 然后你分配一些值 再打几个电话。 然后你“如果”只在更改侦听器中更改的值。

此时您的布尔值尚未设置。 所以会抛出一个空指针。

有多种方法可以解决此问题,但希望您了解根本原因。

【讨论】:

  • 所以这意味着我的方法 onDataChange,直到 if 语句之后才被调用。我该如何解决我的问题?
【解决方案2】:

我设法通过这样做解决了我的问题:

public void onDataChange(DataSnapshot dataSnapshot) {
            userOnlineBoolean = dataSnapshot.getValue(Boolean.class);
            if(userOnlineBoolean){
                userOnlineString = "Online";
                settextmethod();
            }

 private void settextmethod() {
    lastSeenCustomBar.setText(userOnlineString);
}

但我还是不明白为什么我以前的方法是错误的。

【讨论】:

  • 这是因为您的 if 语句在您的更改侦听器之前执行。更改侦听器不会执行代码来设置您的布尔值,直到稍后发生更改事件,这可能是毫秒、秒、分钟,甚至永远不会。
  • 你的堆栈跟踪是什么?
【解决方案3】:

EventListener 通常被异步调用。您的if-clause 可能正在处理之前onDataChange 回调被执行。

在下方找到解决您问题的建议。

首先,您应该重新考虑变量userOnlineBoolean 本身。考虑变量在其生命周期中可能具有的状态总是一个好主意。在这种情况下,您可以争辩说只有两种状态:用户在线或不在线。如果是这样,您应该避免该变量为 undefinednull。立即初始化您的变量,即在声明它时:

private boolean userOnlineBoolean = false;

如您所见,我使用 primitive boolean 而不是包装类 Boolean 以确保它不能为空。

现在,onCreate() 方法中有很多代码。我不知道您的应用程序的上下文,但该方法可能只调用一次。但是,您希望 UI 的相关部分不仅更新一次,而且可能每次您的数据库更改。所以代码应该进入EventListener,或者更好的是,进入一个单独的方法,从EventListener中调用。

好吧,您可能想从 onCreate() 方法中删除以下代码:

if(userOnlineBoolean){
   userOnlineString = "Online";
}
lastSeenCustomBar.setText(userOnlineString);

并将其放入这样的新方法中。

private void updateUIOnDatabaseChange() {
   userOnlineString = userOnlineBoolean ? "Online" : "";
   lastSeenCustomBar.setText(userOnlineString);
}

注意,我考虑过用户状态从在线变为不在线的情况。这就是为什么我用三元运算符(if-else 的缩写形式)替换了if 子句。

同时更新您的onDataChange

@Override
public void onDataChange(DataSnapshot dataSnapshot) {
  userOnlineBoolean = dataSnapshot.getValue(Boolean.class);
  updateUIOnDatabaseChange();
  Log.e("lol ", ""+userOnlineBoolean);
}

我认为这是一个更实用和合理的设计。让我知道这是否适合您。

【讨论】:

    猜你喜欢
    • 2012-04-02
    • 1970-01-01
    • 2020-05-13
    • 2011-11-17
    • 2020-06-27
    • 1970-01-01
    • 2020-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多