RecycleView包的DiffUtil+AsyncListDiffer工具类详解

一.DiffUtil工具类简介

 

1.说明

DiffUtil工具类是RecyclerView包中提供的一个工具类。

 

 

2.源码解释

英文

DiffUtil is a utility class that calculates the difference

between two lists and outputs a list of update operations that converts the first list into the second one.

翻译

DiffUtil是一个实用程序类,用于计算两个列表之间的差异,并输出将第一个列表转换为第二个列表的更新操作列表。

 

 

3.源码时间耗时说明

<li>100 items and 10 modifications: avg: 0.39 ms, median: 0.35 ms

<li>100 items and 100 modifications: 3.82 ms, median: 3.75 ms

<li>100 items and 100 modifications without moves: 2.09 ms, median: 2.06 ms

<li>1000 items and 50 modifications: avg: 4.67 ms, median: 4.59 ms

<li>1000 items and 50 modifications without moves: avg: 3.59 ms, median: 3.50 ms

<li>1000 items and 200 modifications: 27.07 ms, median: 26.92 ms

<li>1000 items and 200 modifications without moves: 13.54 ms, median: 13.36 ms

可以看出DiffUtil工具类的性能还是非常不错的。

 

 

 

 

 

 

 

 

二.DiffUtil工具类使用

Activity

public class RecyclerViewUpdateActivity extends AppCompatActivity {

    private SwipeRefreshLayout mSwipeRefreshLayout;
    private RecyclerView mRecyclerView;
    private RecycleViewUpdateAdapter mRecycleViewAdapter;
    private List<RecyclerViewBean> mList;
    private int mCount = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recyclerview);
        initView();
    }

    /**
     * 初始化各种View
     */

    private void initView() {
        mSwipeRefreshLayout = findViewById(R.id.activity_recyclerview_srl);
        initSwipeRefreshLayout();
        mRecyclerView = findViewById(R.id.activity_recyclerview_recyclerView);
        mList = getList();
        //1.设置LinearLayoutManager ListView
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        //2.设置固定大小
        mRecyclerView.setHasFixedSize(true);
        //3.设置Adapter
        mRecycleViewAdapter = new RecycleViewUpdateAdapter(this, mList);
        mRecyclerView.setAdapter(mRecycleViewAdapter);
        //4.RecyclerView点击事件
        onRecyclerViewClick();
    }

    /**
     * 初始化SwipeRefreshLayout
     */

    private void initSwipeRefreshLayout() {
        //设置进度View的组合颜色,在手指上下滑时使用第一个颜色,在刷新中,会一个个颜色进行切换
        mSwipeRefreshLayout.setColorSchemeColors(Color.parseColor("#6200EE"), Color.parseColor("#3700B3"), Color.parseColor("#03DAC5"), Color.YELLOW, Color.BLUE);
        //下拉刷新
        mSwipeRefreshLayout.setOnRefreshListener(() -> {
            //模拟6秒刷新时间
            Handler handler = new Handler(Looper.getMainLooper());
            handler.postDelayed(() -> {
                RecyclerViewUpdateActivity.this.runOnUiThread(() -> {
                    List<RecyclerViewBean> oldList = mRecycleViewAdapter.getData();
//                    mList = getUpdateList();//数据变化
                    mList = getList();//数据不变

                    mRecycleViewAdapter.updateData(oldList, mList);//DiffUtil差量刷新 同步
                });
                mSwipeRefreshLayout.setRefreshing(false);//结束刷新
            }, 6000);
        });
    }

    /**
     * RecyclerView点击事件
     */

    private void onRecyclerViewClick() {
        mRecycleViewAdapter.setRecyclerViewItemClick(new IRecyclerViewItemClick() {
            @Override
            public void onItemClick(View view, int position) {
                Log.d("DiffUtilCallBack", "RecyclerView点击 position----:" + position);
                Log.d("DiffUtilCallBack", "RecyclerView点击 title----:" + mList.get(position).getTitle());
            }

            @Override
            public void onItemLongClick(View view, int position) {
                Log.d("DiffUtilCallBack", "RecyclerView长按 position----:" + position);
                Log.d("DiffUtilCallBack", "RecyclerView长按 title----:" + mList.get(position).getTitle());
            }
        });
    }


    /**
     * 初始化 默认集合数据
     */

    private List<RecyclerViewBean> getList() {

        List<RecyclerViewBean> list = new ArrayList<>();

        RecyclerViewBean listViewBean1 = new RecyclerViewBean();
        listViewBean1.setAva("http://sss");
        listViewBean1.setTitle("张三");

        RecyclerViewBean listViewBean2 = new RecyclerViewBean();
        listViewBean2.setAva("http://sss");
        listViewBean2.setTitle("韦德");

        RecyclerViewBean listViewBean3 = new RecyclerViewBean();
        listViewBean3.setAva("http://sss");
        listViewBean3.setTitle("保罗");

        for (int i = 0; i < 10; i++) {
            list.add(listViewBean1);
            list.add(listViewBean2);
            list.add(listViewBean3);
        }

        return list;
    }

    /**
     * 初始化 刷新集合数据
     */

    private List<RecyclerViewBean> getUpdateList() {

        mCount++;

        List<RecyclerViewBean> list = new ArrayList<>();

        //更新头像和标题
        RecyclerViewBean listViewBean1 = new RecyclerViewBean();
        listViewBean1.setAva("https://avatar.csdnimg.cn/1/2/4/3_weixin_37730482_1607556601.jpg");
        listViewBean1.setTitle("张三_刷新" + mCount);

        RecyclerViewBean listViewBean2 = new RecyclerViewBean();
        listViewBean2.setAva("http://sss");
        listViewBean2.setTitle("韦德");

        RecyclerViewBean listViewBean3 = new RecyclerViewBean();
        listViewBean3.setAva("http://sss");
        listViewBean3.setTitle("保罗");

        for (int i = 0; i < 10; i++) {
            list.add(listViewBean1);
            list.add(listViewBean2);
            list.add(listViewBean3);
        }

        return list;
    }
}

 

