Search code examples
javaandroidarraylistrequestbackendless

User properties, random object without concord .. Why doesn't works? Why doesn't get 21 objects?


I have a complex problem, what I don't understand. In this class I would like to
add 21 random objects from one arraylist listChallenges to the arraylist finalChallenges. However it doesn't work , sometimes finalChallanges contains 21 objects , but most of the times it contains less objects, but I don't know where is the problem. Actually, I tried to comment every step, and if did something wrong, please tell me. Please help me, I have no idea what shoud I do..

 ArrayList<Challenges>          listChallenges  = new ArrayList<Challenges>();
 ArrayList<Challenges>          finalChallenges = new ArrayList<Challenges>(20);

//Check where the same userId and subscribers.objectId,
    //Request these categories object and save to the  ArrayList<Category> totalCategories
    //Save these categories objectId to the selectedCategoriesId List<String>
    BackendlessDataQuery query = new BackendlessDataQuery();
    query.setWhereClause( "subscribers.objectId = '"+backendlessUser.getObjectId()+"'");

    Backendless.Data.of(Category.class).find(query, new AsyncCallback<BackendlessCollection<Category>>() {
        @Override
        public void handleResponse(BackendlessCollection<Category> categoriesBackendlessCollection) {
            //add selected categories to totalActivities Category ArrayList
            for( Category categories : categoriesBackendlessCollection.getData()) {
                totalCategories.add(categories);
                selectedCategoriesId.add(categories.getObjectId());
               //
            }
            System.out.println(selectedCategoriesId);

            //For cycle is going to selectedCategoriesId.size
            //Check where the same category-objectId and actual selectedCategoriesId
            //Request these challenges object, which are in the actual category and save to the  ArrayList<Challenges> listChallenges
            //Save these categories objectId to the selectedCategoriesId List<String>
            for(int k=0;k<selectedCategoriesId.size();k++) {

                BackendlessDataQuery query = new BackendlessDataQuery();
                query.setPageSize(pageSize);
                query.setWhereClause("category.objectId = '" + selectedCategoriesId.get(k) + "'");

                Backendless.Data.of(Challenges.class).find(query, new AsyncCallback<BackendlessCollection<Challenges>>() {
                    @Override
                    public void handleResponse(BackendlessCollection<Challenges> cha) {
                        for (Challenges challenges : cha.getData()) {
                            listChallenges.add(challenges);

                            challengeTitle.add(challenges.getChallengeTitle());
                            challengeContent.add(challenges.getChallengeContent());
                            challangeId.add(challenges.getObjectId());
                        }
                        System.out.println("osszes elem:"+listChallenges);
                        //ArrayList<Challenges> finalChallenges  size is 21 with 0
                        //  get from listChallenges random 21 object without concord and add to the finalChallenges
                        Random random = new Random();
                        List<Challenges> temp = new ArrayList<>(listChallenges);
                        ArrayList<Challenges> tempNewList = new ArrayList<Challenges>();
                        //ArrayList<Challenges> temp = new ArrayList<Challenges>(listChallenges.size());
                        for (Challenges item : listChallenges) temp.add(item);
                        while (finalChallenges.size()<21 && temp.size()>0) {
                               int index = random.nextInt(temp.size());
                               tempNewList.add(temp.get(index));
                               temp.remove(index);
                            finalChallenges= tempNewList;
                        }

                       // System.out.println("kihívások");
                        System.out.println(finalChallenges);
                        System.out.println(finalChallenges.size());

                       // title.setText(challengeTitle.get(0));
                       // content.setText(challengeContent.get(0));
                       // objectId = challangeId.get(0);

                    }

                    @Override
                    public void handleFault(BackendlessFault fault) {

                    }
                });

                //save finalChallenges array objects to the current user "userChallenges" relationship
                Backendless.UserService.login( email, password, new AsyncCallback<BackendlessUser>() {
                    @Override
                    public void handleResponse(BackendlessUser backendlessUser) {

                        backendlessUser.setProperty("userChallenges",new ArrayList<>(finalChallenges));


                            }
                        });

                        Backendless.UserService.update(backendlessUser, new BackendlessCallback<BackendlessUser>() {
                            @Override
                            public void handleResponse(BackendlessUser response) {
                                System.out.println( "User has been updated" );
                            }

                            @Override
                            public void handleFault(BackendlessFault fault) {
                                System.out.println( "User has not been updated");
                            }
                        });

                    }

                    @Override
                    public void handleFault(BackendlessFault backendlessFault) {
                        System.out.println( "Server reported an error - " + backendlessFault.getMessage() );
                    }
                },true);
            }


        }

        @Override
        public void handleFault(BackendlessFault fault) {

        }
    });

Solution

  • You don't show where finalChallenges is initialized, and we can see it is overwritten asynchronously in response handlers: it is very likely an issue of concurrent access.

    The logic itself where you fill the list from random elements of another list would be correct, if the instance of finalChallenges was not "shared" across different/concurrent executions of that handler.

    Also, a small tip: to create your temp list in one go without loop you can do this: List<Challenge> temp = new ArrayList<>(listChallenges);

    Edit: 2 suggestions.

    1. Use a temporary list in your loop when you fill it, then swap the lists atomically (listChallenges = tempNewList)
    2. When you pass your list to user properties, pass a copy (backendlessUser.setProperty("userChallenges", new ArrayList<>(finalChallenges));)