使用recycleview实现item多布局踩的坑

来源:互联网 发布:mac的safari无法退出 编辑:程序博客网 时间:2024/05/21 08:21

关于使用recycleview写多种布局布局遇到的坑

最近项目中遇到多种布局嵌套使用情况,为了不多麻烦去写自定义控件监听事件的分发,便使用了recycleview.对于第一次在项目中使用这个玩意,在看过官方文档后并不是很理解其介绍(主要是全英文),于是乎在CSDN怼了个中文注解的示例demo来用,于是乎就有了下面的这个问题.

 

1. 首先看原型图


2. 服务器返回的数据

 

 

3.我的代码(recycleview使用adapter部分出自CSDN示列demo).

Activity:

package com.example.administrator.a3dmark.detail_shop;

import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.example.administrator.a3dmark.Activity.BaseActivity;
import com.example.administrator.a3dmark.R;
import com.example.administrator.a3dmark.adapter.ShopAdapter;
import com.example.administrator.a3dmark.bean.Banners;
import com.example.administrator.a3dmark.bean.ShopGoods;
import com.example.administrator.a3dmark.util.Contants;
import com.example.administrator.a3dmark.util.ItemDivider;
import com.example.administrator.a3dmark.util.SharedUtil;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.callback.StringCallback;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

import butterknife.BindView;
import butterknife.ButterKnife;
import okhttp3.Call;
import okhttp3.Response;

/**
 * 店铺
 * Created by Administrator on 2017/3/8.
 */
public class Shop_ActivityextendsBaseActivity {

    @BindView(R.id.image_title_white_back)
    ImageView imageTitleWhiteBack;
    @BindView(R.id.tv_title_white)
    TextView tvTitleWhite;
    @BindView(R.id.tv_title_white_vice)
    TextView tvTitleWhiteVice;
    Intent intent;
    @BindView(R.id.tv_collection_title)
    TextView tvCollectionTitle;
    @BindView(R.id.tv_title_num)
    TextView tvTitleNum;
    @BindView(R.id.ll_title)
    LinearLayout llTitle;
    @BindView(R.id.recyclerView)
    RecyclerView recyclerView;


    private String bussiness_id;
    private String userid;

    //轮播图List<bean>对象
    
privateArrayList<Banners>Flybanners= newArrayList<>();
    //商品List<bean>对象
    
privateArrayList<ShopGoods>goodses= newArrayList<ShopGoods>();

    private ShopAdapter adapter;

    @Override
    protected voidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.shop_activity);
        ButterKnife.bind(this);
        intent = getIntent();
        bussiness_id =intent.getStringExtra("bussiness_id");
        Toast.makeText(Shop_Activity.this,bussiness_id, Toast.LENGTH_SHORT).show();
        userid = (String) SharedUtil.getParam(this,"userid","");
        llTitle.setVisibility(View.VISIBLE);

        recyclerView.setLayoutManager(newGridLayoutManager(recyclerView.getContext(),3, GridLayoutManager.VERTICAL,false));
        recyclerView.addItemDecoration(newItemDivider().setDividerWith(this,20));
        adapter = new ShopAdapter(Shop_Activity.this);
        initGradData();
        recyclerView.setAdapter(adapter);
        adapter.setOnItemClickListener(newShopAdapter.OnRecyclerViewItemClickListener() {
            @Override
            public voidonItemClick(View view) {
                int position =recyclerView.getChildAdapterPosition(view);
                startActivity(new Intent(Shop_Activity.this,Boutique_Detail.class)
                        .putExtra("goods_id",goodses.get(position).getId())
                        .setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
                );
            }
        });

        imageTitleWhiteBack.setOnClickListener(newView.OnClickListener() {
            @Override
            public voidonClick(View view) {
                finish();
            }
        });

    }

    //商品接口
    
