Android – Firebase – 获取子数据的子项

目标

通过Firebase数据库中的数据树获取当前用户的数据,如名称地址邻域 ,以提示他们的数据

数据树的图片

在此处输入图像描述

Desrciption

数据树中的“伦敦”和“华盛顿”子项由管理员帐户添加,这意味着它们不是固定的,并且可以添加其他子项,如“纽约”。

这意味着新编辑的数据树将在“用户”下,将有“伦敦”,“华盛顿”和“纽约”

其他孩子,如下面显示的那些孩子是固定的。

  • 逆天

    • 名称
    • 邻里
  • 警察

    • 地址
    • 名称
    • 邻里
  • 居民

    • 地址

    • 图片

    • 名称

    • 邻里

    • 位置

    • 状态

问题

尝试提示当前登录用户的数据后,我收到“java.lang.NullPointerException”。

错误显示在代码String stgUserHomeName = dataSnapshot.child("Users").getValue().toString();

我之前能够获得我想要的数据,例如“姓名”,“地址”等,但是当我在“伦敦”和“华盛顿”这样的非固定父母中添加时,我遇到了问题。

SettingsActivity类

 import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.FirebaseUser; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.ValueEventListener; import com.google.firebase.storage.FirebaseStorage; import com.google.firebase.storage.StorageReference; import com.google.firebase.storage.UploadTask; import com.squareup.picasso.Callback; import com.squareup.picasso.NetworkPolicy; import com.squareup.picasso.Picasso; import java.io.File; public class SettingsActivity extends AppCompatActivity { private DatabaseReference jSettingsDatabase; private FirebaseUser jFirebaseCurrentUser; private Toolbar jSettingsToolbar; private ImageView jSettingsImageView; private TextView jSettingsDisplayName; private TextView jSettingsStatus; private TextView jSettingsAddress; private TextView jSettingsHomeName; private Button jSettingsDetailsBtn; private Button jSettingsImageBtn; private static final int jSettingsGallerySelect = 1; private StorageReference jSettingsStorageReference; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_settings); jSettingsStorageReference = FirebaseStorage.getInstance().getReference(); jFirebaseCurrentUser = FirebaseAuth.getInstance().getCurrentUser(); String settingsUserID = jFirebaseCurrentUser.getUid(); jSettingsDatabase = FirebaseDatabase.getInstance().getReference().child("Resident").child(settingsUserID); jSettingsDatabase.keepSynced(true); jSettingsImageView = (ImageView) findViewById(R.id.settingUserImg); jSettingsToolbar = (Toolbar) findViewById(R.id.settingsToolBar); setSupportActionBar(jSettingsToolbar); getSupportActionBar().setTitle("Settings"); getSupportActionBar().setDisplayHomeAsUpEnabled(true); jSettingsDisplayName = (TextView) findViewById(R.id.settingUserNameTxt); jSettingsStatus = (TextView) findViewById(R.id.settingUserStatusTxt); jSettingsAddress = (TextView) findViewById(R.id.settingUserAddressTxt); jSettingsHomeName = (TextView) findViewById(R.id.settingsUserHomeTxt); jSettingsDetailsBtn = (Button) findViewById(R.id.settingChangeDetailsBtn); jSettingsImageBtn = (Button) findViewById(R.id.settingChangeImageBtn); jSettingsDatabase.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { String stgUserHomeName = dataSnapshot.child("Users").getValue().toString(); String stgUserName = dataSnapshot.child("Users").child(stgUserHomeName).child("name").getValue().toString(); String stgUserStatus = dataSnapshot.child("Users").child(stgUserHomeName).child("status").getValue().toString(); String stgUserHomeAddress = dataSnapshot.child("Users").child(stgUserHomeName).child("address").getValue().toString(); final String stgUserImage = dataSnapshot.child("Users").child(stgUserHomeName).child("image").getValue().toString(); jSettingsDisplayName.setText(stgUserName); jSettingsStatus.setText(stgUserStatus); jSettingsAddress.setText(stgUserHomeAddress); if(!stgUserImage.equals("default")){ Picasso.with(SettingsActivity.this).load(stgUserImage).networkPolicy(NetworkPolicy.OFFLINE) .placeholder(R.drawable.avataricon).into(jSettingsImageView, new Callback() { @Override public void onSuccess() { } @Override public void onError() { Picasso.with(SettingsActivity.this).load(stgUserImage).placeholder(R.drawable.avataricon).into(jSettingsImageView); } }); } } @Override public void onCancelled(DatabaseError databaseError) { } }); jSettingsDetailsBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String stgUserStatusValue = jSettingsStatus.getText().toString(); String stgUserAddressValue = jSettingsAddress.getText().toString(); String stgUserNameValue = jSettingsDisplayName.getText().toString(); Intent intentDetails = new Intent(SettingsActivity.this, DetailsActivity.class); intentDetails.putExtra("stgUserNameValue" , stgUserNameValue); intentDetails.putExtra("stgUserStatusValue", stgUserStatusValue); intentDetails.putExtra("stgUserAddressValue", stgUserAddressValue); startActivity(intentDetails); } }); jSettingsImageBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intentGallery = new Intent(); intentGallery.setType("image/*"); intentGallery.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult(Intent.createChooser(intentGallery, "SELECT IMAGE"), jSettingsGallerySelect); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(requestCode == jSettingsGallerySelect && resultCode == RESULT_OK){ Uri imageUri = data.getData(); String currentUserID = jFirebaseCurrentUser.getUid(); StorageReference imageFilePath = jSettingsStorageReference.child("profileImages").child(currentUserID+".jpg"); imageFilePath.putFile(imageUri).addOnCompleteListener(new OnCompleteListener(){ @Override public void onComplete(@NonNull Task task) { @SuppressWarnings("VisibleForTests") String downloadImageUrl = task.getResult().getDownloadUrl().toString(); jSettingsDatabase.child("image").setValue(downloadImageUrl).addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { if(task.isSuccessful()){ Toast.makeText(SettingsActivity.this, "Upload Successful", Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(SettingsActivity.this, "Upload Failed", Toast.LENGTH_SHORT).show(); } } }); } }); } } } 