Adapter

public class RecycleViewUpdateAdapter extends RecyclerView.Adapter<RecycleViewUpdateAdapter.ViewHolder> {

    private IRecyclerViewItemClick mClick;

    public void setRecyclerViewItemClick(IRecyclerViewItemClick click) {
        mClick = click;
    }

    private List<RecyclerViewBean> mList;
    private LayoutInflater mInflater;
    private Context mContext;

    public RecycleViewUpdateAdapter(Context context, List<RecyclerViewBean> list) {
        mContext = context;
        mList = list;
        mInflater = LayoutInflater.from(context);
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.recyclerview_item, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.textView.setText(mList.get(position).getTitle());
        Glide.with(mContext).load(mList.get(position).getAva()).error(R.color.colorPrimary).into(holder.imageView);

        //Item点击事件
        holder.itemView.setOnClickListener(v -> {
            if (null != mClick) {
                mClick.onItemClick(v, position);
            }
        });

        //Item长按事件
        holder.itemView.setOnLongClickListener(v -> {
            if (null != mClick) {
                mClick.onItemLongClick(v, position);
            }
            return true;
        });

        Log.d("DiffUtilCallBack", "两个个参数的onBindViewHolder方法 position----:" + position);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull List<Object> payloads) {
        super.onBindViewHolder(holder, position, payloads);
        if (payloads.isEmpty()) {//如果payloads集合为空 则执行两个参数的普通的onBindViewHolder方法
            onBindViewHolder(holder, position);
        } else {//如果payloads集合不为空 仅仅更新Item的某个控件
            Bundle bundle = (Bundle) payloads.get(0);
            if (null == bundle) return;
            String ava = bundle.getString("KEY_AVA");
            String title = bundle.getString("KEY_TITLE");
            holder.textView.setText(title);
            if (!TextUtils.isEmpty(ava)) {
                Glide.with(mContext).load(ava).into(holder.imageView);
            }
            Log.d("DiffUtilCallBack", "三个参数的onBindViewHolder方法 ava----:" + ava);
            Log.d("DiffUtilCallBack", "三个参数的onBindViewHolder方法 title----:" + title);
        }
    }