private voidinitGradData() {
        final ProgressDialog mDialog = ProgressDialog.show(this,"获取数据","获取数据中");
        OkGo.post(Contants.DTORE)
                .params("bussinessId",bussiness_id)
                .execute(new StringCallback() {
                    @Override
                    public voidonSuccess(String s, Call call, Response response) {
                        Log.d("code===initGradData", s);
                        mDialog.dismiss();
                        try {
                            JSONObject json = newJSONObject(s);
                            if (s.indexOf("error") != -1) {//有错误
                                
Toast.makeText(Shop_Activity.this, json.getString("error"), Toast.LENGTH_SHORT).show();
                                return;
                            }

                            JSONObject success = json.getJSONObject("success");
                            tvTitleWhite.setText(success.getString("shopName"));
                            tvTitleNum.setText("店铺号:"+success.getString("introduce"));

                            JSONArray info = success.getJSONArray("goodsInfoArray");
                            for (inti =0; i < info.length(); i++) {
                                JSONObject obj = info.getJSONObject(i);
                                ShopGoods shopgoods = newShopGoods();
                                shopgoods.setGoodsname(obj.getString("goodsName"));
                                shopgoods.setId(obj.getString("goodsId"));
                                shopgoods.setImages(obj.getString("img"));
                                shopgoods.setPricenow(obj.getString("priceNow"));
                                goodses.add(shopgoods);
                            }
                            adapter.setGoods(goodses);
                            JSONArray showPage = success.getJSONArray("showPage");
                            for (intj =0; j < showPage.length(); j++){
                                JSONObject page = info.getJSONObject(j);
                                Banners banners = newBanners();
                                //banners.setId(page.getString("id"));
                                
banners.setImg(page.getString("img"));
                                Flybanners.add(banners);
                            }
                            adapter.setFlybanners(Flybanners);
                            adapter.notifyDataSetChanged();

                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public voidonError(Call call, Response response, Exception e) {
                        super.onError(call, response, e);
                        mDialog.dismiss();
                        Toast.makeText(Shop_Activity.this, e.toString(), Toast.LENGTH_LONG).show();
                    }
                });
    }
}

 

Adapter:

package com.example.administrator.a3dmark.adapter;

import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.example.administrator.a3dmark.R;
import com.example.administrator.a3dmark.bean.Banners;
import com.example.administrator.a3dmark.bean.ShopGoods;
import com.recker.flybanner.FlyBanner;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2017/3/8.
 */
public class ShopAdapterextendsRecyclerView.Adapter<RecyclerView.ViewHolder> {
    private Context context;

    //轮播图List<bean>对象
    
privateArrayList<Banners>Flybanners;
    //商品List<bean>对象
    
privateArrayList<ShopGoods>goods;


    //type
    
public static final intTYPE_1= 0xff0111;
    public static final int TYPE_MAIN=0xffffff;

    public ShopAdapter(Context context) {
        this.context= context;
        Flybanners = new ArrayList<>();
        goods = new ArrayList<>();
    }


    public ArrayList<Banners> getFlybanners() {
        return Flybanners;
    }

    public void setFlybanners(ArrayList<Banners> flybanners) {
        Flybanners = flybanners;
    }

    public List<ShopGoods> getGoods() {
        return goods;
    }

    public void setGoods(ArrayList<ShopGoods> goods) {
        this.goods= goods;
    }

    //自定义监听事件
    
public static interfaceOnRecyclerViewItemClickListener {
        void onItemClick(View view);
        //void onItemLongClick(View view);
    
}
    //监听接口
    
privateShopAdapter.OnRecyclerViewItemClickListenermOnItemClickListener=null;
    //监听实现
    
public voidsetOnItemClickListener(ShopAdapter.OnRecyclerViewItemClickListener listener) {
        mOnItemClickListener = listener;
    }



    @Override
    publicRecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {
        switch (viewType){
            case TYPE_1:
                return new ShopAdapter.MyViewHolder1(LayoutInflater.from(parent.getContext()).inflate(R.layout.md_recycle_item_type1, parent, false));
            case TYPE_MAIN:
                View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_shop_typemain, parent,false);
                view.setOnClickListener(newView.OnClickListener() {
                    @Override
                    public voidonClick(View view) {
                        if (mOnItemClickListener!=null) {
                            mOnItemClickListener.onItemClick(view);
                        }
                    }
                });
                return new ShopAdapter.MyViewHolderMain(view);
            default:
                Log.d("error","viewholder is null");
                return null;
        }
    }

    @Override
    public voidonBindViewHolder(RecyclerView.ViewHolder holder,intposition) {
        if (holder instanceof ShopAdapter.MyViewHolder1){
            bindType1((ShopAdapter.MyViewHolder1) holder, position);
        }else if (holderinstanceofShopAdapter.MyViewHolderMain){
            bindTypeMain((ShopAdapter.MyViewHolderMain) holder, position);
        }
    }


    /**
     * Main RecyclerView getItemCount
     *
@return
     
*/
    
@Override
    public intgetItemCount() {
        return getGoods().size();
    }

    @Override
    public intgetItemViewType(intposition) {
        if (position == 0){
            return TYPE_1;
        }else {
            return TYPE_MAIN;
        }
    }


    @Override
    public voidonAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);

        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if(manager instanceof GridLayoutManager) {
            final GridLayoutManager gridManager = ((GridLayoutManager) manager);
            gridManager.setSpanSizeLookup(newGridLayoutManager.SpanSizeLookup() {
                @Override
                public intgetSpanSize(intposition) {
                    int type = getItemViewType(position);
                    switch (type){
                        case TYPE_1:
                            return gridManager.getSpanCount();
                        default:
                            return 1;
                    }
                }
            });
        }
    }


    private void bindType1(ShopAdapter.MyViewHolder1 holder,intposition){
        //轮播图URL
        
ArrayList<String> ImagesUrl =newArrayList();

        if (getFlybanners().size() !=0) {
            for (Banners flyBanners : getFlybanners()) {
                ImagesUrl.add(flyBanners.getImg());
            }
            holder.flyBanner.setImagesUrl(ImagesUrl);
        }

        holder.flyBanner.setOnItemClickListener(newFlyBanner.OnItemClickListener() {
            @Override
            public voidonItemClick(intposition) {
//                Intent intent = new Intent(context, Boutique_Detail.class);
//                intent.putExtra("goods_id", Flybanners.get(position).getId());
//                context.startActivity(intent);
            
}
        });

    }


    private void bindTypeMain(ShopAdapter.MyViewHolderMain holder,intposition){
        Glide.with(context).load(getGoods().get(position).getImages()).fitCenter().placeholder(R.drawable.icon_empty).into(holder.img);
        holder.textprice.setText(getGoods().get(position).getPricenow());
        holder.name.setText(getGoods().get(position).getGoodsname());
        holder.buy.setOnClickListener(newView.OnClickListener() {
            @Override
            public voidonClick(View view) {
                //去试衣间
            
}
        });
    }


    public class MyViewHolder1extendsRecyclerView.ViewHolder {
        public FlyBannerflyBanner;

        public MyViewHolder1(View itemView) {
            super(itemView);
            flyBanner = (FlyBanner) itemView.findViewById(R.id.banner);
        }
    }

    public class MyViewHolderMainextendsRecyclerView.ViewHolder {
        public ImageViewimg;//商品图片
        
publicTextViewname;//商品简介
        
publicTextViewtextprice;//商品价格
        
publicTextViewbuy;//立即购买

        
publicMyViewHolderMain(finalView itemView) {
            super(itemView);
            img = (ImageView) itemView.findViewById(R.id.img);
            name = (TextView) itemView.findViewById(R.id.name);
            textprice = (TextView) itemView.findViewById(R.id.price);
            buy = (Button) itemView.findViewById(R.id.buy);
        }
    }
}

 

 

