간단하고 똑똑한 adapter-SmartDiffAdapter

22141 단어
프로젝트 주소:https://github.com/woaigmz/SmartDiffAdapter, 가입을 환영합니다:) 화이팅!감사https://github.com/CymChad/BaseRecyclerViewAdapterHelper의 대신들:)1: 이adapter는 일부 기능을 간소화하여 자신의 프로젝트에서 사용하면 추가 코드가 너무 많다고 느끼지 않는다.2:adapter의 추상적인 convert 방법을 실현하여view와 데이터의 연결을 하고 모델(data)과viewholder(helper)를 모범적이고 구조로 전송하고,convert에서 데이터와 helper를 출력합니다.
protected abstract void convert(K helper, T item)

3:Smart Diff Adapter는android를 생산했습니다.support.v7.util 아래의 DiffUtil에서 국부 리셋을 진행하고 rxjava로 라인을 전환하여 하위 라인에서 계산하고 adapter 리셋 데이터를 주 라인에서 조작하면 리셋을 표시합니다. 항목의 변경 수와 총수의 비율을 통해 라인을 방출합니다.
BaseSmartAdapter: 다중 항목 지원
public abstract class BaseSmartAdapter extends RecyclerView.Adapter {}
    /**    
     * initialize some
     * @param layoutResId   
     * @param mData         
     */
    public BaseSmartAdapter(int layoutResId, List mData) {
        if (layoutResId != 0)
            this.mLayoutResId = layoutResId;
        this.mData = mData == null ? new ArrayList() : mData;
    }

    @Override
    public K onCreateViewHolder(ViewGroup parent, int viewType) {
        K baseViewHolder = null;
        this.mLayoutInflater = LayoutInflater.from(parent.getContext());
        baseViewHolder = onCreateDefViewHolder(parent, viewType);
        return baseViewHolder;
    }

    @Override
    public void onBindViewHolder(K holder, int position) {
        convert(holder, getItem(position));
    }
    @Override
    public void onBindViewHolder(K holder, int position, List payloads) {
        if (payloads == null || payloads.isEmpty()) {
            onBindViewHolder(holder, position);
        } else {
            Bundle payload = (Bundle) payloads.get(0);
            convert(holder, payload);
        }
    }
    protected abstract void convert(K helper, T item);

    protected abstract void convert(K helper, Bundle payload);
    //******************************************************************************
       
    private MultiTypeDelegate mMultiTypeDelegate;

    public void setMultiTypeDelegate(MultiTypeDelegate multiTypeDelegate) {
        mMultiTypeDelegate = multiTypeDelegate;
    }

    public MultiTypeDelegate getMultiTypeDelegate() {
        return mMultiTypeDelegate;
    }

    protected int getDefItemViewType(int position) {
        if (mMultiTypeDelegate != null) {
            return mMultiTypeDelegate.getDefItemViewType(mData, position);
        }
        return super.getItemViewType(position);
    }


    protected K onCreateDefViewHolder(ViewGroup parent, int viewType) {
        int layoutId = mLayoutResId;
        if (mMultiTypeDelegate != null) {
            layoutId = mMultiTypeDelegate.getLayoutId(viewType);
        }
        return createBaseViewHolder(parent, layoutId);
    }
 //**************************************************************************************************
     /**
     * DiffUtils     
     *
     * @param newData    
     */
    public void refreshData(final List newData) {
        if (smartDiffCallBack == null) {
            throw new RuntimeException("callback must be created before refresh data");
        }
        Observable.create(new ObservableOnSubscribe() {
            @Override
            public void subscribe(ObservableEmitter e) throws Exception {
                BaseCallBack callBack = new BaseCallBack(mData, newData, smartDiffCallBack);
                DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(callBack, true);
                e.onNext(diffResult);
            }
        }).subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer() {
            @Override
            public void accept(DiffUtil.DiffResult diffResult) throws Exception {
                diffResult.dispatchUpdatesTo(BaseSmartAdapter.this);
                mData = newData;

            }
        }, new Consumer() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                replaceData(newData);
            }
        });
    }



this work will be update to build project simplily 사용
allprojects {
         repositories {
             ...
             maven { url 'https://jitpack.io' }
        }
}

Step 2. Add the dependency
dependencies {
            implementation 'com.github.woaigmz:SmartDiffAdapter:0.1.2'
    }

just like this your RecyclerView adapter:
public class MainAdapter extends BaseSmartAdapter {


    public MainAdapter(int mLayoutResId) {
        super(mLayoutResId);
    }

    @Override
    protected void convert(MainViewHolder helper, Student item) {
        helper.setText(R.id.student_name, item.getName())
                .setText(R.id.student_sex, item.getSex())
                .setText(R.id.student_age, item.getAge())
                .setText(R.id.student_weight, item.getWeight())
                .setText(R.id.student_score, item.getScore());
    }