    @Override
    public int getItemCount() {
        return mList.size();
    }

    /**
     * ViewHolder类
     */

    static class ViewHolder extends RecyclerView.ViewHolder {

        private ImageView imageView;
        private TextView textView;

        public ViewHolder(View itemView) {
            super(itemView);
            imageView = itemView.findViewById(R.id.recyclerview_item_imageview);
            textView = itemView.findViewById(R.id.recyclerview_item_textview);
        }
    }

    /**
     * 刷新数据 原始全量刷新
     */

    public void updateData(List<RecyclerViewBean> list) {
        if (null == list || list.size() == 0) return;
        mList = list;
        notifyDataSetChanged();
    }

    /**
     * 刷新数据 DiffUtil差量刷新 同步
     */

    public void updateData(List<RecyclerViewBean> oldList, List<RecyclerViewBean> newList) {
        if (null == oldList || null == newList) return;

        //1.获取DiffResult对象
        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtilCallBack(oldList, newList));
        //2.更新集合数据
        mList = newList;
        //3.使用DiffResult对象的dispatchUpdatesTo方法Adapter热更新
        diffResult.dispatchUpdatesTo(this);
    }

    /**
     * 获取Adapter中最新的集合数据
     */

    public List<RecyclerViewBean> getData() {
        return mList;
    }

}

 


DiffUtil.Callback实现类

public class DiffUtilCallBack extends DiffUtil.Callback {

    private List<RecyclerViewBean> mOldList;
    private List<RecyclerViewBean> mNewList;

    public DiffUtilCallBack(List<RecyclerViewBean> oldList, List<RecyclerViewBean> newList) {
        mOldList = oldList;
        mNewList = newList;
    }

    /**
     * 获取旧集合数据量大小
     */

    @Override
    public int getOldListSize() {
        return null == mOldList ? 0 : mOldList.size();
    }

    /**
     * 获取新集合数据量大小
     */

    @Override
    public int getNewListSize() {
        return null == mNewList ? 0 : mNewList.size();
    }

    /**
     * 是否是相同的Item 返回值操作 根据具体情况 一般不操作ItemViewType 此方法返回true即可
     */

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return true;
    }

    /**
     * 是否是相同的Contents
     */

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        return (mOldList.get(oldItemPosition).getTitle()).equals(mNewList.get(newItemPosition).getTitle());
    }

    /**
     * 更新Item的某一个控件View
     */

    @Nullable
    @Override
    public Object getChangePayload(int oldItemPosition, int newItemPosition) {
        Bundle payload = new Bundle();

        //头像是否更新
        if (!mOldList.get(oldItemPosition).getAva().equals(mNewList.get(newItemPosition).getAva())) {
            payload.putString("KEY_AVA", mNewList.get(newItemPosition).getAva());
        }

        //标题是否更新
        if (!mOldList.get(oldItemPosition).getTitle().equals(mNewList.get(newItemPosition).getTitle())) {
            payload.putString("KEY_TITLE", mNewList.get(newItemPosition).getTitle());
        }

        if (payload.size() == 0) {//如果没有变化 就传空
            return null;
        }

        //更新Item的某个控件View
        return payload;
    }
}

刷新时,由于模拟刷新前和刷新后的数据一样。刷新时onBindViewHolder方法没有执行

 

那么,如果刷新前和刷新后的数据不一样呢?我们测试一下。

 

修改数据,即刷新前和刷新后的数据不一样

mList = getUpdateList();//数据变化

 

刷新时,由于模拟刷新前和刷新后的数据每次都不一样。每次刷新时onBindViewHolder方法都会执行。

D/DiffUtilCallBack: onBindViewHolder position----:6

D/DiffUtilCallBack: onBindViewHolder position----:7

D/DiffUtilCallBack: onBindViewHolder position----:0

D/DiffUtilCallBack: onBindViewHolder position----:3




D/DiffUtilCallBack: onBindViewHolder position----:6

