0

I have a listview in which I assign an imageview per each item on the list. The thing is, I already did that the app will load only 10 rows at a time and items add up when the user scroll, I enable hardware acceleration, I compressed and resized the pictures to tiny sizes, but no matter what I did the listview is still laggy.

I tried to look up online and I couldn't realize how to implement anything on my scenario, or what ever else that could speed up the process. Here is my BaseAdapter:

  public View getView(int position, View convertView, ViewGroup parent) {

    LayoutInflater layoutInflater = ((Activity)context).getLayoutInflater();
    View view = layoutInflater.inflate(R.layout.library_layout, parent, false);
    view.setBackgroundColor(Color.parseColor("#FFFFFF"));
    final GamesLibrary gl = objects.get(position);
    TextView title = (TextView)view.findViewById(R.id.titleId);
    TextView excerpt = (TextView)view.findViewById(R.id.excerptId);
    ImageView imageView = view.findViewById(R.id.listViewImageView);
    ImageButton commBt = view.findViewById(R.id.goToCommLv);
    final TextView author = view.findViewById(R.id.authorId);
    final CheckBox likeBox = view.findViewById(R.id.likeIconLv);
    ImageButton sharingButton = view.findViewById(R.id.shareButtonLv);
    final SharedPreferences sp;
    sp=context.getSharedPreferences("likes", 0);
    final SharedPreferences.Editor editor = sp.edit();
    String[] allFavsIds =SpIdstoArr(sp.getString("ids", ""));
    final String id = String.valueOf(gl.getId());
    SharedPreferences sp4 =context.getSharedPreferences("LocalLogInData", 0);
    String uname= sp4.getString("Uname","dsufhsiudhfsdef");

    if(gl.getTitle().contains(uname))
    {
        Log.d("aw12","aw12");
        commBt.setClickable(false);
        commBt.setEnabled(false);
        commBt.setAlpha(0.5f);
    }






    title.setText(gl.getTitle());
    Log.d("glgl",gl.getTitle());
    excerpt.setText(gl.getExcerpt());
    author.setText("by " + gl.getAuthor());
    String FirstTag = "";
    try {
        FirstTag = gl.getTags()[0];
    }
    catch (Exception e)
    {
        Log.d("gameLibAdap", e.toString());}
    if(FirstTag != null) {
        if (FirstTag.equals("מערך אכפתיות"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.care));
        else if (FirstTag.equals("מערך חגים"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.holidays));
        else if (FirstTag.equals("מערך חשיבה אחרת"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.thinkdifferent2));
        else if (FirstTag.equals("מערך גיבוש והנאה"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.fun));
        else if (FirstTag.equals("מערך חברות"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.friendship));
        else if (FirstTag.equals("מערך סובלנות"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.tolerance));
        else if (FirstTag.equals("מערך אחריות"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.responsibility));
        else if (FirstTag.equals("פעולות ללא מערך"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.logo1));
        else if (FirstTag.equals("מערך שיתוף פעולה"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.teamwork));
        else if (FirstTag.equals("מערך חוץ וטבע"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.nature));
        else if (FirstTag.equals("מערך מנהיגות"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.leading));
        else if (FirstTag.equals("מערך סבלנות"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.patience));
        else if (FirstTag.equals("מערך יוזמה"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.yozma));
        else if (FirstTag.equals("מערך שוויון"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.equlity));
        else if (FirstTag.equals("מערך הישגים אישיים"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.personalachivements));
        else if (FirstTag.equals("מערך עידן מודרני"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.modern));
        else if (FirstTag.equals("ערך שוויון"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.equlity));
        else if (FirstTag.equals("ערך ישראליות/ ציונות"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.zionism));
        else if (FirstTag.equals("מערך מודעות"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.awareness2));
        else if (FirstTag.equals("מערך חשיבה אחרת"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.thinkdifferent2));
        else if (FirstTag.equals("מערך הישגים אישיים"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.personalachivements));
        else if (FirstTag.equals("ערך קבלת השונה"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.acceptance));
        else if (FirstTag.equals("אלכוהול וסמים"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.alcohol));
        else if (FirstTag.equals("ללא הכנה מראש"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.unprepared));
        else if (FirstTag.equals("מערך היכרות"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.meeting));
        else if (FirstTag.equals("מערך הדרכה"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.guiding));
        else if (FirstTag.equals("מערך יום הזיכרון"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.memorial));
        else if (FirstTag.equals("מערך יום הזיכרון לשואה"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.holocaustmemorial));
        else if (FirstTag.equals("מערך שינוי"))
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.change));
        else
            imageView.setImageDrawable(context.getApplicationContext().getResources().getDrawable(R.drawable.logo1));

    }


    likeBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

        @Override
        public void onCheckedChanged(CompoundButton buttonView,boolean isChecked)
        {

            if(isChecked)
            {
                String value = sp.getString("ids", "");
                Log.d("ids", value);
                value += "," + id + "/";
                editor.putString("ids", value).commit();
                Log.d("ids", value);
                Log.d("ids", sp.getString("ids", ""));
            }
            if(!isChecked)
            {
                String value = sp.getString("ids", "");
                String replaceString= value.replace("," + id + "/", "");
                editor.putString("ids", replaceString).commit();
                Log.d("ids2", sp.getString("ids", ""));
            }
            Log.d("ids3", sp.getString("ids", ""));

        }
    });
    if (checkMatch(String.valueOf(id),allFavsIds))
        likeBox.setChecked(true);
    else
        likeBox.setChecked(false);

    commBt.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            Intent in = new Intent(context,CommentActivity.class);
            in.putExtra("Json", gl.getCommJson());
            in.putExtra("pId", String.valueOf(id));
            in.putExtra("cats", gl.getCategories());
            context.startActivity(in);
        }
    });



    sharingButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            shareIt(gl.getUrl(),gl.getTitle());
        }
    });






    return view;}

