Why are my “posts” loading in different sizes in a

2019-03-02 13:05发布

Okay, this is how my recyclerview is showing my "posts". Can anyone tell me why? I will post source code as well. I have tried changing some of the code with no success. Also, when I scroll through my RecyclerView, some of them resize to smaller or larger sizes. Any and all help is appreciated!

This is what my RecyclerView looks like when it loads. Also, when I scroll, some of the resize to other smaller or larger sizes.

fragment_home.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#fff" />

</LinearLayout>

list_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:id="@+id/listItemLayout">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageButton
            android:id="@+id/yesButton"
            android:layout_width="0dp"
            android:layout_height="40dp"
            android:layout_weight="1"
            android:background="#00FF00" />

        <ImageButton
            android:id="@+id/noButton"
            android:layout_width="0dp"
            android:layout_height="40dp"
            android:layout_weight="1"
            android:background="#FF0000" />

    </LinearLayout>

    <com.android.volley.toolbox.NetworkImageView
        android:id="@+id/image_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@drawable/placeholder" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:background="#509f9f9f"
        android:orientation="horizontal">

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="8"
            android:orientation="horizontal">

            <com.android.volley.toolbox.NetworkImageView
                android:id="@+id/thumbnail"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:scaleType="fitXY"
                android:src="@drawable/placeholder" />

            <TextView
                android:id="@+id/pUsername"
                android:layout_marginLeft="5dp"
                android:layout_marginStart="5dp"
                android:gravity="center_vertical"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:text="username" />

        </LinearLayout>

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="horizontal">

            <ImageButton
                android:id="@+id/postMenu"
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:background="#000"/>

        </LinearLayout>

    </LinearLayout>

</LinearLayout>

LruBitmapCache.java:

public class LruBitmapCache extends LruCache<String, Bitmap> implements ImageCache {

    public LruBitmapCache(int maxSize) {
        super(maxSize);
    }

    public LruBitmapCache(Context context) {
        this(getCacheSize(context));
    }

    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight();
    }

    @Override
    public Bitmap getBitmap(String url) {
        return get(url);
    }

    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        put(url, bitmap);
    }

    public static int getCacheSize(Context context) {
        final DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        final int screenWidth = displayMetrics.widthPixels;
        final int screenHeight = displayMetrics.heightPixels;
        final int screenBytes = screenWidth * screenHeight * 4;

        return screenBytes * 3;
    }

}

MyRecyclerAdapter.java:

public class MyRecyclerAdapter extends RecyclerView.Adapter<ListRowViewHolder> {

    private List<ListItems> listItemsList;
    private Context mContext;
    private ImageLoader mImageLoader;

    private int focusedItem = 0;

    public MyRecyclerAdapter(Context context, List<ListItems> listItemsList) {
        this.mContext = context;
        this.listItemsList = listItemsList;
    }

    @Override
    public ListRowViewHolder onCreateViewHolder(final ViewGroup viewGroup, int position) {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item, null);
        ListRowViewHolder holder = new ListRowViewHolder(v);

        return holder;
    }

    @Override
    public void onBindViewHolder(final ListRowViewHolder listRowViewHolder, int position) {
        ListItems listItems = listItemsList.get(position);
        listRowViewHolder.itemView.setSelected(focusedItem == position);

        listRowViewHolder.getLayoutPosition();

        mImageLoader = MySingleton.getInstance(mContext).getImageLoader();

        listRowViewHolder.thumbnail.setImageUrl(listItems.getProfilePicture(), mImageLoader);
        listRowViewHolder.thumbnail.setDefaultImageResId(R.drawable.placeholder);

        listRowViewHolder.image_1.setImageUrl(listItems.getImage_1(), mImageLoader);
        listRowViewHolder.image_1.setDefaultImageResId(R.drawable.placeholder);

        listRowViewHolder.username.setText(Html.fromHtml(listItems.getUsername()));
    }

    public void clearAdapter() {
        listItemsList.clear();
        notifyDataSetChanged();
    }

    @Override
    public int getItemCount() {
        return (null != listItemsList ? listItemsList.size() : 0);
    }

}

MySingleton.java:

public class MySingleton {

    private static MySingleton mInstance;
    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;
    private static Context mContext;

    private MySingleton(Context context) {
        mContext = context;
        mRequestQueue = getRequestQueue();

        mImageLoader = new ImageLoader(mRequestQueue, new LruBitmapCache(LruBitmapCache.getCacheSize(mContext)));
    }

    public static synchronized MySingleton getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new MySingleton(context);
        }
        return mInstance;
    }

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(mContext.getApplicationContext());
        }
        return mRequestQueue;
    }

    public <T> void addToRequestQueue(Request<T> req) {
        getRequestQueue().add(req);
    }

    public ImageLoader getImageLoader() {
        return mImageLoader;
    }

}

ListRowViewHolder.java:

public class ListRowViewHolder extends RecyclerView.ViewHolder {

