Large ListView containing images in Android

For various Android apps, I need big ListViews, i.e. such representations with 100-300 elements.

All records must be loaded in bulk when the application is running, as some sorting and processing is required, and the application cannot know which items should be displayed first, otherwise.

So far, I have also uploaded images for all the elements in the array, which are then stored in ArrayList<CustomType>along with the rest of the data for each record.

But, of course, this is not a good practice, since you will most likely have OutOfMemoryException: Links to all images in the ArrayListgarbage collector do not allow.

So the best solution, obviously, is to download only text data in bulk, while images are then loaded as needed, right? The Google Play application does this, for example: you can see that images are loaded when scrolling to them, i.e. They are probably loaded into the adapter method getView(). But with Google Play, this is a completely different problem, since the images must be downloaded from the Internet, which is not suitable for me. My problem is not that loading images takes too much time, but it takes too much memory to store them.

So what should I do with the images? Upload to getView()when you really need them? Would make the scroll listless. So, is it called AsyncTask? Or just normal Thread? Parameterize it?

I could save the images that are already uploaded to HashMap<String,Bitmap>so that they do not need to be uploaded again to getView(). But if this is done, you will again have a memory problem: it HashMapstores links to all images, so in the end you can have it again OutOfMemoryException.

I know that there are already many questions that discuss the "lazy loading" of images. But they mainly cover the problem of slow loading, and not too much memory consumption.

Edit: Now I decided to run AsyncTasks in getView (), which loads the image into the ListView in the background . But this causes my application to run as a RejectedExecutionException. What should I do now?

+5
source
7

AsyncTask getView , - . , - . , , , , .

:

public class DecodeTask extends AsyncTask<String, Void, Bitmap> {

private static int MaxTextureSize = 2048; /* True for most devices. */

public ImageView v;

public DecodeTask(ImageView iv) {
    v = iv;
}

protected Bitmap doInBackground(String... params) {
    BitmapFactory.Options opt = new BitmapFactory.Options();
    opt.inPurgeable = true;
    opt.inPreferQualityOverSpeed = false;
    opt.inSampleSize = 0;

    Bitmap bitmap = null;
    if(isCancelled()) {
        return bitmap;
    }

    opt.inJustDecodeBounds = true;
    do {
        opt.inSampleSize++;
        BitmapFactory.decodeFile(params[0], opt);
    } while(opt.outHeight > MaxTextureSize || opt.outWidth > MaxTextureSize)
    opt.inJustDecodeBounds = false;

    bitmap = BitmapFactory.decodeFile(params[0], opt);
    return bitmap;
}

@Override
protected void onPostExecute(Bitmap result) {
    if(v != null) {
        v.setImageBitmap(result);
    }
}

}

ArrayList, . getView :

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ImageView iv = null;
    if(convertView == null) {
        convertView = getLayoutInflater().inflate(R.id.your_view, null); /* Inflate your view here */
        iv = convertView.findViewById(R.id.your_image_view);
    } else {
        iv = convertView.findViewById(R.id.your_image_view);
        DecodeTask task = (DecodeTask)iv.getTag(R.id.your_image_view);
        if(task != null) {
            task.cancel(true);
        }
    }
    iv.setImageBitmap(null);
    DecodeTask task = new DecodeTask(iv);
    task.execute(getItem(position) /* File path to image */);
    iv.setTag(R.id.your_image_view, task);

    return convertView;
}

. 1.5 - 2.3, AsyncTask. 3.0+ AsyncTasks, , , . , .

+9

1) HashMap<String, Bitmap>: WeakHashMap, ? ArrayList, , CustomType .

2) , , , , . , , , , , . :

listView.setOnScrollListener(new OnScrollListener() {
  @Override
  public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
      int totalItemCount) {
    // Don't care.
  }

  @Override
  public void onScrollStateChanged(final AbsListView view, int scrollState) {
    // Load images here. ListView can tell you what rows are visible, you load images for these rows and update corresponding View-s.
  }
})

3) , 300 . , OOM, , - . , RGB_565 ListView ( ), 96x96, .

+2

, . AsyncTask getView, , InBackground View PostExecute. , convertView getView, AsyncTask, , AsyncTask , ...

LruCache, . , .

+1

: https://github.com/DHuckaby/Prime

ListView vs, .. .. , , .. - . , .

+1

, , , convertView, asyncTask .. , View v = super.getView(position, convertView, parent); . , if(convertView != null){ myView = convertView} else{ inflate(myView)};

AsyncTask, APIS, execute() API executeOnExecutor , , . URI ImageView AsyncTask. convertView, , AsyncTask. , , hashmap ImageView-AsyncTask , .

PS. , :)

0
    private class CallService extends AsyncTask<String, Integer, String>
         {   
                protected String doInBackground(String... u)
                {
                    fetchReasons();
                    return null;
                }
                protected void onPreExecute() 
                {
                    //Define the loader here.

                }
                public void onProgressUpdate(Integer... args)
                {           
                }
                protected void onPostExecute(String result) 
                {               
                    //remove loader
                    //Add data to your view.
                }
         }

public void fetchReasons()
    {
         //Call Your Web Service and save the records in the arrayList
    }

CallService(). execute(); onCreate()

-1

, .


HACK, :

getItemViewType(int position) :

@Override
public long getItemViewType(int position) {
     return position;
}
@Override
public long getViewTypeCount(int position) {
     return getCount();
}
@Override
public View getView(int position, View convertView, ViewGroup arg2) {
    if (convertView == null) {
        //inflate your convertView and set everything
    }
    //do not do anything just return the convertView
    return convertView;
}

ListView will determine the number of images in the cache.


-3
source

All Articles