I will explain so my code won't be confusing, I simply assign texts and imageviews to each item by its properties, there is also a like button, and a commentbutton that take the user to the comments page. Do you guys have any idea of what can I do?

I am a beginner.

Update: code of check match:

public static boolean checkMatch(String id, String[] favIds)
{
    boolean b = false;
    for (int i = 0; i <favIds.length; i++)
    {
        if(favIds[i].equals(id)) {
            b = true;
            favIds[i] = "";
        }
    }
    return b;
}

New Code - ViewHlder:

class MyviewHolder
{
    TextView title, excerpt,author;
    ImageView imageView, profilepic;
    ImageButton commBt,sharingButton;
    CheckBox likeBox;
    MyviewHolder(View v)
    {
         title = (TextView)v.findViewById(R.id.titleId);
         excerpt = (TextView)v.findViewById(R.id.excerptId);
         imageView =(ImageView) v.findViewById(R.id.listViewImageView);
         commBt = (ImageButton) v.findViewById(R.id.goToCommLv);
          author =(TextView) v.findViewById(R.id.authorId);
          likeBox = (CheckBox) v.findViewById(R.id.likeIconLv);
         sharingButton = (ImageButton) v.findViewById(R.id.shareButtonLv);
         profilepic = v.findViewById(R.id.saProfilePic);
         profilepic.setVisibility(View.VISIBLE);
    }

}

New Code - getView:

@Override
public View getView(int position, View convertView, ViewGroup parent)
{



    View view =convertView;
    MyviewHolder viewHolder=null;

    if(view==null)
    {
        LayoutInflater layoutInflater = ((Activity)context).getLayoutInflater();
        view = layoutInflater.inflate(R.layout.library_layout, parent, false);
        viewHolder=new MyviewHolder(view);
        view.setTag(viewHolder);
        Log.d("gg22","creating");
        view.setBackgroundColor(Color.parseColor("#FFFFFF"));
    }
    else
    {
        viewHolder = (MyviewHolder) view.getTag();
        Log.d("gg22","recycling");
    }



    final GamesLibrary gl = objects.get(position);

    viewHolder.title.setText(gl.getTitle());
    viewHolder.excerpt.setText(gl.getExcerpt());
    viewHolder.imageView.setImageResource(R.drawable.logo1);
    viewHolder.author.setText("by " + gl.getAuthor());



    final SharedPreferences sp;
    sp=context.getSharedPreferences("likes", 0);
    final SharedPreferences.Editor editor = sp.edit();
    String[] allFavsIds =SpIdstoArr(sp.getString("ids", ""));
    final String id = String.valueOf(gl.getId());

    if(gl.getTitle().contains(UName()))
    {
        viewHolder.commBt.setClickable(false);
        viewHolder.commBt.setEnabled(false);
        viewHolder.commBt.setAlpha(0.5f);
    }


    int imageviewRID;






    String FirstTag = "";
    try {
        FirstTag = gl.getTags()[0];
    }
    catch (Exception e)
    {
        Log.d("gameLibAdap", e.toString());}

    if(FirstTag != null) {
        if (FirstTag.equals("מערך אכפתיות"))
            imageviewRID=R.drawable.care;
        else if (FirstTag.equals("מערך חגים"))
            imageviewRID=R.drawable.holidays;
        else if (FirstTag.equals("מערך חשיבה אחרת"))
            imageviewRID=R.drawable.thinkdifferent2;
        else if (FirstTag.equals("מערך גיבוש והנאה"))
            imageviewRID=R.drawable.fun;
        else if (FirstTag.equals("מערך חברות"))
            imageviewRID=R.drawable.friendship;
        else if (FirstTag.equals("מערך סובלנות"))
            imageviewRID=R.drawable.tolerance;
        else if (FirstTag.equals("מערך אחריות"))
            imageviewRID=R.drawable.responsibility;
        else if (FirstTag.equals("פעולות ללא מערך"))
            imageviewRID=R.drawable.logo1;
        else if (FirstTag.equals("מערך שיתוף פעולה"))
            imageviewRID=R.drawable.teamwork;
        else if (FirstTag.equals("מערך חוץ וטבע"))
            imageviewRID=R.drawable.nature;
        else if (FirstTag.equals("מערך מנהיגות"))
            imageviewRID=R.drawable.leading;
        else if (FirstTag.equals("מערך סבלנות"))
            imageviewRID=R.drawable.patience;
        else if (FirstTag.equals("מערך יוזמה"))
            imageviewRID=R.drawable.yozma;
        else if (FirstTag.equals("מערך שוויון"))
            imageviewRID=R.drawable.equlity;
        else if (FirstTag.equals("מערך הישגים אישיים"))
            imageviewRID=R.drawable.personalachivements;
        else if (FirstTag.equals("מערך עידן מודרני"))
            imageviewRID=R.drawable.modern;
        else if (FirstTag.equals("ערך שוויון"))
            imageviewRID=R.drawable.equlity;
        else if (FirstTag.equals("ערך ישראליות/ ציונות"))
            imageviewRID=R.drawable.zionism;
        else if (FirstTag.equals("מערך מודעות"))
            imageviewRID=R.drawable.awareness2;
        else if (FirstTag.equals("מערך חשיבה אחרת"))
            imageviewRID=R.drawable.thinkdifferent2;
        else if (FirstTag.equals("מערך הישגים אישיים"))
            imageviewRID=R.drawable.personalachivements;
        else if (FirstTag.equals("ערך קבלת השונה"))
            imageviewRID=R.drawable.acceptance;
        else if (FirstTag.equals("אלכוהול וסמים"))
            imageviewRID=R.drawable.alcohol;
        else if (FirstTag.equals("ללא הכנה מראש"))
            imageviewRID=R.drawable.unprepared;
        else if (FirstTag.equals("מערך היכרות"))
            imageviewRID=R.drawable.meeting;
        else if (FirstTag.equals("מערך הדרכה"))
            imageviewRID=R.drawable.guiding;
        else if (FirstTag.equals("מערך יום הזיכרון"))
            imageviewRID=R.drawable.memorial;
        else if (FirstTag.equals("מערך יום הזיכרון לשואה"))
            imageviewRID=R.drawable.holocaustmemorial;
        else if (FirstTag.equals("מערך שינוי"))
            imageviewRID=R.drawable.change;
        else
            imageviewRID=R.drawable.logo1;
        viewHolder.imageView.setImageResource(imageviewRID);
    }


    viewHolder.likeBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

        @Override
        public void onCheckedChanged(CompoundButton buttonView,boolean isChecked)
        {

            if(isChecked)
            {
                String value = sp.getString("ids", "");
                Log.d("ids", value);
                value += "," + id + "/";
                editor.putString("ids", value).apply();
                Log.d("ids", value);
                Log.d("ids", sp.getString("ids", ""));
            }
            if(!isChecked)
            {
                String value = sp.getString("ids", "");
                String replaceString= value.replace("," + id + "/", "");
                editor.putString("ids", replaceString).apply();
                Log.d("ids2", sp.getString("ids", ""));
            }
            Log.d("ids3", sp.getString("ids", ""));

        }
    });
    if (checkMatch(String.valueOf(id),allFavsIds))
        viewHolder.likeBox.setChecked(true);
    else
        viewHolder.likeBox.setChecked(false);

    viewHolder.commBt.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            Intent in = new Intent(context,CommentActivity.class);
            in.putExtra("Json", gl.getCommJson());
            in.putExtra("pId", String.valueOf(id));
            in.putExtra("cats", gl.getCategories());
            context.startActivity(in);
        }
    });



    viewHolder.sharingButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            shareIt(gl.getUrl(),gl.getTitle());
        }
    });






    return view;
}
Zoe
  • 27,060
  • 21
  • 118
  • 148