D/DiffUtilCallBack: onBindViewHolder position----:0

D/DiffUtilCallBack: onBindViewHolder position----:3




D/DiffUtilCallBack: onBindViewHolder position----:6

D/DiffUtilCallBack: onBindViewHolder position----:0

D/DiffUtilCallBack: onBindViewHolder position----:3




.........

 

 

总结

<1> DiffUtil类,提前给我们比较了刷新前后的集合变化防止了全量刷新的操作。但是如果集合数据较大时,比较集合差异也是比较耗时的。因为涉及算法计算。因此 Google给我们提供了异步的DiffUtil 即DiffUtil。下面讲解AsyncListDiff的使用。

<2> DiffUtil.Callback类还有一个普通的getChangePayload方法,因为此方法是普通的方法,所以可以不重写。只是在需要的时候重写 比如更新Item的某个控件View。这个方法的返回值会在三个参数的onBindViewHolder方法回调。详情请看代码。

<3> 上述只为测试,正常情况下刷新后需要把刷新出来的数据复制给原有的集合,这样才是正常的流程。这里为了测试老集合一直用的都是老的数据集合

 

 

 

 

 

 

三.AsyncListDiff工具类简介

 

1.说明

AsyncListDiff工具类是RecyclerView包中提供的一个工具类。主要用来替换DiffUtil。在子线程中操作比较集合变化。然后主线程更新UI。

 

 

2.源码解释

英文

Helper for computing the difference between two lists via  on a background thread. 

It can be connected to a {@link RecyclerView.Adapter RecyclerView.Adapter}, and will signal the adapter of changes between sumbitted lists.

 

翻译

帮助通过后台线程计算两个列表之间的差异。


它可以连接到{@link RecyclerView。适配器RecyclerView。},并将在提交列表之间的更改通知适配器。

 

 

 

 

 

 

 

四.AsyncListDiff工具类使用

 

Activity

public class RecyclerViewAsyncUpdateActivity extends AppCompatActivity {