    @Override
    protected void convert(MainViewHolder helper, Bundle payload) {
        for (String key : payload.keySet()) {
            switch (key) {
                case "name":
                    helper.setText(R.id.student_name, payload.getString("name"));
                    break;
                case "sex":
                    helper.setText(R.id.student_sex, payload.getString("sex"));
                    break;
                case "age":
                    helper.setText(R.id.student_age, payload.getString("age"));
                    break;
                case "weight":
                    helper.setText(R.id.student_weight, payload.getString("weight"));
                    break;
                case "score":
                    helper.setText(R.id.student_score, payload.getString("score"));
                    break;

            }
        }
    }
}


use:
 rv.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        adapter = new MainAdapter(R.layout.item);
        adapter.setSmartDiffCallBack(new SmartDiffCallBack() {
            @Override
            public boolean areItemsTheSame(Student oldItem, Student newItem) {
                return oldItem.getName().equals(newItem.getName());
            }

            @Override
            public boolean areContentsTheSame(Student oldItem, Student newItem) {
                if (!oldItem.getName().equals(newItem.getName())) {
                    return false;
                }
                if (!oldItem.getSex().equals(newItem.getSex())) {
                    return false;
                }
                if (oldItem.getAge().equals(newItem.getAge())) {
                    return false;
                }
                if (oldItem.getWeight().equals(newItem.getWeight())) {
                    return false;
                }
                if (oldItem.getScore().equals(newItem.getScore())) {
                    return false;
                }
                return true;
            }

            @Nullable
            @Override
            public Bundle getChangePayload(Bundle bundle, Student oldItem, Student newItem) {
                if (!oldItem.getName().equals(newItem.getName())) {
                    bundle.putString("name", newItem.getName());
                }
                if (!oldItem.getAge().equals(newItem.getAge())) {
                    bundle.putString("age", newItem.getAge());
                }
                if (!oldItem.getSex().equals(newItem.getSex())) {
                    bundle.putString("sex", newItem.getSex());
                }
                if (!oldItem.getWeight().equals(newItem.getWeight())) {
                    bundle.putString("weight", newItem.getWeight());
                }
                if (!oldItem.getScore().equals(newItem.getScore())) {
                    bundle.putString("score", newItem.getScore());
                }
                if (bundle.size() == 0) {
                    return null;
                }
                return bundle;
            }
        });
        rv.setAdapter(adapter);
        ....
        //the main
        adapter.refreshData(studentsNew);

ViewHolder의 패키지 단순 프록시 모드: (인터페이스 계약 - 구현 클래스) IHolder:
public interface IHolder {

    IHolder get(View itemView);

    View getItemView();

     T getView(@IdRes int viewId);

    IHolder setTag(@IdRes int viewId, Object tag);

    IHolder setTag(@IdRes int viewId, int key, Object tag);

    @Deprecated
    IHolder setOnTouchListener(@IdRes int viewId, View.OnTouchListener listener);

    @Deprecated
    IHolder setOnLongClickListener(@IdRes int viewId, View.OnLongClickListener listener);

    @Deprecated
    IHolder setOnItemClickListener(@IdRes int viewId, AdapterView.OnItemClickListener listener);

    IHolder setOnItemLongClickListener(@IdRes int viewId, AdapterView.OnItemLongClickListener listener);

    @Deprecated
    IHolder setOnClickListener(@IdRes int viewId, View.OnClickListener listener);

    IHolder setText(@IdRes int viewId, CharSequence value);

    IHolder setText(@IdRes int viewId, @StringRes int strId);

    IHolder setImageResource(@IdRes int viewId, @DrawableRes int imageResId);

    IHolder setBackgroundColor(@IdRes int viewId, @ColorInt int color);

    IHolder setBackgroundRes(@IdRes int viewId, @DrawableRes int backgroundRes);

    IHolder setTextColor(@IdRes int viewId, @ColorInt int textColor);

    IHolder setImageDrawable(@IdRes int viewId, Drawable drawable);

    IHolder setImageBitmap(@IdRes int viewId, Bitmap bitmap);

    IHolder setAlpha(@IdRes int viewId, float value);

    IHolder setGone(@IdRes int viewId, boolean visible);

    .......    

}

BaseViewHolder:
public class BaseViewHolder extends RecyclerView.ViewHolder implements IHolder {

    private final SparseArray views;
    private View mItemView;


    public BaseViewHolder(View itemView) {
        super(itemView);
        this.views = new SparseArray<>();
        this.mItemView = itemView;
        this.mItemView.setTag(this);
    }

    @Override
    public BaseViewHolder get(View itemView) {
        return (BaseViewHolder) itemView.getTag();
    }

    @Override
    public View getItemView() {
        if (mItemView == null) throw new RuntimeException("item has been gc");
        return mItemView;
    }