amir Asaf
  • 33
  • 6
  • You could try to comment out some parts to see if it makes things faster. I would suspect the calls to `SharedPreferences` and the creation of the `Editor` object. Better to defer the editor creation to the listener where it is needed. Also the method calls of `gl` may or may not slow down things. Try it out. For a complex layout a reuse of the `convertView` may also be useful. – Michael Butscher Nov 04 '18 at 23:28
  • Possible duplicate of [Improve android listview performance for refreshing and scrolling](https://stackoverflow.com/questions/23427747/improve-android-listview-performance-for-refreshing-and-scrolling) – Maik Nov 04 '18 at 23:50

3 Answers3

1

This can be improved with the View Holder pattern. Instead of inflating a new view and doing all the boilerplate setup for each item, reuse the views that have been previously been created for items that are now out of the visible area.

Note that this has been answered already a few times. Take a look at the following questions and answers:

Other things I would change to make this more performant:

  • Remove the use of exceptions for "normal" behavior. Code is usually optimized for the non-exceptional flow (citation needed), so hitting the catch block often might be an issue.
  • Switch from SharedPreferences.Editor.commit() to SharedPreferences.Editor.apply(). Based on the documentation commit() synchronously writes to the disk, while apply() writes only to the in-memory structure and writes to disk asynchronously. The issue here might be that you create the listener first and then call setChecked. Check if the listener gets called when setChecked is called and switch the creation of the listener and the setChecked in the code.
  • See if the long if ... else ... if is an issue. Try a map.
  • Do not create new listeners for each new item. Create them once per ViewHolder, set the gl item on the ViewHolder as a field, and refer to the field in the listener.

If you want to be fancy, use the Android Profiler to measure the performance of the method and see where you spent most of the time.

Maik
  • 3,419
  • 1
  • 23
  • 34
  • Yeah Thank you! I am currently trying to implement this, I hope I will make it. – amir Asaf Nov 05 '18 at 08:49
  • Hi! I implemented ViewHolder, and it's fully working, but the list view is still a bit laggy, do you have any idea what else can I do? – amir Asaf Nov 05 '18 at 10:11
  • Based on your initial code, I would look and see if the following things are the issue: `objects.get()`, reading from the `SharedPreferences`, the long `if .. else if` block. Try to comment them out and replace with some stub code to see they are the cause of the lag. If you want to be more fancy try the [Android Profiler](https://developer.android.com/studio/profile/android-profiler) – Maik Nov 05 '18 at 18:02
  • Also `SharedPreferences.Editor.commit()` might be the issue. The reference doc says it still waits synchronously for writing the changes to disk. So seems like you write to disk whenever a new item gets added to the list. Try `SharedPreferences.Editor.apply()` – Maik Nov 05 '18 at 18:09
  • I updated my answer a bit. See my bullet point about the SharedPreferences. I thing the onCheckedChanged() gets called when you call setChecked(), thus you are incuring a blocking disk write for every item. – Maik Nov 06 '18 at 00:27
  • Hi, thank you a lot!, what you suggested with the View Holder and Shared preferences boosted the app by A LOT, although it still lags a bit. I am trying to apply your new suggestion, but I couldn't understand the third suggestion, do you have any example or lead that you can show me? Thanks! – amir Asaf Nov 06 '18 at 10:54
  • Both your `if else` block and the `checkMatch()` function iterate over N items every time, i.e. it has to do N comparisons. A Map (e.g. a `HashMap` in Java) allows you to do the same thing with just 1 comparison. ... While the speedup might not be that much (due to other reasons), it might give you yet another small boost. Best is you measure and see if this suggestion actually improves the runtime cost. – Maik Nov 06 '18 at 15:18
1

You should use ViewHolder link

In item_listview.xml, if have set background of imageview, remove it

Community
  • 1
  • 1
Cuong Nguyen
  • 970
  • 6
  • 17
0

As Michael Butscher already mentioned you should definitely take a look into the GamesLibrary class. If it's yours you have the chance to improve a lot by moving long running tasks to a background thread instead of using the UI thread.

Besides that I would like to give you some code style tips.

  1. You could use a switch-block instead of all your else if blocks. This will shorten your code a lot and make it more readable.
  2. For strings or other values that you're using a lot and that don't change use constants. (e.g. all your SharedPreferences keys) This will take away a lot of work from you when you have to change some of these values.
  3. You should also use provided constants like Context.MODE_PRIVATE in getSharedPreferences(). Code legibility.
CodeRed
  • 481
  • 4
  • 17