Search code examples
javaandroidandroid-recyclerviewpicasso

Images in RecyclerView items are not shown without scrolling first


I do some request from a WordPress page API to get some content and for every content, I get a picture. And I display them on RecyclerView. But they do not show without doing first a scroll of RecyclerView then they start to show one by one.

Here is the NewsActivity

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_news);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        Window w = getWindow();
        w.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        w.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }

    back_button = findViewById(R.id.toolbar_back_button);
    back_button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            onBackPressed();
        }
    });

    toolbarTxt = findViewById(R.id.tolbar_text_view);
    toolbarTxt.setText("News");

    recyclerView = findViewById(R.id.news_recyclerview);

    RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(mAdapter);
    recyclerView.setHasFixedSize(true);

    ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);

    if(connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState() == NetworkInfo.State.CONNECTED ||
            connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState() == NetworkInfo.State.CONNECTED) {
            merrLajmet();
    } else {
        Toast.makeText(this, "You do not have internet connection", Toast.LENGTH_SHORT).show();
    }

}

Here's how I get the contents.

public void merrLajmet(){

    Uri baseUri = Uri.parse(NEWS_REQUEST_URL);
    Uri.Builder uriBuilder = baseUri.buildUpon();

    JsonArrayRequest jsonObjectRequest = new JsonArrayRequest(
            Request.Method.GET, uriBuilder.toString(), null, new Response.Listener<JSONArray>() {

        @Override
        public void onResponse(JSONArray response) {
            listLajmet = Query.shfaqLajmet(response);

            for (Lajmi lajmi : listLajmet) {
                merrFoton(lajmi);
            }
            mAdapter.setLajmi(listLajmet);
        }
    }, new Response.ErrorListener() {

        @Override
        public void onErrorResponse(VolleyError error) {
            // Error
        }
    });

    if (listLajmet.isEmpty()) {
        MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest);
    }
}

And the get the photo of from specific content.

public void merrFoton(final Lajmi lajmi) {

    Uri baseUri = Uri.parse(IMAGE_REQUEST_URL);
    Uri.Builder uriBuilder = baseUri.buildUpon();
    uriBuilder.appendPath(String.valueOf(lajmi.getFeatureMedia()));

    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(
            Request.Method.GET, uriBuilder.toString(), null, new Response.Listener<JSONObject>() {

        @Override
        public void onResponse(JSONObject response) {
            String imageUrl = Query.shfaqFoton(response);
            if (imageUrl == ""){
                imageUrl = String.valueOf(R.drawable.news_photo1);
            }

            lajmi.setImage(imageUrl);
            //mAdapter.setLajmi(listLajmet);
        }
    }, new Response.ErrorListener() {

        @Override
        public void onErrorResponse(VolleyError error) {
            //Toast.makeText(NewsActivity.this, "Nuk ka te image " +
                    //error.networkResponse.toString(), Toast.LENGTH_SHORT).show();
        }
    });

    MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest);
}

And finally, here's my adapter class.

public class LajmiAdapter extends RecyclerView.Adapter<LajmiAdapter.MyViewHolder>{

    private List<Lajmi> mLajmiList = new ArrayList<>();
    private Context ctx;

    public LajmiAdapter(Context ctx) {
        this.ctx = ctx;
    }

    public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

        TextView mTitle, mCategory;
        ImageView mImage,mColor;

        public MyViewHolder(View itemView) {
            super(itemView);

            itemView.setOnClickListener(this);

            mTitle = itemView.findViewById(R.id.news_text_view_titulli);
            mCategory = itemView.findViewById(R.id.news_text_view_kategoria);

            mImage = itemView.findViewById(R.id.news_image_main);
            mColor = itemView.findViewById(R.id.news_image_small);
        }

        @Override
        public void onClick(View v) {

            int position = getAdapterPosition();

            Lajmi lajmi = mLajmiList.get(position);

            Intent intent = new Intent(ctx, SinglenewsActivity.class);

            intent.putExtra("title", lajmi.getTitle());
            intent.putExtra("category", lajmi.getCategory());
            intent.putExtra("image", lajmi.getImage());
            intent.putExtra("color",lajmi.getColor());
            intent.putExtra("description",lajmi.getDescription());

            ctx.startActivity(intent);
        }
    }

    @Override
    public LajmiAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View itemView;
        itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item, parent, false);
        return new LajmiAdapter.MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(LajmiAdapter.MyViewHolder holder, int position) {

        Lajmi lajmi = mLajmiList.get(position);
        holder.mTitle.setText(lajmi.getTitle());

        Picasso.get()
                .load(lajmi.getImage())
                .resize(400, 300)
                .onlyScaleDown()
                .into(holder.mImage);
    }

    public void setLajmi(List<Lajmi> lajmiList) {
        mLajmiList = lajmiList;
        notifyDataSetChanged();
    }

    @Override
    public int getItemCount() {
        if(mLajmiList == null)
            return 0;
        else
            return mLajmiList.size();
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public int getItemViewType(int position) {
        return position;
    }
}

When I open NewsActivity, I expect all the images to show on the item of RecyclerView without doing a scroll first.


Solution

  • When you are scrolling the list, it gets the updated items and hence gets the updated list of images which you fetched from your server. I think you are missing a notifyDataSetChanged call here.

    @Override
    public void onResponse(JSONObject response) {
        String imageUrl = Query.shfaqFoton(response);
        if (imageUrl == ""){
            imageUrl = String.valueOf(R.drawable.news_photo1);
        }
    
        lajmi.setImage(imageUrl);
        // Add the notifyDataSetChanged here
        mAdapter.notifyDataSetChanged();
    }
    

    However, in this case, as you are fetching your images one by one, each time you are fetching an image, the adapter will be notified and hence the RecyclerView will be reloaded accordingly. Its kind of annoying in the case when you are scrolling through items and the list gets to the top each time a new image is fetched from the server as you are calling notifyDataSetChanged() each time.

    I would like to suggest implementing the whole image fetching a bit differently. Get the count of the images to be downloaded first. Then get all the images URLs and save them in your list. Then call notifyDataSetChanged once you are finished downloading all the image URLs.

    Hope that helps!