问题:

在运行项目后,服务器明明返回给了一个如下红色方框标记的商品数据,而却没有显示出来.


细挖代码后发现,是如下代码位置出了问题.

/**
     * Main RecyclerView getItemCount
     *
@return
     
*/
    
@Override
    public intgetItemCount() {
        return getGoods().size();
    }

@Override
    public intgetItemViewType(intposition) {
        if (position == 0){
            return TYPE_1;
        }else {
            return TYPE_MAIN;
        }
    }

当getItemCount的值return的是getGoods().size();

getItemViewTypeposition == 0时加载了另一个布局,

另一个布局作为了getItemCount的一个item而正好

getGoods().size()1,也就是position == 0.

就出现了本该有的一个商品却没有显示,使数据出现丢失的情况.

理所当然getItemCount应该返回returngetGoods().size()+1;

而当我重新运行项目竟然报错 java.lang.IndexOutOfBoundsException(数组下标越界异常)

根据报错位置找到是下划线位置报错:

private void bindTypeMain(ShopAdapter.MyViewHolderMain holder,intposition){
        Glide.with(context).load(getGoods().get(position).getImages()).fitCenter().placeholder(R.drawable.icon_empty).into(holder.img);
        holder.textprice.setText(getGoods().get(position).getPricenow());
        holder.name.setText(getGoods().get(position).getGoodsname());
        holder.buy.setOnClickListener(newView.OnClickListener() {
            @Override
            public voidonClick(View view) {
                //去试衣间
            
}
        });
    }

