Hot questions for Using Glide in android adapter

Top 10 Java Open Source / Glide / android adapter

Question:

I have added some manually icons to drawable which for some manually data it have to take the drawable and if a icon is not in drawable then take it from the Glide.

I tried something like till now but only it is getting the icons from drawable.

I want to check if icon exists at drawable take from there and if for an url the icon is not in drawable then go at another statement and take it from Glide.

Below is my code. The resID is always 0

String imageUrl = BASE_URL + arrayList.get(position).getSearchUrl() + "&size=32";

            int resID = context.getResources().getIdentifier("icon", "drawable",context.getPackageName());
            if (resID == 0) {
                Log.d("TAG", "onBindViewHolder: " + resID);
                viewHolder.tvIcon.setImageResource(arrayList.get(position).getIcon());
            } else {
                Log.d("TAG", "onBindViewHolder: Glide" + resID);
                Glide.with(context)
                        .load(imageUrl)
                        .apply(requestOptions
                                .placeholder(R.drawable.default_favicon)
                                .diskCacheStrategy(DiskCacheStrategy.ALL)
                                .fitCenter())
                        .into(viewHolder.tvIcon);
            }

Answer:

You need to pass your arrayList.get(position).getIcon() instead of "icon" in context.getResources().getIdentifier()

Also read how getIdentifier() works

Return a resource identifier for the given resource name. A fully qualified resource name is of the form "package:type/entry".

Returns : int The associated resource identifier. Returns 0 if no such resource was found. (0 is not a valid resource ID.)

Try this way

    int resID = context.getResources().getIdentifier(String.valueOf(arrayList.get(position).getIcon()), "drawable",context.getPackageName()); "drawable",context.getPackageName());
    // if resID == 0 means the icon is not available in drawable folder
    // so it will load icon from url using Glide
    if (resID == 0) {
        Log.d("TAG", "onBindViewHolder: Glide" + resID);
        Glide.with(context)
                .load(imageUrl)
                .apply(requestOptions
                        .placeholder(R.drawable.default_favicon)
                        .diskCacheStrategy(DiskCacheStrategy.ALL)
                        .fitCenter())
                .into(viewHolder.tvIcon);

    }
    // if resID != 0 means the icon is  available in drawable folder
    // so it will load icon from drawable folder
    else {
        Log.d("TAG", "onBindViewHolder: " + resID);
        viewHolder.tvIcon.setImageResource(resID);
    } 

Question:

I am fetching data about some pokemon and want to also grab their images and glide in the same activity. The images can not be fetched directly, I have to get the url to images from the pokemon url object.

I mean I have to first fetch pokemons with https://pokeapi.co/api/v2/limit?=10 from the response I get each pokemon images url by id https://pokeapi.co/api/v2/pokemon/1

I was able to do this successfully in my adapter but wondering if it is best practice as I am afraid of it lagging if the number is larger

Adapter is below
class ApiAdapter (internal var activity: MainActivity):RecyclerView.Adapter<ApiAdapter.ApiViewHolder>(){

    private val queue = Volley.newRequestQueue(activity)


    init{

        loadData()
    }
    val dataInstance = ArrayList<DataClass>()
    private fun loadData(){

        val url = "https://pokeapi.co/api/v2/pokemon?limit=5"

        val jsonObjectRequest = JsonObjectRequest(
            Request.Method.GET, url, null,
            Response.Listener { response ->

                try {
                    val jsonArray = response.getJSONArray("results")
                    lateinit var name:String
                    lateinit var pokeUrl: String
                    lateinit var jsonCities: JSONArray
                    for(i in 0 until jsonArray.length()){
                        val jsonObject = jsonArray.getJSONObject(i)
                        name = jsonObject.getString("name")
                        pokeUrl = jsonObject.getString("url")


                        dataInstance.add(DataClass(name, pokeUrl))

                    }


                    notifyDataSetChanged()

                }
                catch (error: JSONException){
                    error.printStackTrace()
                }


            },
            Response.ErrorListener { error ->
                // TODO: Handle error

                Log.e("Api", "error: $error")

            }

        )
        // Add the request to the RequestQueue.
        queue.add(jsonObjectRequest)
    }




    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ApiViewHolder{
        val layout = LayoutInflater.from(parent.context).inflate(R.layout.data_row, parent, false)
        return ApiViewHolder(layout)
    }

    override fun onBindViewHolder(holder:ApiViewHolder, position:Int){

        val current = dataInstance.get(position)

        holder.name.text = current.name


        fun loadImageData(){

            val url = current.url

            val jsonObjectRequest = JsonObjectRequest(
                Request.Method.GET, url, null,
                Response.Listener { response ->

                    try {
                        val jsonResponse = response.getJSONObject("sprites")
                        val picUrl = jsonResponse.optString("front_default")

                        Glide.with(activity).load(picUrl).into(holder.image)

//                        notifyDataSetChanged()
                        Toast.makeText(activity, "res: $picUrl", Toast.LENGTH_LONG).show()
                    }
                    catch (error: JSONException){
                        error.printStackTrace()
                    }

                },
                Response.ErrorListener { error ->


                    Log.e("Api", "error: $error")

                }

            )
            // Add the request to the RequestQueue.
            queue.add(jsonObjectRequest)
        }

        loadImageData()


    }

    override fun getItemCount(): Int {
        return dataInstance.size
    }

    class ApiViewHolder(dataView: View): RecyclerView.ViewHolder(dataView){


        internal var name = dataView.findViewById<TextView>(R.id.name)
        internal var image = dataView.findViewById<ImageView>(R.id.pokemon_image)

    }
}

