Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Here's how I load and cache images in a <code>ListView</code> that creates a contact list for the user. So imagine profile picture on the left, some text views on the right (which sounds close to the problem you're dealing with. Ignore the ugly debug tags and probably poor formatting (sorry). I guess this is kind of like LazyList but here's a detailed explanation in case anyone was confused. </p> <p><strong>Step 1: Set Up Your Cache</strong></p> <pre><code>private LruCache&lt;String, Bitmap&gt; memoryCache; private HashMap&lt;String, String&gt; idPairs = new HashMap&lt;String, String&gt;(); </code></pre> <p>In my approach I use an <code>LruCache</code> and a <code>HashMap</code> to track which user's images I've downloaded. You'll see how its implemented later but the idea is to avoid downloading stuff from the server unless you have to. Then in your <code>onCreate()</code> or some related method, initialize your cache.</p> <pre><code> final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); final int cacheSize = maxMemory / 8; memoryCache = new LruCache&lt;String, Bitmap&gt;(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap){ return (bitmap.getRowBytes() * bitmap.getHeight()) / 1024; //don't use getByteCount for API &lt; 12 } }; </code></pre> <p>My next step is to add the default "empty image" bitmap to the cache in case I reach an entry that does not have a picture associated with it. That way I only have to process and add this bitmap once</p> <pre><code>Bitmap defaultPicture = BitmapFactory.decodeResource(getResources(), R.drawable.default_user_picture); addBitmapToMemoryCache("default", defaultPicture); </code></pre> <p>Then its time to get the data you need for the list!</p> <p><strong>Step 2: Get The Data</strong></p> <pre><code>private class GetPeopleData extends AsyncTask&lt;JSONArray, Void, Void&gt; { @Override protected Void doInBackground(JSONArray...lists) { HttpClient httpClient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost(); ResponseHandler &lt;String&gt; responseHandler = new BasicResponseHandler(); if(DEBUG) Log.d("GET PEOPLE DATA TASK", lists[0].length() + " users"); getUsers(lists[0], httpClient, httpPost, responseHandler); return null; } @Override protected void onPostExecute(Void result){ updateUserListView(); } } </code></pre> <p>Here's a borring <code>AsyncTask</code> that takes a <code>JSONArray</code> of user data as an argument. I left out that part because it's pretty much just a basic HTTP download that doesn't need explanation. The getUsers method is where I start to put together what will be added to my <code>ListView</code>. What I do next is process the JSON downloaded from the server to create user objects that will be added it to a list of users that will be displayed. </p> <pre><code>private void getUsers(JSONArray userArray, HttpClient httpClient, HttpPost httpPost, ResponseHandler&lt;String&gt; responseHandler){ if(DEBUG) Log.d("USERS ARRAY", userArray.length() + " users"); try{ users = new ArrayList&lt;User&gt;(); if(DEBUG) Log.d("User Array -START", "" + users.size()); //Go through userArray and get information needed for list for(int i = 0; i &lt; userArray.length(); i++){ User u = new User(); if(DEBUG) Log.d("User Array - ADD USER", "" + users.size()); String profileId = userArray.getJSONObject(i).getString("profileid"); u.setId(userArray.getJSONObject(i).getString("id")); u.setDisplayName(userArray.getJSONObject(i).getString("displayname")); u.setStatus(userArray.getJSONObject(i).getString("status")); //check HashMap for sender/profileid pair if(idPairs.containsKey(profileId)){ if(DEBUG) Log.d("idPairs", "User in HashMap"); profileId = idPairs.get(profileId); } else { if(DEBUG) Log.d("idPairs", "User not in HashMap. Add profileId"); idPairs.put("profileId", profileId); } u.setProfilePicture(getProfilePictureFromCache(profileId, httpClient, httpPost, responseHandler)); //check cache for image users.add(u); if(DEBUG) Log.d("User info", u.toString()); } } catch (Exception e) { Log.e("BACKGROUND_PROC", e.getMessage()); } } </code></pre> <p>I associate the picture with the user object that will eventually be displayed. I figure this isn't a total waste of time since the image is pulled from the bitmap cache</p> <pre><code>private Bitmap getProfilePictureFromCache(String profileId, HttpClient httpClient, HttpPost httpPost, ResponseHandler&lt;String&gt; responseHandler){ Bitmap defaultPicture = getBitmapFromMemCache("default"); Bitmap profilePicture = getBitmapFromMemCache(profileId); if(profilePicture != null){ return profilePicture; } else { String pictureString = getProfilePic(profileId, httpClient, httpPost, responseHandler); if(!pictureString.isEmpty()){ byte[] decodedString = Base64.decode(pictureString, Base64.DEFAULT); profilePicture = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length); addBitmapToMemoryCache(profileId, profilePicture); if(DEBUG) Log.d("MEMCACHE", "Download and store picture for " + profileId); return profilePicture; } else if (defaultPicture != null &amp;&amp; pictureString.equals(null)) { if(DEBUG) Log.d("MEMCACHE", "Load default picture"); return defaultPicture; } } return defaultPicture; } </code></pre> <p>If a picture exists in the cache it is returned, if not it is downloaded. For me, displaying users, each picture is cached according to userid so even if someone were to appear more than once in the list, there would only be one picture stored in the cache for that user. </p> <pre><code>ImageView profile_picture = (ImageView) v.findViewById(R.id.profile_picture); if(profile_picture != null){ profile_picture.setImageBitmap(u.getProfilePicture()); } </code></pre> <p>The only thing left to do is find the <code>ImageView</code> in your adapter and set that view to the picture you associated with the object in your list. </p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload