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

本文详细介绍了在使用ViewPager与RecyclerView结合时遇到的视图加载空白问题,通过排查排除了ImageView、Adapter等可能原因,最终发现问题是由于在子线程中进行UI操作导致的。解决方案是通过Handler在主线程中处理UI更新,确保正确显示网络图片。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.问题简述:

                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的绑定的代码。

@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);
            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。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值