    private SwipeRefreshLayout mSwipeRefreshLayout;
    private RecyclerView mRecyclerView;
    private RecycleViewAsyncUpdateAdapter mRecycleViewAdapter;
    private List<RecyclerViewBean> mList;
    private int mCount = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recyclerview);
        initView();
    }

    /**
     * 初始化各种View
     */

    private void initView() {
        mSwipeRefreshLayout = findViewById(R.id.activity_recyclerview_srl);
        initSwipeRefreshLayout();
        mRecyclerView = findViewById(R.id.activity_recyclerview_recyclerView);
        mList = getList();
        //1.设置LinearLayoutManager ListView
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        //2.设置固定大小
        mRecyclerView.setHasFixedSize(true);
        //3.设置Adapter
        mRecycleViewAdapter = new RecycleViewAsyncUpdateAdapter(this);
        mRecyclerView.setAdapter(mRecycleViewAdapter);
        mRecycleViewAdapter.submitList(mList);//AsyncListDiffer差量刷新 异步 初始化也要用这种方式添加数据
        //4.RecyclerView点击事件
        onRecyclerViewClick();
    }

    /**
     * 初始化SwipeRefreshLayout
     */

    private void initSwipeRefreshLayout() {
        //设置进度View的组合颜色,在手指上下滑时使用第一个颜色,在刷新中,会一个个颜色进行切换
        mSwipeRefreshLayout.setColorSchemeColors(Color.parseColor("#6200EE"), Color.parseColor("#3700B3"), Color.parseColor("#03DAC5"), Color.YELLOW, Color.BLUE);
        //下拉刷新
        mSwipeRefreshLayout.setOnRefreshListener(() -> {
            //模拟6秒刷新时间
            Handler handler = new Handler(Looper.getMainLooper());
            handler.postDelayed(() -> {
                RecyclerViewAsyncUpdateActivity.this.runOnUiThread(() -> {
//                    mList = getUpdateList();//数据变化
                    mList = getList();//数据不变
                    mRecycleViewAdapter.submitList(mList);//AsyncListDiffer差量刷新 异步
                });
                mSwipeRefreshLayout.setRefreshing(false);//结束刷新
            }, 6000);
        });
    }

    /**
     * RecyclerView点击事件
     */

    private void onRecyclerViewClick() {
        mRecycleViewAdapter.setRecyclerViewItemClick(new IRecyclerViewItemClick() {
            @Override
            public void onItemClick(View view, int position) {
                Log.d("DiffUtilCallBack", "RecyclerView点击 position----:" + position);
                Log.d("DiffUtilCallBack", "RecyclerView点击 title----:" + mList.get(position).getTitle());
            }

            @Override
            public void onItemLongClick(View view, int position) {
                Log.d("DiffUtilCallBack", "RecyclerView长按 position----:" + position);
                Log.d("DiffUtilCallBack", "RecyclerView长按 title----:" + mList.get(position).getTitle());
            }
        });
    }


    /**
     * 初始化 默认集合数据
     */

    private List<RecyclerViewBean> getList() {

        List<RecyclerViewBean> list = new ArrayList<>();

        RecyclerViewBean listViewBean1 = new RecyclerViewBean();
        listViewBean1.setAva("http://sss");
        listViewBean1.setTitle("张三");

        RecyclerViewBean listViewBean2 = new RecyclerViewBean();
        listViewBean2.setAva("http://sss");
        listViewBean2.setTitle("韦德");

        RecyclerViewBean listViewBean3 = new RecyclerViewBean();
        listViewBean3.setAva("http://sss");
        listViewBean3.setTitle("保罗");

        for (int i = 0; i < 10; i++) {
            list.add(listViewBean1);
            list.add(listViewBean2);
            list.add(listViewBean3);
        }

        return list;
    }

    /**
     * 初始化 刷新集合数据
     */

    private List<RecyclerViewBean> getUpdateList() {

        mCount++;

        List<RecyclerViewBean> list = new ArrayList<>();

        RecyclerViewBean listViewBean1 = new RecyclerViewBean();
        listViewBean1.setAva("https://avatar.csdnimg.cn/1/2/4/3_weixin_37730482_1607556601.jpg");
        listViewBean1.setTitle("张三_刷新" + mCount);

        RecyclerViewBean listViewBean2 = new RecyclerViewBean();
        listViewBean2.setAva("http://sss");
        listViewBean2.setTitle("韦德");

        RecyclerViewBean listViewBean3 = new RecyclerViewBean();
        listViewBean3.setAva("http://sss");
        listViewBean3.setTitle("保罗");

        for (int i = 0; i < 10; i++) {
            list.add(listViewBean1);
            list.add(listViewBean2);
            list.add(listViewBean3);
        }

        return list;
    }
}

 

Adapter

public class RecycleViewAsyncUpdateAdapter extends RecyclerView.Adapter<RecycleViewAsyncUpdateAdapter.ViewHolder> {

    private IRecyclerViewItemClick mClick;

    public void setRecyclerViewItemClick(IRecyclerViewItemClick click) {
        mClick = click;
    }

    private DiffUtil.ItemCallback<RecyclerViewBean> diffUtil = new DiffUtil.ItemCallback<RecyclerViewBean>() {

        /**
         * 是否是相同的Item 返回值操作 根据具体情况 一般不操作ItemViewType 此方法返回true即可
         */

        @Override
        public boolean areItemsTheSame(@NonNull RecyclerViewBean oldItem, @NonNull RecyclerViewBean newItem) {
            return true;
        }

        /**
         * 是否是相同的Contents
         */

        @Override
        public boolean areContentsTheSame(@NonNull RecyclerViewBean oldItem, @NonNull RecyclerViewBean newItem) {
            return oldItem.getTitle().equals(newItem.getTitle());
        }

        /**
         * 更新Item的某一个控件View
         */

        @Nullable
        @Override
        public Object getChangePayload(@NonNull RecyclerViewBean oldItem, @NonNull RecyclerViewBean newItem) {
            Bundle payload = new Bundle();

            //头像是否更新
            if (!oldItem.getAva().equals(newItem.getAva())) {
                payload.putString("KEY_AVA", newItem.getAva());
            }

            //标题是否更新
            if (!oldItem.getTitle().equals(newItem.getTitle())) {
                payload.putString("KEY_TITLE", newItem.getTitle());
            }

            if (payload.size() == 0) {//如果没有变化 就传空
                return null;
            }

            //更新Item的某个控件View
            return payload;
        }
    };

    private AsyncListDiffer<RecyclerViewBean> mDiffer;
    private List<RecyclerViewBean> mList;
    private LayoutInflater mInflater;
    private Context mContext;

    public RecycleViewAsyncUpdateAdapter(Context context) {
        mContext = context;
        mInflater = LayoutInflater.from(context);
        mDiffer = new AsyncListDiffer<>(this, diffUtil);
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.recyclerview_item, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.textView.setText(mList.get(position).getTitle());
        Glide.with(mContext).load(mList.get(position).getAva()).error(R.color.colorPrimary).into(holder.imageView);

        //Item点击事件
        holder.itemView.setOnClickListener(v -> {
            if (null != mClick) {
                mClick.onItemClick(v, position);
            }
        });

        //Item长按事件
        holder.itemView.setOnLongClickListener(v -> {
            if (null != mClick) {
                mClick.onItemLongClick(v, position);
            }
            return true;
        });

        Log.d("DiffUtilCallBack", "onBindViewHolder position----:" + position);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull List<Object> payloads) {
        if (payloads.isEmpty()) {//如果payloads集合为空 则执行两个参数的普通的onBindViewHolder方法
            onBindViewHolder(holder, position);
        } else {//如果payloads集合不为空 仅仅更新Item的某个控件
            Bundle bundle = (Bundle) payloads.get(0);
            if (null == bundle) return;
            String ava = bundle.getString("KEY_AVA");
            String title = bundle.getString("KEY_TITLE");
            holder.textView.setText(title);
            if (!TextUtils.isEmpty(ava)) {
                Glide.with(mContext).load(ava).into(holder.imageView);
            }
            Log.d("DiffUtilCallBack", "三个参数的onBindViewHolder方法 ava----:" + ava);
            Log.d("DiffUtilCallBack", "三个参数的onBindViewHolder方法 title----:" + title);
        }
    }

    @Override
    public int getItemCount() {
        return mDiffer.getCurrentList().size();//默认 return mList.size();
    }

    /**
     * ViewHolder类
     */

    static class ViewHolder extends RecyclerView.ViewHolder {

        private ImageView imageView;
        private TextView textView;

        public ViewHolder(View itemView) {
            super(itemView);
            imageView = itemView.findViewById(R.id.recyclerview_item_imageview);
            textView = itemView.findViewById(R.id.recyclerview_item_textview);
        }
    }


    /**
     * 刷新数据 AsyncListDiffer差量刷新 异步
     */

    public void submitList(List<RecyclerViewBean> data) {
        //1.AsyncListDiffer提交差量
        mDiffer.submitList(data);
        //2.更新集合数据
        mList = data;
    }

}

 

刷新时,由于模拟刷新前和刷新后的数据一样。刷新时onBindViewHolder方法没有执行。

 

那么,如果刷新前和刷新后的数据不一样呢?我们测试一下。

 

修改数据,即刷新前和刷新后的数据不一样

mList = getUpdateList();//数据变化

 刷新时,由于模拟刷新前和刷新后的数据每次都不一样。每次刷新时onBindViewHolder方法都会执行。

D/DiffUtilCallBack: onBindViewHolder position----:6

D/DiffUtilCallBack: onBindViewHolder position----:7

D/DiffUtilCallBack: onBindViewHolder position----:0

D/DiffUtilCallBack: onBindViewHolder position----:3




D/DiffUtilCallBack: onBindViewHolder position----:6

D/DiffUtilCallBack: onBindViewHolder position----:0

D/DiffUtilCallBack: onBindViewHolder position----:3



D/DiffUtilCallBack: onBindViewHolder position----:6