Perhaps there is a better way to get around this. Your advice will be highly appreciated


Answer:

A few general notes and suggestions:

  • You are triggering an API call from onBindViewHolder. This will trigger it every time the view is bound after recycling. You will need to either pull it out of the adapter, or implement some caching. In general, never put API within an Adapter without caching, it's a recipe for disaster.
  • You are calling notifyDatasetChanged() from within the adapter. This is also generally considered bad practice. The workflow should be the adapter takes in only view state data, then applies that view state data to it's children via an external notifyDatasetChanged.

For your situation specifically though, you do not really need an extra API call at all to get the pokemon's image. All pokemon from the PokeAPI use the same image URL format, for example: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png

If you simply replace the number 4 in that URL with the ID of the pokemon, you can avoid having to make that extra API call and just pass that manual URL direct to the adapter. Then grab the full pokemon object in the full details activity or fragment. Just an idea.

Question:

public class MyAdapter_home extends RecyclerView.Adapter<MyAdapter_home.MyAdapter_HomeViewHolder> {


private List<Datum> data;
private List<Datum2>data2;
private int rowLayout;
private Context context;
PopupMenu popupMenu ;


public MyAdapter_home(List<Datum> data, int rowLayout, Context context) {
    this.data = data;
    this.rowLayout = rowLayout;
    this.context = context;
}



@Override
public MyAdapter_HomeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_item_home, parent, false);
    return new MyAdapter_HomeViewHolder(view);
}

@Override
public void onBindViewHolder(final MyAdapter_HomeViewHolder holder, final int position) {



    holder.userNameTV.setText(data.get(position).getUserInfo().getFullName());
    holder.msgBodyTV.setText(data.get(position).getBody());
    holder.originator_iD.setText(data.get(position).getUserInfo().getId().toString());
    holder.imV.setImageURI(Uri.parse(Uri.parse(data.get(position).getUserInfo().getAvatar()).getPath()));
    holder.owner_type_ET.setText("1");
    holder.subject_ET.setText("Message");




    holder.mCardView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            Intent intent = new Intent(view.getContext(), Single_Message.class);
            intent.putExtra("ORIGINATOR_ID", holder.originator_iD.getText().toString());
            intent.putExtra("OWNER_TYPE", holder.owner_type_ET.getText().toString());
            intent.putExtra("SUBJECT", holder.subject_ET.getText().toString());
            intent.putExtra("USERNAME", holder.userNameTV.getText().toString());
            view.getContext().startActivity(intent);


        }
    });

    holder.mCardView.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(final View view) {

            popupMenu = new PopupMenu(view.getContext(), view);
            popupMenu.setOnDismissListener(new PopupMenu.OnDismissListener() {
                @Override
                public void onDismiss(PopupMenu menu) {

                }
            });
            popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {
                    switch (item.getItemId()) {
                        case R.id.lang_java:
                            Intent intent = view.getContext().getPackageManager().getLaunchIntentForPackage("com.freemig.social");
                            if (intent != null) {
                                // We found the activity now start the activity
                                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                view.getContext().startActivity(intent);
                            } else {
                                // Bring user to the market or let them choose an app?
                                intent = new Intent(Intent.ACTION_VIEW);
                                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                intent.setData(Uri.parse("market://details?id=" + "com.freemig.social"));
                                view.getContext().startActivity(intent);
                            }
                            return true;
                        case R.id.lang_android:
                            Toast.makeText(view.getContext(), "Mute Conversation clicked",
                                    Toast.LENGTH_SHORT).show();
                            return true;
                        case R.id.lang_python:
                            Toast.makeText(view.getContext(), "Remove User clicked",
                                    Toast.LENGTH_SHORT).show();
                            return true;
                        case R.id.lang_ruby:
                            Toast.makeText(view.getContext(), "Block User clicked",
                                    Toast.LENGTH_SHORT).show();
                            return true;
                    }
                    return false;
                }
            });
            popupMenu.inflate(R.menu.popup_home_long_click);
            popupMenu.show();
            return false;
        }
    });
}

@Override
public int getItemCount() {
    return data.size();
}

public static class MyAdapter_HomeViewHolder extends RecyclerView.ViewHolder {

    TextView userNameTV;
    TextView msgBodyTV;
    CardView mCardView;
    TextView originator_iD;
    ImageView imV;
    String s;

    ConversationAPIService conversationAPIService;
    EditText owner_type_ET, subject_ET;


    public MyAdapter_HomeViewHolder(View itemView) {
        super(itemView);
        userNameTV = (TextView) itemView.findViewById(R.id.username);
        msgBodyTV = itemView.findViewById(R.id.msgbody);
        mCardView = (CardView) itemView.findViewById(R.id.card_view);
        originator_iD = itemView.findViewById(R.id.frIdET);
        imV = itemView.findViewById(R.id.iv_image);
        owner_type_ET = (EditText) itemView.findViewById(R.id.owner_typeET);
        subject_ET = (EditText) itemView.findViewById(R.id.subjectET);
    }
}
}

This is my adapter class for a recyclerView. I want to show image avatar from here. I don't understand how to it. What I tried -

  1. Glide documentation but not understand
  2. In stackoverflow everyone use static URL that previously defined.But my url is generating randomly and how to use that URL
  3. I tried to use bitmap. but can't figure it out. How to do it?

Answer:

You can log like this,

Uri uri = Uri.parse(Uri.parse(data.get(position).getUserInfo().getAvatar()).getPath());
Glide.with(context).load(uri).into(holder.imV);