代码说明

jSettingsHomeNamestgUserHomeName意味着“伦敦”,“华盛顿”等。

解决几乎相似的问题

在链接: 如何从android中的firebase获取子值的子项? ,它显示了一个程序员如何能够得到一个孩子的孩子但是为什么我无法遵循的原因是因为我的“伦敦”和“华盛顿”子层没有修复

更新:Ewald B.提供的尝试解决方案

 jSettingsDatabase.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { for(DataSnapshot node : dataSnapshot.getChildren()) { String stgUserHomeName = node.getKey(); String stgUserName = node.child("Resident").child(settingsUserID).child("name").getValue().toString(); String stgUserStatus = node.child("Resident").child(settingsUserID).child("status").getValue().toString(); String stgUserHomeAddress = node.child("Resident").child(settingsUserID).child("address").getValue().toString(); final String stgUserImage = node.child("Resident").child(settingsUserID).child("image").getValue().toString(); jSettingsHomeName.setText(stgUserHomeName); jSettingsDisplayName.setText(stgUserName); jSettingsStatus.setText(stgUserStatus); jSettingsAddress.setText(stgUserHomeAddress); if(!stgUserImage.equals("default")){ Picasso.with(SettingsActivity.this).load(stgUserImage).networkPolicy(NetworkPolicy.OFFLINE) .placeholder(R.drawable.avataricon).into(jSettingsImageView, new Callback() { @Override public void onSuccess() { } @Override public void onError() { Picasso.with(SettingsActivity.this).load(stgUserImage).placeholder(R.drawable.avataricon).into(jSettingsImageView); } }); } } } @Override public void onCancelled(DatabaseError databaseError) { } }); 

错误

com.example.task.app.SettingsActivity $ 1.onDataChange(SettingsActivity.java:91)中的java.lang.NullPointerException

第91行指向String stgUserName = node.child("Resident").child(settingsUserID).child("name").getValue().toString();

根据数据模型并查看此声明

 jSettingsDatabase = FirebaseDatabase.getInstance().getReference().child("Resident").child(settingsUserID); 

/Resident/userId下面没有节点User 。 查询需要从数据库的根开始,我认为是根User

为了获得London, Washington, etc.您需要调整代码:

 jSettingsDatabase = FirebaseDatabase.getInstance().getReference().child("Users"); ... jSettingsDatabase.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { for(DataSnapshot node : dataSnapshot.getChildren()) { // you will get all cities String stgUserHomeName = node.getKey(); if(!"Washington".equals(stgUserHomeName)) // or whatever city you need continue; // add some more conditional logic to cope with the distinct subtrees that don't have the same properties // London's Resident has more properties than Washington --> exception is thrown then // to get the resident's data node.child("Resident").child(userId).child("address")... node.child("Resident").child(userId).child("image")... // or node.child("Resident").child(userId).getValue(Resident.class); ... } .... } }); 

您的树中没有此查询所需的用户ID。 但根据数据库的访问规则,可能需要它。 显然,其他查询也需要进行调整。 城市名称也不是值,而是键(必须是唯一的),因此调用DataSnapshot.getKey()方法非常重要。

在您的情况下,将提取用户向下的整个数据库,并且在客户端上将丢弃所有不需要的城市。 这是浪费资源。

出于测试目的,仅将Firebase实时数据库规则设置为允许任何人进行读写操作

例如

 { "rules": { ".write": "true", ".read": "true" } } 

查看Firebase规则文档https://firebase.google.com/docs/database/security/

只要节点上有多个子节点,就需要在循环中扫描它们。 该事件表明“一些”孩子被改变了。 此外,尝试将事件更改为onChildAdded。 如下所示:

 public void onChildAdded(DataSnapshot dataSnapshot, String s) { if (dataSnapshot.getChildrenCount() > 0) { for (DataSnapshot ds1 : dataSnapshot.getChildren()) { String stgUserHomeName = ds1.getValue.toString(); .....