├── .classpath ├── .gitignore ├── .project ├── AndroidManifest.xml ├── README.md ├── assets ├── .DS_Store └── json_simple-1.1.jar ├── bin ├── TweetView.apk ├── classes.dex ├── com │ └── example │ │ ├── Example$Tweet.class │ │ ├── Example.class │ │ ├── ImageManager$BitmapDisplayer.class │ │ ├── ImageManager$ImageQueue.class │ │ ├── ImageManager$ImageQueueManager.class │ │ ├── ImageManager$ImageRef.class │ │ ├── ImageManager.class │ │ ├── R$attr.class │ │ ├── R$drawable.class │ │ ├── R$id.class │ │ ├── R$layout.class │ │ ├── R$string.class │ │ ├── R.class │ │ ├── TweetItemAdapter$ViewHolder.class │ │ └── TweetItemAdapter.class └── resources.ap_ ├── default.properties ├── gen └── com │ └── example │ └── R.java ├── proguard.cfg ├── res ├── drawable-hdpi │ └── icon.png ├── drawable-ldpi │ └── icon.png ├── drawable-mdpi │ └── icon.png ├── layout │ ├── listitem.xml │ └── main.xml └── values │ └── strings.xml └── src └── com └── example ├── Example.java ├── ImageManager.java └── TweetItemAdapter.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | TweetView 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## TweetView 2 | 3 | This project is an example Android Twitter feed reader app 4 | from the Codehenge Android development tutorial: 5 | 6 | http://www.codehenge.net/blog/ 7 | 8 | It is designed as a learning aid, and written for illustrative purposes. This project was developed in Eclipse, and includes all associated files. I've also packaged in the open source simple-json library used in the example. 9 | 10 | This code is free as in both speech and beer. Feel free to fork, modify, or do anything you want with this code. 11 | 12 | 13 | [Associated Blog Post](http://www.codehenge.net/2011/06/android-development-tutorial-asynchronous-lazy-loading-and-caching-of-listview-images/) 14 | -------------------------------------------------------------------------------- /assets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/assets/.DS_Store -------------------------------------------------------------------------------- /assets/json_simple-1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/assets/json_simple-1.1.jar -------------------------------------------------------------------------------- /bin/TweetView.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/TweetView.apk -------------------------------------------------------------------------------- /bin/classes.dex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/classes.dex -------------------------------------------------------------------------------- /bin/com/example/Example$Tweet.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/Example$Tweet.class -------------------------------------------------------------------------------- /bin/com/example/Example.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/Example.class -------------------------------------------------------------------------------- /bin/com/example/ImageManager$BitmapDisplayer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/ImageManager$BitmapDisplayer.class -------------------------------------------------------------------------------- /bin/com/example/ImageManager$ImageQueue.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/ImageManager$ImageQueue.class -------------------------------------------------------------------------------- /bin/com/example/ImageManager$ImageQueueManager.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/ImageManager$ImageQueueManager.class -------------------------------------------------------------------------------- /bin/com/example/ImageManager$ImageRef.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/ImageManager$ImageRef.class -------------------------------------------------------------------------------- /bin/com/example/ImageManager.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/ImageManager.class -------------------------------------------------------------------------------- /bin/com/example/R$attr.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/R$attr.class -------------------------------------------------------------------------------- /bin/com/example/R$drawable.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/R$drawable.class -------------------------------------------------------------------------------- /bin/com/example/R$id.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/R$id.class -------------------------------------------------------------------------------- /bin/com/example/R$layout.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/R$layout.class -------------------------------------------------------------------------------- /bin/com/example/R$string.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/R$string.class -------------------------------------------------------------------------------- /bin/com/example/R.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/R.class -------------------------------------------------------------------------------- /bin/com/example/TweetItemAdapter$ViewHolder.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/TweetItemAdapter$ViewHolder.class -------------------------------------------------------------------------------- /bin/com/example/TweetItemAdapter.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/com/example/TweetItemAdapter.class -------------------------------------------------------------------------------- /bin/resources.ap_: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/bin/resources.ap_ -------------------------------------------------------------------------------- /default.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system use, 7 | # "build.properties", and override values to adapt the script to your 8 | # project structure. 9 | 10 | # Project target. 11 | target=android-4 12 | -------------------------------------------------------------------------------- /gen/com/example/R.java: -------------------------------------------------------------------------------- 1 | /* AUTO-GENERATED FILE. DO NOT MODIFY. 2 | * 3 | * This class was automatically generated by the 4 | * aapt tool from the resource data it found. It 5 | * should not be modified by hand. 6 | */ 7 | 8 | package com.example; 9 | 10 | public final class R { 11 | public static final class attr { 12 | } 13 | public static final class drawable { 14 | public static final int icon=0x7f020000; 15 | } 16 | public static final class id { 17 | public static final int ListViewId=0x7f050003; 18 | public static final int avatar=0x7f050000; 19 | public static final int message=0x7f050002; 20 | public static final int username=0x7f050001; 21 | } 22 | public static final class layout { 23 | public static final int listitem=0x7f030000; 24 | public static final int main=0x7f030001; 25 | } 26 | public static final class string { 27 | public static final int app_name=0x7f040001; 28 | public static final int hello=0x7f040000; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /proguard.cfg: -------------------------------------------------------------------------------- 1 | -optimizationpasses 5 2 | -dontusemixedcaseclassnames 3 | -dontskipnonpubliclibraryclasses 4 | -dontpreverify 5 | -verbose 6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 7 | 8 | -keep public class * extends android.app.Activity 9 | -keep public class * extends android.app.Application 10 | -keep public class * extends android.app.Service 11 | -keep public class * extends android.content.BroadcastReceiver 12 | -keep public class * extends android.content.ContentProvider 13 | -keep public class * extends android.app.backup.BackupAgentHelper 14 | -keep public class * extends android.preference.Preference 15 | -keep public class com.android.vending.licensing.ILicensingService 16 | 17 | -keepclasseswithmembernames class * { 18 | native ; 19 | } 20 | 21 | -keepclasseswithmembernames class * { 22 | public (android.content.Context, android.util.AttributeSet); 23 | } 24 | 25 | -keepclasseswithmembernames class * { 26 | public (android.content.Context, android.util.AttributeSet, int); 27 | } 28 | 29 | -keepclassmembers enum * { 30 | public static **[] values(); 31 | public static ** valueOf(java.lang.String); 32 | } 33 | 34 | -keep class * implements android.os.Parcelable { 35 | public static final android.os.Parcelable$Creator *; 36 | } 37 | -------------------------------------------------------------------------------- /res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /res/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/res/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /res/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cacois/TweetView/1cc7eed35138046f64211d78354e45dc4dbac701/res/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /res/layout/listitem.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 21 | 25 | 30 | 31 | -------------------------------------------------------------------------------- /res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello World, Example! 4 | CustomListViewExample 5 | 6 | -------------------------------------------------------------------------------- /src/com/example/Example.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import java.util.ArrayList; 4 | 5 | import org.apache.http.client.HttpClient; 6 | import org.apache.http.client.ResponseHandler; 7 | import org.apache.http.client.methods.HttpGet; 8 | import org.apache.http.impl.client.BasicResponseHandler; 9 | import org.apache.http.impl.client.DefaultHttpClient; 10 | import org.json.simple.JSONArray; 11 | import org.json.simple.JSONObject; 12 | import org.json.simple.parser.JSONParser; 13 | 14 | import android.app.Activity; 15 | import android.graphics.Bitmap; 16 | import android.os.Bundle; 17 | import android.util.Log; 18 | import android.widget.ListView; 19 | 20 | public class Example extends Activity { 21 | 22 | public Bitmap placeholder; 23 | 24 | @Override 25 | public void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.main); 28 | 29 | ArrayList tweets = getTweets("android", 1); 30 | 31 | ListView listView = (ListView) findViewById(R.id.ListViewId); 32 | listView.setAdapter(new TweetItemAdapter(this, R.layout.listitem, tweets)); 33 | } 34 | 35 | public ArrayList getTweets(String searchTerm, int page) { 36 | String searchUrl = "http://search.twitter.com/search.json?q=@" 37 | + searchTerm + "&rpp=100&page=" + page; 38 | 39 | ArrayList tweets = new ArrayList(); 40 | 41 | HttpClient client = new DefaultHttpClient(); 42 | HttpGet get = new HttpGet(searchUrl); 43 | 44 | ResponseHandler responseHandler = new BasicResponseHandler(); 45 | 46 | String responseBody = null; 47 | try{ 48 | responseBody = client.execute(get, responseHandler); 49 | }catch(Exception ex) { 50 | ex.printStackTrace(); 51 | } 52 | 53 | JSONObject jsonObject = null; 54 | JSONParser parser=new JSONParser(); 55 | 56 | try { 57 | Object obj = parser.parse(responseBody); 58 | jsonObject=(JSONObject)obj; 59 | 60 | }catch(Exception ex){ 61 | Log.v("TEST","Exception: " + ex.getMessage()); 62 | } 63 | 64 | JSONArray arr = null; 65 | 66 | try { 67 | Object j = jsonObject.get("results"); 68 | arr = (JSONArray)j; 69 | }catch(Exception ex){ 70 | Log.v("TEST","Exception: " + ex.getMessage()); 71 | } 72 | 73 | for(Object t : arr) { 74 | Tweet tweet = new Tweet( 75 | ((JSONObject)t).get("from_user").toString(), 76 | ((JSONObject)t).get("text").toString(), 77 | ((JSONObject)t).get("profile_image_url").toString() 78 | ); 79 | tweets.add(tweet); 80 | } 81 | 82 | return tweets; 83 | } 84 | 85 | /** Classes **/ 86 | 87 | public class Tweet { 88 | public String username; 89 | public String message; 90 | public String image_url; 91 | public Boolean usernameSet = false; 92 | public Boolean messageSet = false; 93 | public Boolean imageSet = false; 94 | public Bitmap avatar; 95 | 96 | public Tweet(String username, String message, String url) { 97 | this.username = username; 98 | this.message = message; 99 | this.image_url = url; 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /src/com/example/ImageManager.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileOutputStream; 6 | import java.io.FileReader; 7 | import java.io.IOException; 8 | import java.lang.ref.SoftReference; 9 | import java.net.URL; 10 | import java.net.URLConnection; 11 | import java.text.DateFormat; 12 | import java.text.SimpleDateFormat; 13 | import java.util.HashMap; 14 | import java.util.Stack; 15 | 16 | import android.app.Activity; 17 | import android.content.Context; 18 | import android.graphics.Bitmap; 19 | import android.graphics.BitmapFactory; 20 | import android.widget.ImageView; 21 | 22 | public class ImageManager { 23 | 24 | private long cacheDuration; 25 | private DateFormat mDateFormatter; 26 | 27 | private HashMap> imageMap = new HashMap>(); 28 | 29 | private File cacheDir; 30 | private ImageQueue imageQueue = new ImageQueue(); 31 | private Thread imageLoaderThread = new Thread(new ImageQueueManager()); 32 | 33 | public ImageManager(Context context, long _cacheDuration) { 34 | 35 | cacheDuration = _cacheDuration; 36 | //TODO Make this match the date format of your server 37 | mDateFormatter = new SimpleDateFormat("EEE',' dd MMM yyyy HH:mm:ss zzz"); 38 | 39 | // Make background thread low priority, to avoid affecting UI performance 40 | imageLoaderThread.setPriority(Thread.NORM_PRIORITY-1); 41 | 42 | // Find the dir to save cached images 43 | String sdState = android.os.Environment.getExternalStorageState(); 44 | if (sdState.equals(android.os.Environment.MEDIA_MOUNTED)) { 45 | File sdDir = android.os.Environment.getExternalStorageDirectory(); 46 | cacheDir = new File(sdDir,"data/codehenge"); 47 | 48 | } else { 49 | cacheDir = context.getCacheDir(); 50 | } 51 | 52 | if (!cacheDir.exists()) { 53 | cacheDir.mkdirs(); 54 | } 55 | } 56 | 57 | public void displayImage(String url, ImageView imageView, int defaultDrawableId) { 58 | 59 | if(imageMap.containsKey(url)) { 60 | imageView.setImageBitmap(imageMap.get(url).get()); 61 | 62 | } else { 63 | queueImage(url, imageView, defaultDrawableId); 64 | imageView.setImageResource(defaultDrawableId); 65 | } 66 | } 67 | 68 | private void queueImage(String url, ImageView imageView, int defaultDrawableId) { 69 | // This ImageView might have been used for other images, so we clear 70 | // the queue of old tasks before starting. 71 | imageQueue.Clean(imageView); 72 | ImageRef p = new ImageRef(url, imageView, defaultDrawableId); 73 | 74 | synchronized(imageQueue.imageRefs) { 75 | imageQueue.imageRefs.push(p); 76 | imageQueue.imageRefs.notifyAll(); 77 | } 78 | 79 | // Start thread if it's not started yet 80 | if(imageLoaderThread.getState() == Thread.State.NEW) { 81 | imageLoaderThread.start(); 82 | } 83 | } 84 | 85 | private Bitmap getBitmap(String url) { 86 | 87 | try { 88 | URLConnection openConnection = new URL(url).openConnection(); 89 | 90 | String filename = String.valueOf(url.hashCode()); 91 | 92 | File bitmapFile = new File(cacheDir, filename); 93 | Bitmap bitmap = BitmapFactory.decodeFile(bitmapFile.getPath()); 94 | 95 | long currentTimeMillis = System.currentTimeMillis(); 96 | 97 | // Is the bitmap in our cache? 98 | if (bitmap != null) { 99 | 100 | // Has it expired? 101 | long bitmapTimeMillis = bitmapFile.lastModified(); 102 | if ( (currentTimeMillis - bitmapTimeMillis) < cacheDuration ) { 103 | return bitmap; 104 | } 105 | 106 | // Check also if it was modified on the server before downloading it 107 | String lastMod = openConnection.getHeaderField("Last-Modified"); 108 | long lastModTimeMillis = mDateFormatter.parse(lastMod).getTime(); 109 | 110 | if ( lastModTimeMillis <= bitmapTimeMillis ) { 111 | 112 | //Discard the connection and return the cached version 113 | return bitmap; 114 | } 115 | } 116 | 117 | // Nope, have to download it 118 | bitmap = BitmapFactory.decodeStream(openConnection.getInputStream()); 119 | // save bitmap to cache for later 120 | writeFile(bitmap, bitmapFile); 121 | 122 | return bitmap; 123 | 124 | } catch (Exception ex) { 125 | ex.printStackTrace(); 126 | return null; 127 | } 128 | } 129 | 130 | private void writeFile(Bitmap bmp, File f) { 131 | FileOutputStream out = null; 132 | 133 | try { 134 | out = new FileOutputStream(f); 135 | bmp.compress(Bitmap.CompressFormat.PNG, 80, out); 136 | } catch (Exception e) { 137 | e.printStackTrace(); 138 | } 139 | finally { 140 | try { if (out != null ) out.close(); } 141 | catch(Exception ex) {} 142 | } 143 | } 144 | 145 | /** Classes **/ 146 | 147 | private class ImageRef { 148 | public String url; 149 | public ImageView imageView; 150 | public int defDrawableId; 151 | 152 | public ImageRef(String u, ImageView i, int defaultDrawableId) { 153 | url=u; 154 | imageView=i; 155 | defDrawableId = defaultDrawableId; 156 | } 157 | } 158 | 159 | //stores list of images to download 160 | private class ImageQueue { 161 | private Stack imageRefs = 162 | new Stack(); 163 | 164 | //removes all instances of this ImageView 165 | public void Clean(ImageView view) { 166 | 167 | for(int i = 0 ;i < imageRefs.size();) { 168 | if(imageRefs.get(i).imageView == view) 169 | imageRefs.remove(i); 170 | else ++i; 171 | } 172 | } 173 | } 174 | 175 | private class ImageQueueManager implements Runnable { 176 | @Override 177 | public void run() { 178 | try { 179 | while(true) { 180 | // Thread waits until there are images in the 181 | // queue to be retrieved 182 | if(imageQueue.imageRefs.size() == 0) { 183 | synchronized(imageQueue.imageRefs) { 184 | imageQueue.imageRefs.wait(); 185 | } 186 | } 187 | 188 | // When we have images to be loaded 189 | if(imageQueue.imageRefs.size() != 0) { 190 | ImageRef imageToLoad; 191 | 192 | synchronized(imageQueue.imageRefs) { 193 | imageToLoad = imageQueue.imageRefs.pop(); 194 | } 195 | 196 | Bitmap bmp = getBitmap(imageToLoad.url); 197 | imageMap.put(imageToLoad.url, new SoftReference(bmp)); 198 | Object tag = imageToLoad.imageView.getTag(); 199 | 200 | // Make sure we have the right view - thread safety defender 201 | if(tag != null && ((String)tag).equals(imageToLoad.url)) { 202 | BitmapDisplayer bmpDisplayer = 203 | new BitmapDisplayer(bmp, imageToLoad.imageView, imageToLoad.defDrawableId); 204 | 205 | Activity a = 206 | (Activity)imageToLoad.imageView.getContext(); 207 | 208 | a.runOnUiThread(bmpDisplayer); 209 | } 210 | } 211 | 212 | if(Thread.interrupted()) 213 | break; 214 | } 215 | } catch (InterruptedException e) {} 216 | } 217 | } 218 | 219 | //Used to display bitmap in the UI thread 220 | private class BitmapDisplayer implements Runnable { 221 | Bitmap bitmap; 222 | ImageView imageView; 223 | int defDrawableId; 224 | 225 | public BitmapDisplayer(Bitmap b, ImageView i, int defaultDrawableId) { 226 | bitmap=b; 227 | imageView=i; 228 | defDrawableId = defaultDrawableId; 229 | } 230 | 231 | public void run() { 232 | if(bitmap != null) 233 | imageView.setImageBitmap(bitmap); 234 | else 235 | imageView.setImageResource(defDrawableId); 236 | } 237 | } 238 | } -------------------------------------------------------------------------------- /src/com/example/TweetItemAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import java.util.ArrayList; 4 | 5 | import com.example.Example.Tweet; 6 | 7 | import android.app.Activity; 8 | import android.content.Context; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.ArrayAdapter; 13 | import android.widget.ImageView; 14 | import android.widget.TextView; 15 | 16 | public class TweetItemAdapter extends ArrayAdapter { 17 | private ArrayList tweets; 18 | private Activity activity; 19 | public ImageManager imageManager; 20 | 21 | public TweetItemAdapter(Activity a, int textViewResourceId, ArrayList tweets) { 22 | super(a, textViewResourceId, tweets); 23 | this.tweets = tweets; 24 | activity = a; 25 | 26 | imageManager = 27 | new ImageManager(activity.getApplicationContext()); 28 | } 29 | 30 | public static class ViewHolder{ 31 | public TextView username; 32 | public TextView message; 33 | public ImageView image; 34 | } 35 | 36 | @Override 37 | public View getView(int position, View convertView, ViewGroup parent) { 38 | View v = convertView; 39 | ViewHolder holder; 40 | if (v == null) { 41 | LayoutInflater vi = 42 | (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 43 | v = vi.inflate(R.layout.listitem, null); 44 | holder = new ViewHolder(); 45 | holder.username = (TextView) v.findViewById(R.id.username); 46 | holder.message = (TextView) v.findViewById(R.id.message); 47 | holder.image = (ImageView) v.findViewById(R.id.avatar); 48 | v.setTag(holder); 49 | } 50 | else 51 | holder=(ViewHolder)v.getTag(); 52 | 53 | final Tweet tweet = tweets.get(position); 54 | if (tweet != null) { 55 | holder.username.setText(tweet.username); 56 | holder.message.setText(tweet.message); 57 | holder.image.setTag(tweet.image_url); 58 | imageManager.displayImage(tweet.image_url, activity, holder.image); 59 | } 60 | return v; 61 | } 62 | } --------------------------------------------------------------------------------