【问题标题】:Adding a multi-node ArrayList to Firebase Realtime-Database将多节点 ArrayList 添加到 Firebase 实时数据库
【发布时间】:2018-10-28 22:42:49
【问题描述】:

我已经在这个多人游戏大厅工作了几天,我很挣扎让我告诉你。

无论如何,我正在纸上修改问题,以便我可以逐步实现我想要做的事情。我的大厅的简单步骤如下:

  1. 用户单击“创建游戏”按钮
  2. 该按钮调用 createGame 方法,该方法将节点添加到我的实时数据库中的 openGames 根目录中
  3. 该节点有更多子节点,例如用户名、用户 ID、游戏在列表中的索引以及其他一些内容。
  4. 这个在arraylist中被索引的游戏,通过RecyclerView被绘制到屏幕上

这是我目前的流程,但我不确定我是否遗漏了任何步骤。当然,这些步骤背后有很多代码,但这只是要点。

我的问题是如何做到这一点,以便在用户创建游戏时,如何将其正确添加到实时且可供所有用户访问的 ArrayList 中。现在,对于所有用户来说,ArrayList 并不相同。因此,如果一个人制作了一款游戏,该游戏会添加到实时数据库中,但不会添加到每个用户的列表中。

如何制作动态实时 ArrayList?

这是当前将游戏同时添加到数据库和列表的方法。

    gameMaker = new GameMaker(hp.uid, userName, wagerD, numGames);

    cgRef.child(Integer.toString(numGames))
            .setValue(gameMaker).addOnCompleteListener(new OnCompleteListener<Void>() {
        @Override
        public void onComplete(@NonNull Task<Void> task) {
                if (task.isSuccessful()) {
                Toast.makeText(FlipCoinLobby.this, "Game creation successful.", Toast.LENGTH_SHORT).show();
                uName = gameRef.child("Username").toString();

                openGames.add(numGames, uName);

                adapter.notifyDataSetChanged();
            } else {
                Toast.makeText(FlipCoinLobby.this, task.getException().getMessage(), Toast.LENGTH_SHORT).show();
            }
        }
    });

我的 ArrayList 在类的顶部被简单地定义为:

ArrayList<String> openGames = new ArrayList<>();

