美文网首页
由NotifyDateSetChanged无法生效产生的思考

由NotifyDateSetChanged无法生效产生的思考

作者: Rreply | 来源:发表于2018-07-22 01:02 被阅读12次

    最近在使用notifyDataSetChanged方法时,发现数据并没有按照想象中的刷新,经过查看文档以及搜索,得知了产生这种现象的原因。

     if (mCountDownAdapter == null) {
                mCountDowns = LitePal.findAll(CountDown.class);
                mCountDownAdapter = new CountDownAdapter(mCountDowns);
                mRecyclerView.setAdapter(mCountDownAdapter);
            } 
    

    首先Litepal.findAll方法最终调用了如下onFindAll方法

    public <T> List<T> onFindAll(Class<T> modelClass, boolean isEager, long... ids) {
            List<T> dataList;
            if (isAffectAllLines(ids)) {
                dataList = query(modelClass, null, null, null, null, null, "id", null,
                        getForeignKeyAssociations(modelClass.getName(), isEager));
            } else {
                dataList = query(modelClass, null, getWhereOfIdsWithOr(ids), null, null, null, "id",
                        null, getForeignKeyAssociations(modelClass.getName(), isEager));
            }
            return dataList;
        }
    

    可以看出Litepal.findAll最终返回的List是根据查询的数据添加到List中返回的,也就是说如果数据库发生了变化,那么这个List是不会变化的。这就为我们理解RecycleView为什么不能正确刷新打下了基础。

    mCountDownAdapter = new CountDownAdapter(mCountDowns);
    

    在这里,Adapter是和mCountDowns连接起来的,mCountdowns就是返回的List。因此在Adapter没有重建的时候,它绑定的都是mCountdowns列表。
    在用户输入数据的时候,我是进行下面处理的:

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    mCountDown.setName(s.toString());
                    mCountDown.save();    //将CountDown实例产生的变化存储到数据库中
                }
    

    因此,我处理数据变化是方式是直接在数据库中进行修改,而与Adapter绑定的List却不会发生变化。所以Adapter调用NotifyDateSetChanged的时候就不会刷新数据了,因为其绑定的List数据没有刷新。
    因此,有两个方法可以解决这个问题,一种是在修改数据到数据库的同时,对Adapter相关联的List也进行修改。一种是将关联的List重新清空,获取数据。从对性能的损失上来看,第一种方法较好。
    有时候修改的只是一个item中的数据,而调用NotifyDateSetChanged的时候确实把全部可见项的数据都刷新了,造成了不必要的性能损失。
    使用NotifyItemChanged(int position)方法就能够很好地避免这种损失,可以创建一个全局变量来储存点击的位置。

            @Override
            public void onClick(View v) {
                int countdown_id = mCountDown.getId();
                Intent intent = DetailActivity.newIntent(getActivity(), countdown_id);
                startActivity(intent);
                position = getAdapterPosition();   //获取该位置
            }
    

    然而到这里还不算完成,NotifyItemChanged(int position)方法刷新的是这个item中所有的View,不管其有没有被修改。这就导致一个问题,如果这个item中存在很多耗时的动画图片等,刷新这些view就会耗费大量的时间。
    举个例子,我刷微博的时候,看到一个博主发的gif太搞笑了,点了一个赞,如果整个item都刷新的话,这个gif也要重新刷新,这就太浪费时间了。
    因此使用notifyItemChanged(int position, Object payloads)方法,首先需要重写如下方法

            @Override
            public void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) {
                  //因为payloads为空时,默认刷新item中全部的view,所以需要这样写
                if(!payloads.isEmpty()) {
                    if (payloads.get(0) instanceof Integer) {
                        holder.tvScore.setText(String.valueOf((Integer)payloads.get(0)))
                    }
                }else {
                    super.onBindViewHolder(holder,position, payloads);
                }
            }
    

    最后在需要刷新数据的时候调用notifyItemChanged(int position, Object payloads)就行了。

    相关文章

      网友评论

          本文标题:由NotifyDateSetChanged无法生效产生的思考

          本文链接:https://www.haomeiwen.com/subject/shihmftx.html