    @Override
    public  T getView(@IdRes int viewId) {
        View view = views.get(viewId);
        if (view == null) {
            view = mItemView.findViewById(viewId);
            views.put(viewId, view);
        }
        return (T) view;
    }

    @Override
    public BaseViewHolder setTag(@IdRes int viewId, Object tag) {
        View view = getView(viewId);
        view.setTag(tag);
        return this;
    }

    @Override
    public BaseViewHolder setTag(@IdRes int viewId, int key, Object tag) {
        View view = getView(viewId);
        view.setTag(key, tag);
        return this;
    }

    @Override
    @Deprecated
    public BaseViewHolder setOnTouchListener(@IdRes int viewId, View.OnTouchListener listener) {
        View view = getView(viewId);
        view.setOnTouchListener(listener);
        return this;
    }

    @Override
    @Deprecated
    public BaseViewHolder setOnLongClickListener(@IdRes int viewId, View.OnLongClickListener listener) {
        View view = getView(viewId);
        view.setOnLongClickListener(listener);
        return this;
    }
    .......    

다중 목적 사용: your bean like this must be implements MultiItem Entity
public class HomePageMultiItem implements MultiItemEntity {

    public int itemType;

    public static final int HEAD_BANNER = 1;
    public static final int NAVIGATION_BUTTON_LIST = 2;
    public static final int RECOMMEND_PRODUCT_LIST = 3;

    public List imgList;
    public List buttonList;
    public HomePageRecommendsProductListBean.ListBean listBean;


    @Override
    public int getItemType() {
        return itemType;
    }
}

your adapter: List가 데이터를 받는 순서에 따라 여러 항목의 순서가 결정됩니다. you can test or view the source code of Smart Diff Adapter thanks
public class HomePageAdapter extends BaseMultiItemQuickAdapter {


    public HomePageAdapter(List data) {
        super(data);
        addItemType(HomePageMultiItem.HEAD_BANNER, R.layout.home_page_banner);
        addItemType(HomePageMultiItem.NAVIGATION_BUTTON_LIST, R.layout.home_page_navigation_button);
        addItemType(HomePageMultiItem.RECOMMEND_PRODUCT_LIST, R.layout.item_home_recommend);
    }

    @Override
    protected void convert(MyViewHolder helper, HomePageMultiItem item) {

        switch (helper.getItemViewType()) {

            case HomePageMultiItem.HEAD_BANNER:
                helper.setBannerList(item.imgList);
                break;

            case HomePageMultiItem.NAVIGATION_BUTTON_LIST:
                helper.setNavigationButtonList(item.buttonList);
                break;

            case HomePageMultiItem.RECOMMEND_PRODUCT_LIST:
                HomePageRecommendsProductListBean.ListBean bean = item.listBean;
                ......  
                break;
        }


    }

    public void stopBanner(ViewGroup groupView) {
      ......
    }

    static class MyViewHolder extends BaseViewHolder {
        public MyViewHolder(View view) {
            super(view);
        }

        MyViewHolder setBannerList(List imgList) {
            List urls = new ArrayList<>();
            for (BannerListBean.ImgListBean imgListBean : imgList) {
                urls.add(imgListBean.address);
            }
            Banner banner = getView(R.id.cycleBanner);
            banner.setImageLoader(new GlideImageLoader());
            banner.setImages(urls);
            banner.start();
            return this;
        }


        MyViewHolder setNavigationButtonList(List buttonList) {
            TabLayout tab = getView(R.id.tabs_home);
            tab.removeAllTabs();
            for (HomePageNavigationButtonBean.HomePageButtonListBean homePageButtonListBean : buttonList) {
                View brand_view = View.inflate(tab.getContext(), R.layout.tablayout_brand, null);
                ImageView iv_brand = brand_view.findViewById(R.id.iv_home_btn);
                TextView tv_brand = brand_view.findViewById(R.id.tv_home_btn);
                ImageLoader.loadImage(iv_brand, homePageButtonListBean.buttonURL);
                tv_brand.setText(homePageButtonListBean.buttonName);
                tab.addTab(tab.newTab().setCustomView(brand_view), false);
            }
            return this;
        }
    }
}

presenter(getdata --- this example --->HomePageMultiItem):
public class HomePagePresenter extends BasePresenter implements HomePageContract.HomePagePresenter {


    @Override
    public void toLoadingData() {

        mView.showLoading();
        //.onErrorReturn(throwable -> Collections.emptyList())        ,          ,            
        mDisposable.add(Observable.zip(mModel.getBannerList().onErrorReturn(throwable -> Collections.emptyList()), mModel.getNavigationButtonList().onErrorReturn(throwable -> Collections.emptyList()), mModel.getRecommendsProductList().onErrorReturn(throwable -> Collections.emptyList()), (bannerListBeans, buttonListBeans, recommendListBeans) -> {
            List items = getHomePageMultiItems(bannerListBeans, buttonListBeans, recommendListBeans);
            mView.hideLoading();
            return items;
        }).subscribe((List homePageMultiItems) ->
                mView.onLoadingSucceed(homePageMultiItems), throwable ->
                mView.onError(throwable.getMessage())));

    }