getGoods().size()+1,position的值就不能再匹配对应的数据,

position是大于getGoods().size().

 

反复调试后:

private void bindTypeMain(ShopAdapter.MyViewHolderMain holder, int position){

        ShopGoods shopGoods = null;

 

        if (position <= getGoods().size()) {

            shopGoods = getGoods().get(position-1);

        }

 

        Glide.with(context).load(shopGoods.getImages()).fitCenter().placeholder(R.drawable.icon_empty).into(holder.img);

        holder.textprice.setText(shopGoods.getPricenow());

        holder.name.setText(shopGoods.getGoodsname());

        holder.buy.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View view) {

                //去试衣间

            }

        });

}

 

这样设置后运行项目,看到界面(喜极而泣)终于显示出来了

好接着开始写点击事件,写好后点击一看toast,靠商品对应的ID不对?

ID出现乱序.靠什么鬼?

再挖代码,挖挖找找....真TMD(别乱猜中文,我反正是想说”他妹的”)不负有心人,再activity点击事件的回调中这样写:

//item的点击事件

        adapter.setOnItemClickListener(new ShopAdapter.OnRecyclerViewItemClickListener() {

            @Override

            public void onItemClick(View view) {

                ShopGoods shopGoods = null;

                int position = recyclerView.getChildAdapterPosition(view);

                if (position <= goodses.size()) {

                    shopGoods = goodses.get(position-1);

                }

                startActivity(new Intent(Shop_Activity.this,Boutique_Detail.class)

                        .putExtra("goods_id",shopGoods.getId())

                        .setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)

                );

            }

        });

 

再次以怀疑人生的心情运行一次项目,打开界面,点击,

wo~~kao~kao~kao~~~

终于搞定!!!

 

(转眼第二天测试!!!)然而程序总是喜欢跟哥开玩笑,当我再次运行项目(日志显示)服务器给我返回了两个商品数据,而测试手机界面确实也有两个商品数量,这里强调:数量”.很是奇怪第二个商品没任何数据?靠靠靠,又开始挖代码~挖啊挖,半小时过去了.然而并没有什么卵用!已接近崩溃了,早一万句草泥马已经飞奔过去.到了接近快一个小时的时候,发现了红色标注的地方:

private void bindTypeMain(ShopAdapter.MyViewHolderMain holder, int position){

        ShopGoods shopGoods = null;

 

        if (position <= getGoods().size()) {

            shopGoods = getGoods().get(position-1);

        }

 

        Glide.with(context).load(shopGoods.getImages()).fitCenter().placeholder(R.drawable.icon_empty).into(holder.img);

        holder.textprice.setText(shopGoods.getPricenow());

        holder.name.setText(shopGoods.getGoodsname());

        holder.buy.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View view) {

                //去试衣间

            }

        });

}

就这个判断,正确判断应该是

if (position <= getGoods().size()+1) {

            shopGoods = getGoods().get(position-1);

        }

 

在黑字标注的地方 +1 欧了运行项目显示正常!点击商品异常退出应用!

TM 什么鬼?

再去点击事件查看  靠靠啊靠~~

 

adapter.setOnItemClickListener(new ShopAdapter.OnRecyclerViewItemClickListener() {

            @Override

            public void onItemClick(View view) {

                ShopGoods shopGoods = null;

                int position = recyclerView.getChildAdapterPosition(view);

                if (position <= goodses.size()+1) {

                    shopGoods = goodses.get(position-1);

                }

                startActivity(new Intent(Shop_Activity.this,Boutique_Detail.class)

                        .putExtra("goods_id",shopGoods.getId())

                        .setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)

                );

            }

        });

 

原来少 +1 ,加上运行项目,显示正常,点击商品跳转正常!

这次才算真正的终于搞定!!!