D/DiffUtilCallBack: onBindViewHolder position----:0

D/DiffUtilCallBack: onBindViewHolder position----:3





.........

 

 

注意

使用AsyncListDiffer时,和使用DiffUtil或者普通的RecyclerView有几点不同需要注意。

<1> Adaper中getItemCount()方法有差别

@Override
public int getItemCount() {
    return mDiffer.getCurrentList().size();//默认 return mList.size();
}

 

<2> 设置初始值有差别

普通

mRecycleViewAdapter = new RecycleViewUpdateAdapter(this, mList);
mRecyclerView.setAdapter(mRecycleViewAdapter);

即:在new Adapter时传参集合数据。

 

AsyncListDiffer

mRecycleViewAdapter = new RecycleViewAsyncUpdateAdapter(this);
mRecyclerView.setAdapter(mRecycleViewAdapter);
mRecycleViewAdapter.submitList(mList);//AsyncListDiffer差量刷新 异步 初始化也要用这种方式添加数据

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现高德地图卡片的拖拽功能,可以使用BottomSheet和RecycleView来实现。BottomSheet是一个可以从屏幕底部弹出的面板,可以含各种内容。RecycleView是一个用于显示列表的控件,可以显示大量的数据。 首先,在布局文件中添加BottomSheet和RecycleView控件: ``` <androidx.coordinatorlayout.widget.CoordinatorLayout android:id="@+id/coordinator_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" android:padding="16dp" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> <com.google.android.material.bottomsheet.BottomSheetBehavior android:id="@+id/bottom_sheet_behavior" android:layout_width="match_parent" android:layout_height="wrap_content" app:behavior_peekHeight="0dp" app:behavior_hideable="true" app:behavior_draggable="true"> <LinearLayout android:id="@+id/bottom_sheet" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" android:orientation="vertical"> <!-- BottomSheet内容 --> </LinearLayout> </com.google.android.material.bottomsheet.BottomSheetBehavior> </androidx.coordinatorlayout.widget.CoordinatorLayout> ``` 然后,要在代码中实现BottomSheet和RecycleView的拖拽功能。可以使用TouchHelper类来实现拖拽和滑动的操作。首先,要创建一个TouchHelper.Callback类: ``` private val itemTouchHelperCallback = object : ItemTouchHelper.Callback() { override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN val swipeFlags = 0 return makeMovementFlags(dragFlags, swipeFlags) } override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { val fromPosition = viewHolder.adapterPosition val toPosition = target.adapterPosition adapter.moveItem(fromPosition, toPosition) return true } override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { // do nothing } } ``` 这个类中实现了getMovementFlags、onMove和onSwiped三个方法。getMovementFlags方法用于指定可以执行的操作,这里只允许上下拖拽操作。onMove方法用于在拖拽时处理数据的移动,这里调用了adapter的moveItem方法。onSwiped方法用于处理滑动操作,这里不需要处理。 接下来,要将TouchHelper.Callback类绑定到RecycleView上: ``` val itemTouchHelper = ItemTouchHelper(itemTouchHelperCallback) itemTouchHelper.attachToRecyclerView(recyclerView) ``` 最后,在BottomSheetBehavior的回调函数中,要将BottomSheet和RecycleView的高度进行调整,以便在BottomSheet拖拽时RecycleView的高度也能够自动调整: ``` val bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet) bottomSheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onStateChanged(bottomSheet: View, newState: Int) { if (newState == BottomSheetBehavior.STATE_DRAGGING) { val layoutParams = recyclerView.layoutParams as CoordinatorLayout.LayoutParams layoutParams.height = coordinatorLayout.height - bottomSheet.top recyclerView.layoutParams = layoutParams } } override fun onSlide(bottomSheet: View, slideOffset: Float) { // do nothing } }) ``` 这里使用了BottomSheetBehavior的回调函数,当BottomSheet的状态发生变化时调用。在拖拽时,将RecycleView的高度进行调整,以便适应BottomSheet的高度。 这样,就可以实现高德地图卡片的拖拽功能了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值