ViewPager與recycleView同時使用時出現的View加載空白問題

一.問題簡述:

                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。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章