    @Override
    public void refreshData() {
        //    zip              onErrorReturn      ,    doOnError        
        mDisposable.add(Observable.zip(mModel.getBannerList(), mModel.getNavigationButtonList(), mModel.getRecommendsProductList(), (bannerListBeans, buttonListBeans, recommendListBeans) -> {
            List items = getHomePageMultiItems(bannerListBeans, buttonListBeans, recommendListBeans);
            return items;
        }).doOnError(new ApiErrorConsumer() {
            @Override
            public void onFail(String code, String message) {
                mView.onError("    :" + message);
            }
        }).onErrorReturn(throwable -> Collections.emptyList()).subscribe(homePageMultiItems ->
                mView.onLoadingSucceed(homePageMultiItems)));
        mView.afterRefreshData();
    }

    @Override
    public HomePageContract.HomePageModel bindModel() {
        return (HomePageContract.HomePageModel) HomePageModel.newInstance();
    }

    /**********************************************************************************************************************************************************/

    @NonNull
    private List getHomePageMultiItems(List bannerListBeans, List buttonListBeans, List recommendListBeans) {
        List items = new ArrayList<>();

        if (bannerListBeans != null && bannerListBeans.size() > 0) {
            HomePageMultiItem item = new HomePageMultiItem();
            item.itemType = HomePageMultiItem.HEAD_BANNER;
            item.imgList = bannerListBeans;
            items.add(item);
        }
        if (buttonListBeans != null && buttonListBeans.size() > 0) {
            HomePageMultiItem item = new HomePageMultiItem();
            item.itemType = HomePageMultiItem.NAVIGATION_BUTTON_LIST;
            item.buttonList = buttonListBeans;
            items.add(item);
        }
        if (recommendListBeans != null && recommendListBeans.size() > 0) {
            for (HomePageRecommendsProductListBean.ListBean listBean : recommendListBeans) {
                HomePageMultiItem item = new HomePageMultiItem();
                item.itemType = HomePageMultiItem.RECOMMEND_PRODUCT_LIST;
                item.listBean = listBean;
                items.add(item);
            }
        }
        return items;
    }
}

마지막: BaseDiffCallBack의 몇 가지 리셋 방법에 대한 이해:
public class BaseCallBack extends DiffUtil.Callback {

    private final List oldItems;
    private final List newItems;
    private SmartDiffCallBack callBack;


    BaseCallBack(List oldItems, List newItems, SmartDiffCallBack smartDiffCallBack) {
        this.oldItems = oldItems;
        this.newItems = newItems;
        this.callBack = smartDiffCallBack;
    }


    @Override
    public final int getOldListSize() {
        return oldItems.size();
    }

    @Override
    public final int getNewListSize() {
        return newItems.size();
    }

    /**
     *                Item。
     *      bean     id
     * For example, if your items have unique ids, this method should check their id equality.
     *
     * @param oldItemPosition
     * @param newItemPosition
     * @return True if the two items represent the same object or false if they are different.
     */
    @Override
    public final boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return callBack.areItemsTheSame(oldItems.get(oldItemPosition), newItems.get(newItemPosition));
    }

    /**
     *        areItemsTheSame()  true ,   。
     *
     * @param oldItemPosition
     * @param newItemPosition
     * @return True if the contents of the items are the same or false if they are different.Item         。
     */
    @Override
    public final boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        return callBack.areContentsTheSame(oldItems.get(oldItemPosition), newItems.get(newItemPosition));
    }

    /**
     *  {@link # areItemsTheSame(int, int)}   true, {@link # areContentsTheSame(int, int)}   false ,DiffUtils      ,
     *      Item(   )   payload。
     *
     * @param oldItemPosition
     * @param newItemPosition
     * @return         null
     */
    @Nullable
    @Override
    public Object getChangePayload(int oldItemPosition, int newItemPosition) {
        return callBack.getChangePayload(new Bundle(), oldItems.get(oldItemPosition), newItems.get(newItemPosition));
    }
}

Adapter에서 setXXinterface를 쓰는 방법을 사용하는 사용자 정의 콜백 인터페이스
public interface SmartDiffCallBack {
    boolean areItemsTheSame(T oldItem, T newItem);

    boolean areContentsTheSame(T oldItem, T newItem);

    @Nullable
    Object getChangePayload(Bundle bundle, T oldItem, T newItem);
}

thanks 여러분의 관심과 지지에 감사 드립니다:)

좋은 웹페이지 즐겨찾기