【问题标题】:Firebase access child with random generated key具有随机生成密钥的 Firebase 访问子项
【发布时间】:2017-08-13 20:48:07
【问题描述】:

我正在尝试创建一个基本应用程序,在该应用程序中,我将消息发送到 Firebase 中的实时数据库并在列表视图中接收它们。(它是 Whatsapp 的翻版。)我发送用户的用户名和消息通过推送消息到数据库。但是,由于随机生成的密钥,我无法读取它们并从中创建列表视图。 有没有办法接收参考聊天的所有孩子并将它们放在列表视图中?

ps。我不能使用 .getKey 函数,因为消息将来自不同的设备。

pps。 可以提供额外的代码或详细信息。

代码:

public class MessageBoard extends AppCompatActivity {
    private static final String TAG = "MessageBoard";

    private FirebaseAuth mAuth= FirebaseAuth.getInstance();
    private FirebaseDatabase database = FirebaseDatabase.getInstance();
    private FirebaseUser user = mAuth.getCurrentUser();
    private ArrayList<String> chatlist;
    private ArrayAdapter<String> arrayAdapter;
    private DatabaseReference ref;
    private DatabaseReference Users;
    private String username;
    private String email;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_message_board);

        final Button SignOut = (Button) findViewById(R.id.SignOut);
        final Button SendMessage = (Button) findViewById(R.id.SendMessage);
        final EditText MessageText = (EditText) findViewById(R.id.Message_Text);
        final ListView listView = (ListView) findViewById(R.id.Listview);
        final TextView UserNameDis = (TextView) findViewById(R.id.UserNameDisplay);
        if(user != null){
            email = user.getEmail();

        }


        chatlist = new ArrayList<String>();

        arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, chatlist);

        listView.setAdapter(arrayAdapter);

        ref = database.getReference("chat");

//-----------------------------------------------------------------------------------------------------------------------------------------
//to login screen

        if(user == null){
            startActivity(new Intent(MessageBoard.this, Login.class));
            Log.d(TAG, "Login");
        }else{
            Toast.makeText(MessageBoard.this, "Login Succesfull.",
                    Toast.LENGTH_SHORT).show();
        }




//-----------------------------------------------------------------------------------------------------------------------------------------
//to username screen
        if(user.getDisplayName() == null){
            startActivity(new Intent(MessageBoard.this, Username.class));
            Log.d(TAG, "Username");
        }else{
            Toast.makeText(MessageBoard.this, "Username Known.",
                    Toast.LENGTH_SHORT).show();
        }



//-----------------------------------------------------------------------------------------------------------------------------------------
        //set username welcome text
        username = user.getDisplayName();
        String Welcome = "Welcome " + username;
        UserNameDis.setText(Welcome);


//-----------------------------------------------------------------------------------------------------------------------------------------
//sign out button
        SignOut.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                FirebaseAuth.getInstance().signOut();
                startActivity(new Intent(MessageBoard.this,Login.class));

            }
        });



//-----------------------------------------------------------------------------------------------------------------------------------------
// chat data update
        ref.orderByKey();

        ref.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                //where I think the receiving code should be
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });
//-----------------------------------------------------------------------------------------------------------------------------------------
//message send
        SendMessage.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v) {
                String push = ref.push().getKey();
                ref.child(push).child("message").setValue(username);
                ref.child(push).child("username").setValue(username);

            }
        });
//-----------------------------------------------------------------------------------------------------------------------------------------
    }

}

