Androidプロジェクトのまとめ——Stagg eredGrade LayoutManagerの滝の流れのよくある問題

26801 ワード

背景の紹介:
一つのプロジェクトをする時に、このような要求があります.サーバーにお願いしてから写真を見せてください.美図のような需要があるでしょう.具体的なプロジェクトの詳細は詳しく説明しません.サービス側は国内の優秀なThinkjsフレームに基づいています.クライアント:Android;Androidクライアントの問題についてまとめてみます.後でサービスをまとめます.
デマンド機能ポイントは以下の通りです.1.改ページクエリをサポートし、アップデートしてより多くを検索し、データがある場合は回転圏のローディングがより多く、データがない場合はヒントを与えることを表示します.2.爆布流で表示し、同時に写真の高さがランダムである.
全体の考え方1.oKHttp第三者オープンソースを採用してインターフェースデータ要求を行う;2.RecyclerView+Stagg eredGrade LayoutManagerを使って爆布流のUIを実現する;
よくある問題:1.RecyclerViewはどうやってもっと多くのローディングを実現しますか?2.Stagg eredGridLayoutManagerの表示がもっと多くロードされた時、最後のitemとして単独で画面の幅を満たせず、一つのitemの幅として表示されます.3.Stagg eredGridLayoutManagerはどのようにランダムにitemの高さを設定しますか?4.Stagg eredGridLayoutManagerからデータリフレッシュUIを読み込む際、高度にランダムでページitemのジッタが発生します.5.RecyclerViewの不可解なInconsistency detectedが崩壊する.
埋め立てを開始します.1.recyclerViewはどうやってボトムローディングを実現しますか?
  • まずrecyclerViewスライドイベントをモニターできるようにする.
  • は、recyclerViewが最後のitemにスライドするかどうかを判断する.
  • recyclerViewより多くのRecyclerView.Adapterをロードする設定処理.
  • 関連コード:recyclerViewスライドイベントをモニターし、最後のアイテムにスライドするかどうかを計算します.
    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    staggeredGridLayoutManager.invalidateSpanAssignments(); //             
                    currentScrollState = newState;
                    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
                    int visibleItemCount = layoutManager.getChildCount();
                    int totalItemCount = layoutManager.getItemCount();
                    if ((visibleItemCount > 0 && currentScrollState == RecyclerView.SCROLL_STATE_IDLE && (lastVisibleItemPosition) >= totalItemCount - 1)) {
                        Log.i(TAG, "onScrollStateChanged: ...");
                        requestMoreData();//      
                    }
                }
    
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
    
                    if (layoutManagerType == null) {
                        if (layoutManager instanceof LinearLayoutManager) {
                            layoutManagerType = LayoutManagerType.LinearLayout;
                        } else if (layoutManager instanceof GridLayoutManager) {
                            layoutManagerType = LayoutManagerType.GridLayout;
                        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
                            layoutManagerType = LayoutManagerType.StaggeredGridLayout;
                        } else {
                            throw new RuntimeException(
                                    "Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager");
                        }
                    }
    
                    switch (layoutManagerType) {
                        case LinearLayout:
                            lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
                            break;
                        case GridLayout:
                            lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
                            break;
                        case StaggeredGridLayout:
                            StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
                            if (lastPositions == null) {
                                lastPositions = new int[staggeredGridLayoutManager.getSpanCount()];
                            }
                            staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions);
                            lastVisibleItemPosition = findMax(lastPositions);
                            break;
                        default:
                            break;
                    }
                }
            });
        /**
         *        
         *
         * @param lastPositions
         * @return
         */
        private int findMax(int[] lastPositions) {
            int max = lastPositions[0];
            for (int value : lastPositions) {
                if (value > max) {
                    max = value;
                }
            }
    
            return max;
        }
    
        public static enum LayoutManagerType {
            LinearLayout,
            StaggeredGridLayout,
            GridLayout
        }
    RecyclerView.Adapterの関連コードは主に2つのView Holderタイプを定義します.TYPE_BOTTOMは底のview Holder、TYPE_を表します.NOMALは正常なitemのview Holderと表し、positionによって異なるview holderを表示します.コードの中には上のStaggreed LayoutManagerに対する問題処理もあります.具体的には以下に詳しく説明します.
    public class XXXRcyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    
        private static final int TYPE_BOTTOM = 0;
        private static final int TYPE_NOMAL = 1;
        private LayoutInflater inflater;
        private Context mContext;
        private int preNumb = 0;
        private boolean isLoading = false;
    
        ************        
    
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == TYPE_BOTTOM){
                return new BottomViewHolder(inflater.inflate(R.layout.item_type_bottom,parent,false));
            }
            return new NomalViewHolder(inflater.inflate(R.layout.item_qr_code_say_rcy,parent,false));
        }
    
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
            if (holder instanceof NomalViewHolder){
                NomalViewHolder nomalViewHolder = (NomalViewHolder) holder;
                *********        ***********
                ViewGroup.LayoutParams lp = nomalViewHolder.imgView.getLayoutParams();
                int scale = new Random().nextInt(10);
                if (scale < 5){
                    scale = 9;
                }
                lp.height= (int) (UIUtil.dp2px(mContext,200) *0.1 * scale);
                lp.width= RecyclerView.LayoutParams.MATCH_PARENT;
                nomalViewHolder.imgView.setLayoutParams(lp);
                *********     Imageview      *********
    
            }else if (holder instanceof  BottomViewHolder){
                BottomViewHolder bottomViewHolder = (BottomViewHolder) holder;
                if (isLoading){
    
                  bottomViewHolder.bottomContainer.setVisibility(View.VISIBLE);
                    bottomViewHolder.imgView.setVisibility(View.VISIBLE);
                    bottomViewHolder.textView.setVisibility(View.VISIBLE);
                    /***       ***/
                }else{
                    bottomViewHolder.bottomContainer.setVisibility(View.VISIBLE);
                    bottomViewHolder.imgView.setVisibility(View.GONE);
                    bottomViewHolder.textView.setVisibility(View.VISIBLE);
                    /***       ***/
                }
            }
        }
    
        @Override
        public int getItemCount() {
            return xxxxList.size() + 1;
        }
    
    
        /**
         *   viewType    
         * @param position
         * @return
         */
        @Override
        public int getItemViewType(int position) {
            if (position < qrCodeSayBeanList.size()){
                return TYPE_NOMAL;
            }
            return TYPE_BOTTOM;
        }
    
    
        /**
         *    GridLayoutManager      ,        item          
         * @param recyclerView
         */
        @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            super.onAttachedToRecyclerView(recyclerView);
            RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
            if (manager instanceof GridLayoutManager) {
                final GridLayoutManager gridManager = ((GridLayoutManager) manager);
                gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                    @Override
                    public int getSpanSize(int position) {
                        return isFooter(position) ? gridManager.getSpanCount() : 1;
                    }
                });
            }
    
        }
    
    
        /**
         *    StaggeredGridLayoutManager      ,          item          
         * @param holder
         */
        @Override
        public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
            super.onViewAttachedToWindow(holder);
            if (isStaggeredGridLayout(holder)) {
                handleLayoutIfStaggeredGridLayout(holder, holder.getLayoutPosition());
            }
        }
    
        private boolean isStaggeredGridLayout(RecyclerView.ViewHolder holder) {
            ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
            if (layoutParams != null && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) {
                return true;
            }
            return false;
        }
    
        protected void handleLayoutIfStaggeredGridLayout(RecyclerView.ViewHolder holder, int position) {
            if ( isFooter(position)){
                StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();
                p.setFullSpan(true);
            }
        }
    
        /**
         *       
         * @param position
         * @return
         */
        private boolean isFooter(int position) {
            if (position == qrCodeSayBeanList.size()){
                return true;
            }
            return false;
        }
    
    
        /**
             *    viewHolder
             */
        private static class BottomViewHolder extends RecyclerView.ViewHolder{
    
            private View bottomContainer;
            private ImageView imgView;
            private TextView textView;
            public BottomViewHolder(View itemView) {
                super(itemView);
                bottomContainer = itemView.findViewById(R.id.bottom_container);
                imgView = itemView.findViewById(R.id.img_loading);
                textView = itemView.findViewById(R.id.txt_tips);
            }
        }
    
        /**
         *    viewHolder
         */
        private static class NomalViewHolder extends RecyclerView.ViewHolder{
            private ImageView imgView;
            private TextView txtViewNumb;
            private TextView txtLikedNumb;
            public NomalViewHolder(View itemView) {
                super(itemView);
                imgView = itemView.findViewById(R.id.img_view);
                txtViewNumb = itemView.findViewById(R.id.txt_view_numbs);
                txtLikedNumb = itemView.findViewById(R.id.txt_tap_liked_numbs);
            }
        }
    
        /**
         *       ,    
         */
        public void startLoading(){
            isLoading = true;
    //        notifyDataSetChanged();
            notifyItemRangeChanged(preNumb,qrCodeSayBeanList.size());//    item  ,                ,        
            preNumb = xxxList.size();
        }
    
        /**
         *       ,    
         */
        public void stopLoading(){
            isLoading = false;
    //        notifyDataSetChanged();
            notifyItemRangeChanged(preNumb,qrCodeSayBeanList.size());//    item  ,                ,        
            preNumb = xxxList.size();
        }
    
        /**
         *       ,    
         */
        public void stopLoadingNotifyAll(){
            isLoading = false;
            notifyDataSetChanged();
        }
    }
    
    2.Stagg eredGridLayoutManagerの表示がもっと多くロードされた時、最後のitemとして単独で画面の幅を満たせず、一つのitemの幅として表示されます.
    主にlayoutManagerの特徴によって、下記の2つの方法を書き換え、layoutManagerに関するSpanの設定方法を呼び出します.
    final GridLayoutManager gridManager = ((GridLayoutManager) manager);
                gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                    @Override
                    public int getSpanSize(int position) {
                        return isFooter(position) ? gridManager.getSpanCount() : 1;
                    }
                });
    StaggeredGridLayoutManager.LayoutParams.setFullSpan(true);
    /**
         *    GridLayoutManager      ,        item          
         * @param recyclerView
         */
        @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            super.onAttachedToRecyclerView(recyclerView);
            RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
            if (manager instanceof GridLayoutManager) {
                final GridLayoutManager gridManager = ((GridLayoutManager) manager);
                gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                    @Override
                    public int getSpanSize(int position) {
                        return isFooter(position) ? gridManager.getSpanCount() : 1;
                    }
                });
            }
    
        }
    
    
        /**
         *    StaggeredGridLayoutManager      ,          item          
         * @param holder
         */
        @Override
        public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
            super.onViewAttachedToWindow(holder);
            if (isStaggeredGridLayout(holder)) {
                handleLayoutIfStaggeredGridLayout(holder, holder.getLayoutPosition());
            }
        }
    
        private boolean isStaggeredGridLayout(RecyclerView.ViewHolder holder) {
            ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
            if (layoutParams != null && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) {
                return true;
            }
            return false;
        }
    
        protected void handleLayoutIfStaggeredGridLayout(RecyclerView.ViewHolder holder, int position) {
            if ( isFooter(position)){
                StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();
                p.setFullSpan(true);
            }
        }
    
        /**
         *       
         * @param position
         * @return
         */
        private boolean isFooter(int position) {
            if (position == qrCodeSayBeanList.size()){
                return true;
            }
            return false;
        }
    
    3.Stagg eredGridLayoutManagerはどのようにランダムにitemの高さを設定しますか?
     ViewGroup.LayoutParams lp = nomalViewHolder.imgView.getLayoutParams();
                int scale = new Random().nextInt(10);
                if (scale < 5){
                    scale = 9;
                }
                lp.height= (int) (UIUtil.dp2px(mContext,200) *0.1 * scale);
                lp.width= RecyclerView.LayoutParams.MATCH_PARENT;
                nomalViewHolder.imgView.setLayoutParams(lp);
    
    4.Stagg eredGridLayoutManagerからデータリフレッシュUIを読み込む際、高度にランダムでページitemのジッタが発生します.ここでは直接notifyData SetChangedを呼び出します.これは全体の更新で、更新時にitemの高さがランダムに割り当てられ、データが更新された時にジッタが発生します.notifyItemRangeChangedを採用してローカルリフレッシュすることを提案します.
        /**
         *       ,    
         */
        public void startLoading(){
            isLoading = true;
    //        notifyDataSetChanged();
            notifyItemRangeChanged(preNumb,qrCodeSayBeanList.size());//    item  ,                ,        
            preNumb = qrCodeSayBeanList.size();
        }
    
        /**
         *       ,    
         */
        public void stopLoading(){
            isLoading = false;
    //        notifyDataSetChanged();
            notifyItemRangeChanged(preNumb,xxxList.size());//    item  ,                ,        
            preNumb = xxxList.size();
        }
    
        /**
         *       ,    
         */
        public void stopLoadingNotifyAll(){
            isLoading = false;
            notifyDataSetChanged();
        }
    5.RecyclerViewの不可解なInconsistency detectedが崩壊する.CustoomStagg eredGrade LayoutManagerをカスタマイズしてオンラyoutChildrenで異常を捕獲します.
    public class CustomStaggeredGridLayoutManager extends StaggeredGridLayoutManager {
        private static final String TAG = "LOG_CustomStaggered";
        public CustomStaggeredGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }
    
        public CustomStaggeredGridLayoutManager(int spanCount, int orientation) {
            super(spanCount, orientation);
        }
    
        @Override
        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
            try {
                super.onLayoutChildren(recycler, state);
            }catch (Exception e){
                Log.i(TAG, "onLayoutChildren: e " + e.getMessage());
            }
    
        }
    }
    参照https://www.jianshu.com/p/2eca433869e9