在基本适配器中滚动后,TextView 值更改回之前的值

Posted

技术标签:

【中文标题】在基本适配器中滚动后,TextView 值更改回之前的值【英文标题】:TextView value changes back to previous value after scroll in base adapter 【发布时间】:2017-04-11 23:08:41 【问题描述】:

我一直在研究这个问题,但找不到解决方案。关于我的自定义列表视图的一切似乎都正确执行。当我单击holder.feedUpVoteButton 时,文本会正确更改+=1。但是,当我向下滚动并向上滚动时,文本值将恢复为单击之前的值。

我拒绝使用notifyDatasetChanged,因为我没有添加任何内容或从列表中删除任何内容。

public class CustomFeedListViewAdapter extends BaseAdapter

    CustomFeedListViewAdapter customFeedListViewAdapter;
    Date createdAt, currentDate; int num;
    static HashMap<String, String> oneData = new HashMap<String, String>();
    HashMap<String, String> iFeed = new HashMap<>();


    private String likesString;

    String upVoteClicked, downVoteClicked;
    HashMap<String, String> mFeed = new HashMap<>();
    List<ParseObject>  mObjects;

    private ParseObject parseObFeed;

        CustomFeedListViewAdapter(Context context, ArrayList<HashMap<String, String>> data) 

        super();
        this.mContext = context;
        GlobalFeedTab.arrayFeedList = data;
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    


    @Override
    public int getCount() 
        return GlobalFeedTab.arrayFeedList.size();
    

    @Override
    public Object getItem(int i) 
        return GlobalFeedTab.arrayFeedList.get(i);
    

    @Override
    public long getItemId(int i) 
        return i;
    

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) 

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

       final ViewHolder holder;

        if (view == null) 

            position = i;

            view = inflater.inflate(R.layout.feed_list_row, viewGroup, false);

            holder = new ViewHolder();


            holder.feedNumOfLikes = (TextView) view.findViewById(R.id.feedNumofLikes);
            holder.feedUpVoteButton = (Button) view.findViewById(R.id.feedUpVoteButton);



         else 
            position = i;
            holder = (ViewHolder) view.getTag();
        


        mFeed = GlobalFeedTab.arrayFeedList.get(position);

        holder.feedNumOfLikes.setText(mFeed.get("likes"));

        likesString = mFeed.get("likes");
        likes[position] = Integer.valueOf(likesString);

        holder.feedUpVoteButton.setTag(position);

        ParseQuery<ParseObject> query2 = new ParseQuery<ParseObject>("FeedItem");
        query2.setLimit(250);
        query2.addDescendingOrder("createdAt");

        query2.findInBackground(new FindCallback<ParseObject>() 
            @Override
            public void done(final List<ParseObject> objects, ParseException e) 

                if (e == null) 

                    for ( final ParseObject object : objects) 



                        holder.feedUpVoteButton.setOnClickListener(new View.OnClickListener() 
                            @Override
                            public void onClick(View v) 

                                int pos = (Integer) v.getTag();
                                parseObFeed = objects.get(pos);
                                username = parseObFeed.getString("username");
                                createdAt = parseObFeed.getDate("createdAt");

                                likes[pos] += 1;                           
                                parseObFeed.put("likes", likes[pos]);
                                holder.feedNumOfLikes.setText(String.valueOf(parseObFeed.getInt("likes")));

                                parseObFeed.put(ParseUser.getCurrentUser().getUsername() + "upvoteClicked", true);

                                parseObFeed.saveInBackground();
                            
                        );                

            
        );


        return view;
    


    private class ViewHolder 

        ImageView feedProfilePic;
        TextView feedUsername;
        TextView feedNumOfLikes;
        TextView feedFeedItem;
        TextView feedDate;
        TextView feedNumofReplies;
        Button feedUpVoteButton;
        Button feedDownVoteButton;
        Button feedCommentButton;
        ListView feedListView;

    


【问题讨论】:

该链接给了我指导,但是,我仍然对如何使用 BaseAdapter 来实现这一点感到困惑。你能提供一个答案@ArpanSharma 【参考方案1】:

实际上这就是整个理论。当您增加一个值时。您必须从您获取数据的列表中增加该值。因为当您向下滚动时,上面的行将丢失。当您向后滚动时向上,列表将从列表值中再次加载。所以你所要做的就是增加列表中的值,即GlobalFeedTab.arrayFeedList this 链接可获取更多详细信息,适用于任何寻求更多详细信息的人 当你写这行时

likes[pos] += 1;

您还必须增加您的 arraylist(mFeed) 中的值,然后编写 notifyDataSetChanged();

【讨论】:

您能在答案中提供代码吗?我仍然对如何做到这一点感到困惑。 如何增加数组列表中的值以及在哪里?请给我一个完整的答案。 不需要发布代码来解决我在问题中的问题。我只是复制、剪切和粘贴要放置在getView() if(e == null) //here 中的查询【参考方案2】:

每次调用getView,你都会重新制作

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

当您滚动并且您单击的行离开并重新进入显示时,这不会保存。持有者可以持有这个整数值。

private class ViewHolder 
    int likes;
    TextView feedNumOfLikes; 

并相应地更新它

holder.feedUpVoteButton
    .setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 

            holder.feedNumOfLikes.setText(String.valueOf(++holder.likes));

但是,您还需要更新解析对象。

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

我拒绝使用notifyDatasetChanged,因为我没有添加任何内容或从列表中删除任何内容。

不过,您正在修改数据。调用它将使您的适配器数据与存储在 Parse Server 中的数据一致。


编辑

这变得很复杂,因为您让每个“行”都有一些与之关联的“嵌套”对象列表。我想您可以将整个列表存储在持有人中。

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; 

在适配器内部时,您调用 Parse 来获取适配器中每个项目的二级列表,但您只需将其存储在持有人中。当 query2 返回时,不要对它做任何其他事情。

您真正的问题是不清楚query2 甚至返回了什么。当然,这是一些数据列表,但您真的想在列表中显示列表吗?此外,适配器的每个项目都从 Parse 查询完全相同的数据。我认为您需要一个过滤器...然后,您的position 变量在GlobalFeedTab.arrayFeedListList&lt;ParseObject&gt; 之间不对应,因为它们是不同的列表。

这里只是我可以指出的一些 cmets。

    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();
        
    );    

我不记得 saveInBackground 是否有回调,但这可能需要调查

【讨论】:

这看起来很详细。我迫不及待想在几分钟内尝试! @cricket_007 警告:它可能不起作用。只是抛出我看到的第一个问题。 @espa_network 另外,我认为您不需要在for ( final ParseObject object : objects) 上循环,因为您在onClick 中直接使用objects.get(pos)。您在任何时候都不会使用您正在循环播放的object 我在没有notifyDataSetChanged(); 的情况下尝试了您的建议,但没有成功。然后我用notifyDataSetChanged();试了一下,还是不行。 notifyDataSetChanged(); 导致按钮的行为就像被禁用一样。 @cricket_007 我修好了!我能够 1)让 textView 在滚动后更改它的值并且不使用 NotifyDataSetChanged(); 和 2)我能够使用 ParseQuery 一次只能查询 1 个项目。感谢您的所有帮助。我将在明天早上发布代码作为答案。 @cricket_007【参考方案3】:

经过不断的试错。我终于想出了如何在滚动后更改文本视图。我的问题是我得到了错误的ParseObject 值。我的主要活动包含ParseQuery,我从Hashmap(); 获得likes 但是,由于某种原因,我无法直接传递喜欢的值,所以我传递了 ParseObject 本身。因此,在我的BaseAdapter 类中不需要查询。然后,我在GetView(); 中实现了这些代码行来回答我原来的问题:

   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);

    

【讨论】:

很高兴你知道了。你可以使用else 而不是“else if not”

以上是关于在基本适配器中滚动后,TextView 值更改回之前的值的主要内容,如果未能解决你的问题,请参考以下文章

向上滚动时,Textview 重置为旧值

动态更改 ListView 中的 TextView 字体颜色

滚动后未选中 ListView 适配器中的 Android 复选框

在 ListView 适配器的 getView(...) 中更改 TextView 颜色和文本

用户交互后如何根据 RecyclerView 适配器内部服务器的响应更新 TextView?

使用 Fragment 内的方法更改 TextView 值 (NullPointerException)