【问题讨论】:

    标签: java android firebase firebase-realtime-database


    【解决方案1】:

    我在 Firebase 中做过类似的游戏。我通常使用onDataChange() 方法来验证每个客户端都知道gameRoom 的列表发生了变化。

    • 用户点击多人游戏

    • 如果已经有空房间,则客户端进入。

    • 如果其他房间已满或没有空房间,则客户端创建一个房间

    • 配对完毕,开始比赛

    • 比赛结束时,第一个客户端修改用户变量,第二个删除整个房间的孩子。

    如果你想创建一个动态数组列表,你必须使用onDataChange() 方法并在每次数组列表更改时使用它。如果数组列表已更改,您必须更新每个客户端数组列表。

    存在很多竞争问题。


    我的 firebase 数据库是这样的: 一般:

    帐户用于登录信息,对于想要玩多人游戏的人来说是必须的

    Every_Flag 是可供多人游戏使用并由每个客户端下载的标志列表。在客户端代码中,每个标志都有特定的多人游戏 ID - 0、1、2 等 易于更新。

    最后是比赛:

    数据库参考:

     private DatabaseReference Matchmaking, Room,Accounts;
    

    如果玩家登录,多人游戏按钮将变为可访问。 此方法对于在 db 中获取或不可用的每个匹配项很有用:

    //metodo per la gestione dei cambiamenti della tabella Matchmaking
            Matchmaking.addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    //nel caso ci siano delle modifiche alla tabella
                    //se il match non è stato trovato e Account è stato verificato
                    if(accountFound){
                        //azzero la Lista
                        List_party = new ArrayList<>();
                        Id_rooms = new ArrayList<>();
                    for (DataSnapshot ds : dataSnapshot.getChildren()) {
                        //sempre se matchfound non è stato trovato
                        if (!currentwithID.getMatch_found()) {
                            //prendo la quantità di figli presenti
                            size = Integer.parseInt(String.valueOf(dataSnapshot.getChildrenCount()));
                            //inserisco all'interno della variabile CT il valore di ogni figlio
                            ct = ds.getValue(Class_party.class);
                            // e se è il numero di giocatori == 1 e la partita non è iniziata e finita in modo anomalo
                            if (ct.getNumberOfPlayers() == 1 && !ct.getStart() && ct.getCorrect_end() && ct.getAccessible()) {
                                //aggiungo l'id della room alla lista
                                //Inserisco alla list_party l'intero oggetto
                                Id_rooms.add(ct.getId());
                                List_party.add(ct);
                            }
    
                            Toast.makeText(HomeActivity.this, "Lista ROOMs aggiornata", Toast.LENGTH_SHORT).show();
                        }
                    }
                    }
                }
    

    这就是我生成匹配的方式:

    //MATCHMAKING
    public void Create(View view)
    {
        boolean start = false;
        boolean correct_end = true;
        boolean accessible = true;
        uSer = user.getDisplayName();
        //se la lunghezza delle partite disponibili a cui accedere è ==0
        if(size==0||Id_rooms.size()==0)
        {
            //creo la chiave univoca per il match
            String id = Matchmaking.push().getKey();
            //creo un utente corrente con nome e punteggio
            current=new Class_user(uSer,0);
            //un utente con ID utente, nome e se il match è stato trovato
            //genero le domande che verranno utilizzato solo per quel determinato match
            list_game= Generation();
            //ora creo il match vero e proprio e lo inserisco nella tabella matchmaking
            second = new Class_party(id, current, list_game,start,correct_end,accessible);
            Matchmaking.child(id).setValue(second); }
        else{
            accessible = false;
            // se invece ci sono delle partite disponibili, le randomizzo
            Collections.shuffle(Id_rooms);
            for(int i=0; i<List_party.size();i++)
            {
                //le passo tutte finché non trovo quella con l'ID corrispondente alla prima che ho randomizzato
                if(List_party.get(i).getId()==Id_rooms.get(0))
                {
                    // popolo la variabile class_party
                    second=new Class_party(List_party.get(i).getId(),List_party.get(i).getUser1(),List_party.get(i).getFlag(),start,correct_end,accessible);
                }
            }
            matchFound = false;
            //inserisco l'utente e il numero di giocatori = 2
            currentwithID = new Class_user(uID,uSer,matchFound);
            current=new Class_user(uSer,0);
            second.setUser2(current);
            second.setNumberOfPlayers(2);
            //ora reinserisco tutto nel figlio che ha come ID, quello della stanza selezionata
            Matchmaking.child(second.getId()).setValue(second);
            Accounts.child(uID).setValue(currentwithID);
        }
    
    }
    
    public ArrayList<Integer> Generation()
    {
        ArrayList<Integer> tmp = new ArrayList<>();
        Collections.shuffle(mFlag);
        for(int i=0; i<=10; i++) //3 momentaneamente
        {
            tmp.add(mFlag.get(i));
        }
        Toast.makeText(HomeActivity.this,"Domande generate",Toast.LENGTH_LONG).show();
    
        return tmp;
    }
    

    首先,我设置了所有变量。 uSer 是我从 google auth 获得的名称。 如果可用房间为 0,我创建空房间,生成列表 标志(随机 10 个标志) 并插入它是一个类的孩子:

    public class Class_party {
    
    public Class_user user1, user2;
    public int numberOfPlayers;
    public String id;
    public ArrayList<Integer> value;
    public boolean start,correct_end,accessible;
    
    public Class_party(String id,Class_user user1, ArrayList<Integer> value, Boolean start,Boolean correct_end, Boolean accessible) {
        this.value = value;
        this.user1 = user1;
        this.numberOfPlayers = 1;
        this.id = id;
        this.start = start;
        this.accessible = accessible;
        this.correct_end = correct_end;
        user2 = null;
    
    }
    
    
    public Class_party() {
    }
    
    public Class_user getUser1() {
        return user1;
    }
    
    public void setUser1(Class_user user1) {
        this.user1 = user1;
    }
    
    public Class_user getUser2() {
        return user2;
    }
    
    public void setUser2(Class_user user2) {
        this.user2 = user2;
    }
    
    public int getNumberOfPlayers() {
        return numberOfPlayers;
    }
    
    public void setNumberOfPlayers(int numberOfPlayers) {
        this.numberOfPlayers = numberOfPlayers;
    }
    
    public String getId() {
        return id;
    }
    
    public void setId(String id) {
        this.id = id;
    }
    
    public ArrayList<Integer> getFlag() { return value; }
    
    public void setValue(ArrayList<Integer> value) {
        this.value=value;
    

    如果我找到匹配项或匹配项列表,我会选择随机匹配项 我找到它并在 FirebaseDatabase 中设置了第二个用户 使用这个特定的字符串:Matchmaking.child(second.getId()).setValue(second);

    现在,我们有了一个名为 MULTIPLAYER 的新活动:

    在这个活动中,我创建了多人游戏,但让我们看看我如何获取所有信息并设置所有变量。 首先,我使用 onDataChange 来获取比赛中的每一个变化。

     Matchmaking.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                //prendo tutte le tabelle e le aggiungo a list_party
                    for (DataSnapshot ds : dataSnapshot.getChildren()) {
                        ct = ds.getValue(Class_party.class);
                        List_party.add(ct);
                    }
                    // mi prendo la partita che mi interessa
                    for (int i = 0; i < List_party.size(); i++) {
                        if (List_party.get(i).getId() == intent_id) {
                            ct = List_party.get(i);
                        }
                    }
                    //controllo che gli utenti collegati siano due e che la partita non sia cominciata ne finita in modo anomalo
                if (ct.getNumberOfPlayers() == 2 && !ct.getAccessible() && ct.getCorrect_end() && !ct.getStart()) {
                        //mi scarico le bandiere che sono state scelte alla creazione della ROOM
                    FlagsFromDB = ct.getFlag();
                    //passo dal Layout di Waiting a quello iniziale
                    switchToScreen(R.id.screen_intro);
                    matchFound=true;
                    Toast.makeText(MpMultiplayer.this, "Match Found", Toast.LENGTH_SHORT).show();
                    //imposto il match trovato = true
                    currentwithID.setMatch_found(true);
                    //aggiorno la tabella
                    Accounts.child(uID).setValue(currentwithID);
                }
                //se la partita è cominciata e il numero di giocatori è uguale a due e match_found = true
                if (ct.getStart() && ct.getNumberOfPlayers()==2 && matchFound) {
                        //dico che la room è stata creata
                    roomcreated = true;
                    //ora il gioco comincia e cambio di layout
                    switchToScreen(R.id.screen_game);
                    Popolate();
                }
                //se qualcuno esce prima del previsto e la partita è già cominciata
                if(!ct.getCorrect_end() && roomcreated)
                {
                    //assegno automaticamente all'utente 500 punti
                    points += 500;
                    timer1.cancel();
                    mName.setText(intent_user + " You Won!");
                    mName.setTextSize(25);
                    mPoints.setText(new Integer(points).toString());
                    switchToScreen(R.id.screen_score);
                    Toast.makeText(MpMultiplayer.this, "The player LEFT the game", Toast.LENGTH_SHORT).show();
                }
                //se l'utente si è scollegato e la partita non è ancora cominciata
                if(!ct.getCorrect_end() && !roomcreated)
                {  //assegno automaticamente 100 punti
                    points += 100;
                    mName.setText(intent_user + "You Won!");
                    mName.setTextSize(25);
                    mPoints.setText(new Integer(points).toString());
                    switchToScreen(R.id.screen_score);
                    Toast.makeText(MpMultiplayer.this, "The player LEFT the game", Toast.LENGTH_SHORT).show();
                }
            }
    
            @Override
            public void onCancelled(DatabaseError databaseError) {
            }
        });
    

    当两个用户之一按下开始按钮时,我用这种方法更改数据库变量:

       void ChangeStartValue(){
    
            Room = FirebaseDatabase.getInstance().getReference("Matchmaking");
            try {
                ct.setStart(true);
                Room.child(ct.getId()).setValue(ct);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        void switchToScreen(int screenId) {
            // make the requested screen visible; hide all others.
            for (int id : SCREENS) {
                findViewById(id).setVisibility(screenId == id ? View.VISIBLE : View.GONE);
            }
        }
    

    这是当用户完成比赛并按下 backToMainMenu 按钮时:

     private View.OnClickListener backtomainmenu = new View.OnClickListener() {
        @Override
        public void onClick(final View view) {
            try {
                if(ct.getNumberOfPlayers()==2){
                ct.setNumberOfPlayers(ct.getNumberOfPlayers()-1);
                Room.child(ct.getId()).setValue(ct);
                Accounts.child(uID).child("match_found").setValue(false);
                }
                else
                    if (ct.getNumberOfPlayers()==1 && ct.getStart()&& ct.getCorrect_end()){
                        Room.child(ct.getId()).removeValue();
                        Accounts.child(uID).child("match_found").setValue(false); }
                        else
                            if(ct.getNumberOfPlayers()==1 && ct.getStart() && !ct.getCorrect_end()){
                                Room.child(ct.getId()).removeValue();
                                Accounts.child(uID).child("match_found").setValue(false);}
                                else
                                    if(ct.getNumberOfPlayers()==1 && !ct.getStart() && !ct.getCorrect_end()) {
                                        Room.child(ct.getId()).removeValue();
                                        Accounts.child(uID).child("match_found").setValue(false);}
    
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            finish();
    
        }
    };
    

    如果用户想在没有完成比赛的情况下出去:

     @Override
        //in caso l'utente voglia uscire
        public void onBackPressed() {
            backpress = (backpress + 1);
            // se preme una volta compare il toast
            if (backpress >= 1 && backpress < 2)
                Toast.makeText(getApplicationContext(), " Press Back again to Exit ", Toast.LENGTH_SHORT).show();
            //se preme per più di una volta esce
            if (backpress > 1) {
                try {
                    //se i giocatori sono più di due, setto i giocatori ad 1 e Correct End a false
                    if(ct.getNumberOfPlayers()>=2){
                        ct.setNumberOfPlayers(ct.getNumberOfPlayers()-1);
                        ct.setCorrect_end(false);
                        //aggiorno poi le tabelle
                        Room.child(ct.getId()).setValue(ct);
                        Accounts.child(uID).child("match_found").setValue(false);
                    }
                    else
                        //se il giocatore è da solo
                    if(ct.getNumberOfPlayers()<2)
                    {
                        //cancello il figlio dalla tabella matchmaking
                        Room.child(ct.getId()).removeValue();
                        Accounts.child(uID).child("match_found").setValue(false);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                //se poi la partita era già cominciata, cancello il timer per evitare errori
                if(roomcreated)
                timer1.cancel();
                //chiudo l'activity
                this.finish();
            }
        }
    

    我希望这会对你有所帮助:D 如果你有任何问题,我会回答你:D

    【讨论】:

    • 感谢您为我安排这些,它帮助我自己思考了一些事情。我一直在尝试通过 onDataChange() 更新 ArrayList,但我遇到了一些奇怪的问题。如果您不介意您可以稍后发布该代码以便我查看它吗?很好的答案,但谢谢!
    • 嘿,刚刚再次检查这个问题。
    • @brentB 如果您有任何问题,请通过电子邮件与我联系:riccardo.fassina98@gmail.com:D 我很乐意为您提供帮助:D
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-30
    • 2021-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-24
    相关资源
    最近更新 更多