【问题讨论】:

    标签: android firebase firebase-realtime-database


    【解决方案1】:

    从节点检索数据,您可以在其中获取每个随机生成的密钥及其值。

    ref.addValueEventListener(new ValueEventListener()
    {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot)
    {
        HashMap<String, Object> allMessage = (HashMap<String, Object>) 
        dataSnapshot.getValue();
        String[] pushIds = allMessage.keySet().toArray(new String[0]);
        for (int j = 0; j < allMessage.size(); j++)
        {
            HashMap<String, Object> singleMessage = (HashMap) 
            allMessage.get(pushIds[j]);
            Message message = new message(singleMessage);
            allRequests.add(message);
    
        }
    }
    
    @Override
    public void onCancelled(DatabaseError databaseError)
    {
    
    }
    });
    

    你的模型类

     public class Message
     {
        String message;
        public Message(HashMap<String,Object> singleMessage)
      {
        message = singleMessage.get("message").toString();
      }
      };
    

    【讨论】:

    • 您能解释一下这是如何工作的吗?或者参考我可以在哪里了解更多信息?
    • 它将您的所有消息数据接收到一个对象类中。从所有对象中,它会将您的所有 pushid 放入一个字符串数组中。然后在 pushid 数组的帮助下,它获取一条与 pushid[j] 相关联的消息。但是消息在 Hasmap 对象中。所以我必须将它转换为我的对象类,即消息。在创建 Message 的新对象时,它在构造函数中使用 Hasmap 对象并将 hasmap 数据转换为我的对象数据……这有点令人困惑。还有其他方法可以做到这一点,但你必须创建一个额外的类。
    【解决方案2】:

    我没有看到您说您要根据随机生成的密钥订购的任何逻辑(意味着您对这些密钥一无所知)。你为什么要这样做?您可以使用 email_id 或 device_id 作为键,以便跟踪特定节点。这节省了大量的互联网络带宽,因为只有在特定节点发生变化时才会发生 PUSH。

    在您的情况下,有更好的解决方案:

    1) 你不会随机生成密钥;您可以使用 device_id,它是唯一的固定值作为键。这样每个客户端都可以跟踪特定的节点。 ——这是最好的办法。

    2) 如果您必须有随机生成的密钥,那么您可以将Map&lt;ID, MSG_TEXT&gt; 放入您的 JSON 消息数组对象(节点)中。但是,问题在于,每个设备都必须在 Json Message Array 节点上监听。如果发生数百万个设备 R/W,则意味着可能会有不必要的消息到达您的设备,因为根据 firebase 的数据快照定义,JSON 消息数组中的任何内容都会发生更改,PUSH 会发生。

    如果您的设备数量有限(100 台或更少),那没关系。在这种情况下,任何设备都可以使用setValue("Map&lt;Random_key, msg&gt;") 来增加价值。每条新消息都有新的索引(比如第一条消息有 0,第二条有 1,依此类推)。因此,您可以按索引排序。

    您可以在 Firebase 节点中写入哪些值,请参阅此链接:https://firebase.google.com/docs/database/android/read-and-write

    【讨论】:

    • 当我希望连接到数据库的每个人都收到解决方案 1 时,它是否仍然有效?
    • 是的,这确实是标准方法。我已经在我的应用程序中实现了这种方法。因为你可以特别选择你想听哪个节点。并且 Firebase PUSH 服务器仅推送该消息,当您确实收听的该节点发生更改时。这是最好的方法,可以扩展到数十亿台设备。
    • 您根据设备 ID 或 email_id 生成节点,然后调用 setValue("your message")
    • 我仍然不明白如何将消息(以设备 ID 作为键)放入列表视图。我还没有学会如何在没有 .child() 函数的情况下接收消息。例如,如果 2 个人互相说“你好”这个词,就会有带有 2 个不同设备 ID 的键。我不明白如何将这些放入列表视图中。
    • 好的,你生成设备 ID 并创建 Map。现在您可以将整个 Map 对象放入您的 JSON 消息数组中。 Firebase 会自动为您的每条消息编制索引。
    猜你喜欢
    • 1970-01-01
    • 2017-02-10
    • 2014-07-20
    • 2012-06-18
    • 2018-09-10
    • 2015-09-27
    • 1970-01-01
    • 2012-11-15
    • 1970-01-01
    相关资源
    最近更新 更多