    protected NetworkImageView thumbnail;
    protected NetworkImageView image_1;
    protected ImageButton yes;
    protected ImageButton no;
    protected TextView username;
    protected LinearLayout recLayout;

    public ListRowViewHolder(View view) {
        super(view);
        this.thumbnail = (NetworkImageView) view.findViewById(R.id.thumbnail);
        this.image_1 = (NetworkImageView) view.findViewById(R.id.image_1);
        this.yes = (ImageButton) view.findViewById(R.id.yesButton);
        this.no = (ImageButton) view.findViewById(R.id.noButton);
        this.username = (TextView) view.findViewById(R.id.pUsername);
        this.recLayout = (LinearLayout) view.findViewById(R.id.listItemLayout);
        view.setClickable(true);
    }

}

FragmentHome.java:

public class FragmentHome extends Fragment {

    private final String postsUrl = "http://www.example.com/fetch_posts.php";

    private ProgressDialog progressDialog;

    private static final String TAG = "RecyclerViewExample";
    private List<ListItems> listItemsList = new ArrayList<>();

    private RecyclerView mRecyclerView;
    private MyRecyclerAdapter adapter;

    public FragmentHome() {

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (container == null) {
            return null;
        }
        View view = inflater.inflate(R.layout.fragment_home, container, false);

        mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);

        mRecyclerView.addItemDecoration(
                new HorizontalDividerItemDecoration.Builder(getActivity())
                        .color(Color.BLACK)
                        .build());

        final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
        mRecyclerView.setLayoutManager(linearLayoutManager);

        updateFeed();

        return view;
    }

    public void updateFeed() {
        showPD();

        adapter = new MyRecyclerAdapter(getActivity(), listItemsList);
        mRecyclerView.setAdapter(adapter);

        RequestQueue request = Volley.newRequestQueue(getActivity());

        adapter.clearAdapter();

        JsonArrayRequest req = new JsonArrayRequest(postsUrl, new Response.Listener<JSONArray>() {
            @Override
            public void onResponse(JSONArray response) {
                Log.d(TAG, response.toString());

                try {
                    for (int i = 0; i < response.length(); i++) {
                        JSONObject post = (JSONObject) response.get(i);

                        ListItems item = new ListItems();
                        item.setImage_1(post.getString("image_1"));
                        item.setUsername(post.getString("username"));
                        item.setProfilePicture(post.getString("image_1"));
                        listItemsList.add(item);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                    Toast.makeText(getActivity(), "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
                }
                adapter.notifyDataSetChanged();
                hidePD();
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                VolleyLog.d(TAG, "Error: " + error.getMessage());
                hidePD();
                Toast.makeText(getActivity(), "Volley Error: " + error.getMessage(), Toast.LENGTH_LONG).show();
            }
        });
        request.add(req);
    }

    private void showPD() {
        if (progressDialog == null) {
            progressDialog = new ProgressDialog(getActivity());
            progressDialog.setMessage("Loading...");
            progressDialog.setCancelable(false);
            progressDialog.setCanceledOnTouchOutside(false);
            progressDialog.show();
        }
    }

    private void hidePD() {
        if (progressDialog != null) {
            progressDialog.dismiss();
            progressDialog = null;
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        hidePD();
    }

}

2条回答
兄弟一词,经得起流年.
2楼-- · 2019-03-02 13:19

Regarding the question "Also, when I scroll through my RecyclerView, some of them resize to smaller or larger sizes." :
As the name says 'Recycler', it reuses the ViewHolder objects. When you scroll down/up and when the view (holder) goes off the screen, the view object wont get destroyed but it will be used again (recycled) to hold/represent another data set that is becoming visible.

If data set at the new position that is becoming visible does not have data (may be null or empty etc) which in your case is profile_pic/thumbnail, the RecyclerView will use the the data of the recycled holder which is used to represent this position. That is why when you have many data sets than that screen can hold and when you scroll up/down, you see that everytime you scroll a view (make it visible and invisible), it will show different data depending on the (recycled)holder it uses at the moment. If your profile pics are different than just cat pic for every view, then you can witness this effect clearly.

What you've to do is that before you set the data (image, text etc) to a view, you can better reset it first. If it is image you can clear/reset as suggested here https://stackoverflow.com/a/8243184/3209739. Or you can have placeholder image or make it transparent whatever. Then this problem should not occur.
I think for same reason, it shows the different sized images (thumb and profile pic).

Try resetting the views before you set to your actual data. Always better to follow this when RecyclerView is used.

Why do you want to have your own caching code ? Why can not you use Picasso image loader, Universal Image Loader or something that suits your requirement. Take a look here to know the different image loaders Picasso v/s Imageloader v/s Fresco vs Glide.

查看更多
放我归山
3楼-- · 2019-03-02 13:20

You're not properly inflating your View in onCreateViewHolder() Instead of

View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item, null);

you should use

View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item, viewGroup, false);

See this answer for more details on the different LayoutInflater.inflate() methods.

查看更多
登录 后发表回答