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!
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();
}
}
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.
You're not properly inflating your
View
inonCreateViewHolder()
Instead ofyou should use
See this answer for more details on the different
LayoutInflater.inflate()
methods.