ViewPager与recycleView同时使用时出现的View加载空白问题

来源:互联网 发布:mac常用软件推荐 2016 编辑:程序博客网 时间:2024/06/05 11:58

一.问题简述:

                ViewPager一般常用于与Fragment结合或者与View结合使用,当布局只有ViewpPager时,View的加载十分的完美,当加入RecycleView时出现了问题,第一张和第二张View可以加载,但是第三张以后是空白View,这不是重点,重点是调试的时候,ViewPager的View的加载又是十分的完美,而运行的时候又会出现加载空白问题,真的是感觉醉醉的。。。


二.问题分析:

经过我的调试排除了以下可能(可能出现空白的原因):

mImageView的问题:序号问题、越界问题、mImageView没获得数据问题(反正就是非常的确定不是mImageView的问题)

adpater的问题:页面被覆盖问题:加载和释放图片时间不合理问题(反正就是非常的确定不是adapter的问题

毕竟没加入RecycleView时一切正常,所以排除了上述可能原因。

1.Fragment的onCreateView()代码,模块ViewPager的adapter代码模块:

public class HomePageFragment extends Fragment {     ...    @Nullable    @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        View view = LayoutInflater.from(getContext()).inflate(R.layout.home_page, container, false);        ButterKnife.bind(this, view);        init();        //ViewPager模块        pointInit();        mMyPagerAdapter = new MyPagerAdapter(mImageViews);        mImagePager.setAdapter(mMyPagerAdapter);        mMyThread.start();//这是开启线程每隔一段时间切花图片线程(不用关注)        viewPagerChange();//ViewPager换页监听器(不用关注)        //RecycleView列表        initRecycleViewList();//获取到RecycleView列表的数据(不用关注)        mMyRecycleViewAdapter = new MyRecycleViewAdapter(getContext(),mLists);        mRecycleView.setAdapter(mMyRecycleViewAdapter);        LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(getContext(),LinearLayoutManager.VERTICAL,false);        mRecycleView.setLayoutManager(mLinearLayoutManager);        return view;    }       class MyPagerAdapter extends PagerAdapter{        private List<ImageView> mImageViews;        public MyPagerAdapter(List<ImageView> mImageViews) {            this.mImageViews = mImageViews;        }        @Override        public int getCount() {            return mImageViews.size();        }        @Override        public boolean isViewFromObject(View view, Object object) {            return view == object;        }        @Override        public Object instantiateItem(ViewGroup container, int position) {            mImageViews.get(position).setScaleType(ImageView.ScaleType.FIT_XY);            container.addView(mImageViews.get(position));            return mImageViews.get(position);        }        @Override        public void destroyItem(ViewGroup container, int position, Object object) {            container.removeView(mImageViews.get(position));        }    }//其他代码...    }

2.recycleView的adapter中的ViewHolder的绑定的代码。

@Overridepublic void onBindViewHolder(final MyViewHolder holder, final int position) {    HttpUtil.sendHttpRequest(mList.get(position).getmTourismImageString(), new HttpCallbackListener() {        @Override        public void onFinish(byte[] picByte) {            Bitmap bitmap = BitmapFactory.decodeByteArray(picByte, 0, picByte.length);            bitmapList.add(bitmap);            holder.mTourismImage.setImageBitmap(bitmap);        }        @Override        public void onError(Exception e) {            e.printStackTrace();        }    });    holder.mTourismName.setText(mList.get(position).getmTourismNameString());    holder.mTravelDistance.setText(mList.get(position).getmTravelDistance());    holder.mDescribe.setText(mList.get(position).getmDescribe());    holder.mPrice.setText(mList.get(position).getmPrice()+"");    holder.mRatingBar.setRating((float) mList.get(position).getmRatingBarProgress());    holder.mTicketsSold.setText(mList.get(position).getmTicketsSoldNum()+"");}

这是recycleView的adapter方法中的绑定ViewHolder方法的代码,大体是通过接口回调机制获取到网络图片的byte数组,再转化为bitmap从而给mTourismImage赋值。

大体说一说接口回调机制:主要是为了解决某些数据获取需要时间,当执行到此步时,使用接口回调机制当获取到数据是再去执行,从而解决未获取到数据时进行该操作

3.回调接口HttpCallbackListener 与获取网络图片Http类(自定义的)的代码:


①回调接口HttpCallbackListener 

public interface HttpCallbackListener {    void onFinish(byte[] picByte);  //获取到数据时执行该方法    void onError(Exception e);      //未获取到数据时执行该方法}
②获取网络图片Http类

public class HttpUtil {    public static byte[] picByte;    public static void sendHttpRequest(final String address,final HttpCallbackListener listener){        new Thread(new Runnable() {            @Override            public void run() {                try {                    Log.d("TAG","请求运行了");                    URL url = new URL(address);                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();                    connection.setRequestMethod("GET");                    connection.setReadTimeout(10000);                    if(connection.getResponseCode() == 200) {                        InputStream is = connection.getInputStream();                        ByteArrayOutputStream bos = new ByteArrayOutputStream();                        byte[] bytes = new byte[1024];                        int length = -1;                        while((length = is.read(bytes)) != -1) {                            bos.write(bytes,0,length);                        }                        picByte = bos.toByteArray();                        is.close();                        bos.close();                        if(listener != null) {                            listener.onFinish(picByte);                        }                    }                } catch (Exception e) {                    if(listener != null) {                        listener.onError(e);                    }                    e.printStackTrace();                }            }        }).start();    }}
运行时,网络图片的却加载出来了,然而viewPager加载View时第三张以后就出现了空白,本人当时感觉recyleView的实现与ViewPager的实现并没有影响呀,为什么会这样???

最后我发现ViewPager与RecycleView的关联只有一个,那就是他们合起来生成了Fragment(注意这里的Fragment所适配的ViewPager是另外一个,不需要与文中的ViewPager联系),给Fragment返回了一个View,也就是说网络图片生成时影响了这个View从而造成了空白的产生。


三.问题解决:

原因分析:通过仔细的观察网络图片的加载过程发现,加载图片是在接口回调机制中实现的,而该接口的方法实现是在Http中开启了一个子线程实现的,说到这里就有人明白了,弄了半天原来是因为接口回调机制中存在子线程,当我们使用接口回调机制时不经意的在子线程中对UI进行了操作(自己以为是主线程!!),其实这点还真不容易发现,毕竟以接口做参数的Http.sendHttpRequest(final String address,final HttpCallbackListener listener)方法是在主线程中实现的,看起来就像是在主线程中对UI进行的操作。

 解决方法:通过Handler发送信息,在Handler中对UI进行操作。源码如下:

public class MyRecycleViewAdapter extends RecyclerView.Adapter<MyViewHolder> {    private MyViewHolder mMyViewHolder;    private LayoutInflater mLayoutInflater;    private Context mContext;    private List<TouristInformation> mList;    public static List<ImageView> mImageViewList;    public static List<Bitmap> bitmapList;    private MyHandler myHandler;    public MyRecycleViewAdapter(Context context, List<TouristInformation> mList) {        this.mContext = context;        this.mList = mList;        bitmapList = new ArrayList<>();        mImageViewList = new ArrayList<>();        myHandler = new MyHandler();        mLayoutInflater = LayoutInflater.from(context);    }    @Override    public MyViewHolder onCreateViewHolder(ViewGroup ag0, int viewType) {        View view = mLayoutInflater.inflate(R.layout.tourist_information, ag0, false);        mMyViewHolder = new MyViewHolder(view);        return mMyViewHolder;    }    @Override    public void onBindViewHolder(final MyViewHolder holder, final int position) {        HttpUtil.sendHttpRequest(mList.get(position).getmTourismImageString(), new HttpCallbackListener() {            @Override            public void onFinish(byte[] picByte) {                Bitmap bitmap = BitmapFactory.decodeByteArray(picByte, 0, picByte.length);                bitmapList.add(bitmap);                myHandler.sendEmptyMessage(0x123);            }            @Override            public void onError(Exception e) {                e.printStackTrace();            }        });        mImageViewList.add(holder.mTourismImage);        holder.mTourismName.setText(mList.get(position).getmTourismNameString());        holder.mTravelDistance.setText(mList.get(position).getmTravelDistance());        holder.mDescribe.setText(mList.get(position).getmDescribe());        holder.mPrice.setText(mList.get(position).getmPrice()+"");        holder.mRatingBar.setRating((float) mList.get(position).getmRatingBarProgress());        holder.mTicketsSold.setText(mList.get(position).getmTicketsSoldNum()+"");    }    @Override    public int getItemCount() {        return mList.size();    }    class MyHandler extends Handler{        @Override        public void handleMessage(Message msg) {            if(msg.what == 0x123) {                mImageViewList.get(0).setImageBitmap(bitmapList.get(0));//我这里只给第一个设置了bitmap            }        }    }}class MyViewHolder extends RecyclerView.ViewHolder {    @BindView(R.id.tourismImage)    ImageView mTourismImage;    @BindView(R.id.touristName)    TextView mTourismName;    @BindView(R.id.travelDistance)    TextView mTravelDistance;    @BindView(R.id.describe)    TextView mDescribe;    @BindView(R.id.price)    TextView mPrice;    @BindView(R.id.ratingBar)    RatingBar mRatingBar;    @BindView(R.id.ticketsSold)    TextView mTicketsSold;    public MyViewHolder(View view) {        super(view);        ButterKnife.bind(this, view);    }}
总结:使用接口回调机制时最好通过Handler对UI进行操作,防止出现莫名其妙的bug。


0 0