TextView value changes back to previous value after scroll in base adapter

后端 未结 3 543
深忆病人
深忆病人 2021-01-27 02:58

I\'ve been researching this forever and can\'t find a solution. Everything about my custom list view seems to perform correctly. When I click on the holder.feedUpVoteButto

相关标签:
3条回答
  • 2021-01-27 03:10

    Every single time getView is called, you re-make

    likes = new int[GlobalFeedTab.arrayFeedList.size()];
    

    This is not saved as you scroll and the row you clicked leaves and re-enters the display. The holder could hold this integer value.

    private class ViewHolder {
        int likes;
        TextView feedNumOfLikes; 
    }
    

    And update it accordingly

    holder.feedUpVoteButton
        .setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
    
                holder.feedNumOfLikes.setText(String.valueOf(++holder.likes));
    

    However, you need to also update the parse object.

    parseObFeed.put("likes", holder.likes);
    parseObFeed.saveInBackground();
    // notifyDataSetChanged(); // Up to you. Might not work without
    

    I refuse to use notifyDatasetChanged because I am not adding anything or removing anything from the list.

    You are modifying the data, though. Calling it will make your adapter data consistent with what is stored in your Parse Server.


    Edit

    This gets complicated because you are making each "row" have some "nested" list of objects that are associated with it. I suppose you could store that entire list in the holder.

    private class ViewHolder {
        // Java variables to hold onto
        int likes;
        List<ParseObject> feedItems = new ArrayList<ParseObject>();
    
        // Android views to bind those values to
        TextView feedNumOfLikes; 
    }
    

    When inside the adapter, you call Parse to get this secondary list for each item in your adapter, but you only need to store that within the holder. Don't do anything else with it when the query2 returns .

    Your real issue here is that is unclear what query2 is even returning. It's some list of data, sure, but are you actually wanting to display a List within a List? Also, each item of the adapter is querying the exact same data from Parse. I think you need a filter... Then, your position variable doesn't correspond between GlobalFeedTab.arrayFeedList and the List<ParseObject>, because those are different lists.

    Here's just some comments that I can point out.

        else {
            holder = (ViewHolder) view.getTag();
        }
    
        // You don't need 'position', it is just the 'i' value...
        mFeed = GlobalFeedTab.arrayFeedList.get(i);
    
        // This is stored in the Activity, I guess? 
        likesString = mFeed.get("likes");
        holder.feedNumOfLikes.setText(likesString);
    
        holder.feedUpVoteButton.setTag(i);
    
        ParseQuery<ParseObject> query2 = new ParseQuery<ParseObject>("FeedItem");
    
        // This is getting some related "FeedItem" for the current row
        // Just store the info, don't do anything with it yet
        query2.findInBackground(new FindCallback<ParseObject>() {
            @Override
            public void done(final List<ParseObject> objects, ParseException e) {
                if (e == null) {
                    holder.feedItems.clear();
                    holder.feedItems.addAll(objects);
                    notifyDataSetChanged();
                }
            } 
        };
    
        // Here, you can setup the button for the current row
        holder.feedUpVoteButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
    
                int pos = (Integer) v.getTag();
    
                // This is wrong... 'pos' is the position of the adapter! Not the index of List<ParseObject> results from earlier
                // And this is a very clear ArrayIndexOutOfBounds error...
                // The adapter could be shorter/longer than the holder.feedItems
                parseObFeed = holder.feedItems.get(pos);
    
                // !! TODO: Figure out which parseObFeed you actually want to use here 
    
                username = parseObFeed.getString("username");
                createdAt = parseObFeed.getDate("createdAt");
    
                holder.likes++;
                parseObFeed.put("likes", holder.likes);
    
                // This is the value that "resets" when you scroll. 
                // parseObFeed has not yet been saved, so when you scroll, the data isn't changed. 
                holder.feedNumOfLikes
                     .setText(String.valueOf(parseObFeed.getInt("likes")));
    
                // Not really sure what this does - You can store an array of likes rather than one field per username
                parseObFeed.put(ParseUser.getCurrentUser().getUsername() + "upvoteClicked", true);
    
                parseObFeed.saveInBackground();
                notifyDataSetChanged();
            }
        });    
    }
    

    I can't remember if saveInBackground has a callback, but that might be something to look into

    0 讨论(0)
  • 2021-01-27 03:15

    Actually that is the whole theory.When you increment a value.You have to increment that value in the list from where you are fetching the data.Because when you scroll down,the upper rows will be lost.When you scroll back up,list will be loaded again from the list values.So all you have to do is to increment the value in the list too i.e GlobalFeedTab.arrayFeedList this link is for further detail,for anyone looking for some more detail When you write this line

    likes[pos] += 1;
    

    You will also have to increment the value in the arraylist(mFeed) of yours and then write notifyDataSetChanged();

    0 讨论(0)
  • 2021-01-27 03:29

    After continuous trial and error. I finally figured out how to change a textview after it scrolls. My problem was I was getting the wrong ParseObject value. My main activity contains a ParseQuery and I was getting the likesfrom a Hashmap(); However, for some reason I couldn't pass the value of likes directly so I passed the ParseObject itself. Therefore, needing no query in my BaseAdapter Class. Then, I implemented these lines of code in GetView(); to answer my original question:

       holder.upvote[position] =  holder.parseObList[position].getBoolean(ParseUser.getCurrentUser().getUsername() + "upvoteClicked");
        holder.downvote[position] =  holder.parseObList[position].getBoolean(ParseUser.getCurrentUser().getUsername() + "downvoteClicked");
    
        if(holder.upvote[position]  ){
            holder.feedUpVoteButton.setBackgroundResource(R.drawable.arrowclicked);
            holder.feedNumOfLikes.setText(String.valueOf(holder.likes[position]));
    
        }
        else if(!holder.upvote[position]){
            holder.feedUpVoteButton.setBackgroundResource(R.drawable.arrowunclicked);
            holder.feedNumOfLikes.setText(String.valueOf(holder.likes[position]));
    
    
        }
        if(holder.downvote[position]){
            holder.feedDownVoteButton.setBackgroundResource(R.drawable.arrowclicked);
    
        }
        else if(!holder.downvote[position]){
            holder.feedDownVoteButton.setBackgroundResource(R.drawable.arrowunclicked);
    
        }
    
    0 讨论(0)
提交回复
热议问题