简体   繁体   English

Android-Firebase-获取孩子的孩子数据

[英]Android - Firebase - Getting Child of Child Data

Aim 目标

To prompt the data of the current user such as name , address , neighbourhood by acquiring them through the Data Tree within Firebase Database 通过Firebase数据库中的数据树获取当前用户的数据,例如姓名地址邻居等

Picture of the Data Tree 数据树的图片

在此处输入图片说明

Desrciption 宗旨

The "London" and "Washington" child within the Data Tree are added in by the Admin account, which means that they are not fixed and that an additional child such as "New York" can be added. 数据树中的“伦敦”和“华盛顿”子级是通过Admin帐户添加的,这意味着它们不是固定的,可以添加其他子级,例如“纽约”。

Which would mean that the newly edited Data Tree will have under "Users", there will be "London", "Washington", and "New York" 这意味着新编辑的数据树将位于“用户”下,其中将有“伦敦”,“华盛顿”和“纽约”

The other childs, such as those shown below are fixed. 其他孩子,例如下面显示的孩子是固定的。

  • Guards 守卫

    • name 名称
    • neighbourhood 邻里
  • Police 警察

    • address 地址
    • name 名称
    • neighbourhood 邻里
  • Resident 居民

    • address 地址

    • image 图片

    • name 名称

    • neighbourhood 邻里

    • position 位置

    • status 状态

Problem 问题

I receive a "java.lang.NullPointerException" after attempting to prompt the data of the current user who is logged in. 尝试提示登录的当前用户的数据后,我收到“ java.lang.NullPointerException”。

The error is showing at the code String stgUserHomeName = dataSnapshot.child("Users").getValue().toString(); 错误显示在代码String stgUserHomeName = dataSnapshot.child("Users").getValue().toString(); .

I was able to acquire my desired data such as "name", "address" and etc. before but when I had a problem when I added in a Not-Fixed parent such as "London" and "Washington". 我之前可以获取所需的数据,例如“名称”,“地址”等,但是当我添加“伦敦”和“华盛顿”等非固定父母时遇到问题时,我可以获取这些数据。

SettingsActivity Class 设置活动类

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<UploadTask.TaskSnapshot>(){
                @Override
                public void onComplete(@NonNull Task<UploadTask.TaskSnapshot> task) {
                    @SuppressWarnings("VisibleForTests")
                    String downloadImageUrl = task.getResult().getDownloadUrl().toString();

                    jSettingsDatabase.child("image").setValue(downloadImageUrl).addOnCompleteListener(new OnCompleteListener<Void>() {
                        @Override
                        public void onComplete(@NonNull Task<Void> 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();
                            }
                        }
                    });
                }
            });
        }
    }
}

Code Explanation 代码说明

The jSettingsHomeName and stgUserHomeName are meant to be the "London", "Washington", and etc. jSettingsHomeNamestgUserHomeName分别是“伦敦”,“华盛顿”等。

Solution to almost Similar Problem 解决几乎类似的问题

In the link: How to get child of child value from firebase in android? 在链接中: 如何从android中的Firebase获取子级的子级? , it shows how a programmer can get the child of a child but the reason as to why I am unable to follow the is because my "London" and "Washington" child tier isn't fixed ,它显示了程序员如何获取孩子的孩子,但之所以我无法遵循,是因为我的“伦敦”和“华盛顿”孩子级别不固定

Update: Trying Solution given by Ewald B. 更新: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) {

    }
});

Error 错误

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

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

According to the data model and looking at this statement 根据数据模型并查看此语句

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

there's no node User underneath /Resident/userId . /Resident/userId下没有节点User The query needs to start at the database's root which, I assume, is User . 该查询需要从数据库的根目录开始,我假设该根目录是User

In order to get London, Washington, etc. you need to adapt the code to: 为了获得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);
         ...
      }
      ....
   }
});

There's no user ID in your tree that is needed for this query. 您的树中没有此查询所需的用户ID。 But it might be necessary depending on the DB's access rules. 但是根据数据库的访问规则,可能有必要。 Obviously the other queries need to be adapted as well. 显然,其他查询也需要进行调整。 The city names are also not values but a key (must be unique) so what is important to call DataSnapshot.getKey() method. 城市名称也不是值,而是键(必须唯一),因此调用DataSnapshot.getKey()方法很重要。

In your case the whole database from the User downwards will be fetched and on the client all cities that are not needed will be thrown away. 在您的情况下,将从用户向下的整个数据库中获取数据,并在客户端上丢弃所有不需要的城市。 That's a waste of resources. 那是浪费资源。

for testing purposes only set your Firebase Realtime Database rule to allow anyone read and write 出于测试目的,仅将您的Firebase实时数据库规则设置为允许任何人读写

eg 例如

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

Check out Firebase Rules documentation https://firebase.google.com/docs/database/security/ 查看Firebase Rules文档https://firebase.google.com/docs/database/security/

As soon as you have multiple children at the node, it's needed to scan them at the loop. 一旦在节点上有多个子代,就需要在循环中对其进行扫描。 The event indicates that "some" child was changed. 该事件表明“某些”孩子已更改。 Also, try to change the event to onChildAdded. 另外,尝试将事件更改为onChildAdded。 Like below: 如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM