Problem analysis

Recently, the waterfall flow style of RecyclerView is used to load and display pictures. Because it was not optimized at the beginning, there will be Item switching, flashing, page hopping and other problems. The experience is very poor, which requires us to optimize and improve.

Think about it for a second. Why is this a problem? Since the size of the image is unknown (especially its height) when it is loaded, Item needs to recalculate its size, which will lead to redrawing. As multiple images will be loaded by waterfall flow at one time, problems such as Item switching, flickering and page hopping will occur. The bottom line is to determine the size of the Item before loading the image, so that the Item does not recalculate its size. How to determine the size of Item? We need to get the size of the image to load, and then set it to the ImageView in the Item.

The solution

There is right StaggeredGridLayoutManager the following Settings:

layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);Copy the code

After the test, the problem of Item switching between left and right was indeed solved, but when sliding, each column still jumped, and there was blank at the top and bottom. Keep optimizing.

Our picture data is obtained by network request. After obtaining data, we will first process it:

@Override
public void onSuccess(List data) {
     DataService.startService(mActivity, data, mSubtype);
 }Copy the code

Start an IntentService and get the Bitmap based on the url of the image, then get the size information of the image:

public class DataService extends IntentService {
    public DataService() {
        super("");
    }

    public static void startService(Context context, List datas, String subtype) {
        Intent intent = new Intent(context, DataService.class);
        intent.putParcelableArrayListExtra("data", (ArrayList) datas);
        intent.putExtra("subtype", subtype);
        context.startService(intent);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent == null) {
            return;
        }

        List datas = intent.getParcelableArrayListExtra("data");
        String subtype = intent.getStringExtra("subtype");
        handleGirlItemData(datas, subtype);
    }

    private void handleGirlItemData(List datas, String subtype) {
        if (datas.size() == 0) {
            EventBus.getDefault().post("finish");
            return;
        }
        for (GirlItemData data : datas) {
            Bitmap bitmap = ImageLoader.load(this, data.getUrl());
            if (bitmap != null) {
                data.setWidth(bitmap.getWidth());
                data.setHeight(bitmap.getHeight());
            }

            data.setSubtype(subtype);
        }
        EventBus.getDefault().post(datas);
    }
}Copy the code

Finally, the size information is wrapped in data and returned via EventBus.

Why IntentService? Because it is executed in the child thread, it automatically ends after execution, and we can only obtain Bitmap by Glide, after all, this process is a time-consuming operation, so the IntentService held by the child thread is easy.

EventBus returns the data from the Adapter.

@Override
protected void convert(RecyclerView.ViewHolder viewHolder, GirlItemData girlItemData) {
        ViewHolder holder = (ViewHolder) viewHolder;
        ScaleImageView imageView = holder.getView(R.id.girl_item_iv);
        imageView.setInitSize(girlItemData.getWidth(), girlItemData.getHeight());
        ImageLoader.load(NiceReadApplication.getContext(), girlItemData.getUrl(), imageView);
    }Copy the code

In fact, ScaleImageView overrides the onMeasure method of ImageView. We set the width and height of the image to ScaleImageView, and then load the image.

The effect

Finally, let’s compare the effect before and after:




Before optimization




The optimized

Source link…