I am using a listview and each items use an image called from a server with an asynctask class.
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
final ViewHolder viewHolder;
if (view == null) {
view = getActivity().getLayoutInflater().inflate(R.layout.item_liste, null);
viewHolder = new ViewHolder();
viewHolder.image = (ImageView) view.findViewById(R.id.imageView);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
if (/* Image not loaded */) {
/* Create and execute the request using an AsyncTask */
mRequestManager.getDrawable("0", listItemInformation.resumeBien.Identifiant, new SendBitmap() {
/* SendBack is called when the bitmap is received from the server */
#Override
public void sendBack(Bitmap bitmap) {
listItemInformation.drawable.add(bitmap);
listItemInformation.drawableCalled = false;
viewHolder.image.setImageBitmap(bitmap);
}
});
} else {
viewHolder.image.setImageBitmap(listItemInformation.drawable.get(0));
}
return view;
}
The problem is, when the image is received, the ImageView is not the good one.
And all the pictures are loaded in the first item of the listview..
I tried to use adapter.notifyDataSetChanged();
But the listview motion is cut when it is called during a scroll..
What are my possibilities to avoid those issues?
I want the same result as the googleplay's listview.
Thanks in advance :)
You can try Volley's NetworkImageView with just one or two lines to complete your job.
//Dummy:
public static class BitmapLruCache extends LruCache<String, Bitmap> implements ImageCache {
public BitmapLruCache(int maxSize) {
super(maxSize);
}
#Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
#Override
public Bitmap getBitmap(String url) {
return get(url);
}
#Override
public void putBitmap(String url, Bitmap bitmap) {
put(url, bitmap);
}
}
ImageLoader sImageLoader = new ImageLoader(sRequestQueue, new BitmapLruCache(100));
networkImageView.setImageUrl(url_to_image, sImageLoader);
what you need is called "Lazy adapter", to load images in list view you can try my code:
public class MainActivity extends Activity {
ListView list;
LazyAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
list=(ListView)findViewById(R.id.list);
adapter=new LazyAdapter(this, mStrings);
list.setAdapter(adapter);
adapter.imageLoader.clearCache();
adapter.notifyDataSetChanged();
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
//Toast.makeText(getApplicationContext(), id + "", 2000).show();
String wallcategory =(String) ((TextView) view.findViewById(R.id.text)).getText();
//Toast.makeText(getApplicationContext(),mStrings[position], 2000).show();
Intent myIntent = new Intent(MainActivity.this, Wallgrid.class);
myIntent.putExtra("cat", wallcategory); //Optional parameters
MainActivity.this.startActivity(myIntent);
}
});
}
#Override
public void onDestroy()
{
list.setAdapter(null);
super.onDestroy();
}
public String[] mStrings={
"http://www.bourax.com/android/paradise/categories/nature.jpg",
"http://www.bourax.com/android/paradise/categories/animals.jpg",
"http://www.bourax.com/android/paradise/categories/colorful.jpg",
"http://www.bourax.com/android/paradise/categories/cars.jpg",
"http://www.bourax.com/android/paradise/categories/city.jpg",
"http://www.bourax.com/android/paradise/categories/flowers.jpg",
"http://www.bourax.com/android/paradise/categories/girls.jpg",
"http://www.bourax.com/android/paradise/categories/sport.jpg",
"http://www.bourax.com/android/paradise/categories/cats.jpg",
"http://www.bourax.com/android/paradise/categories/fish.jpg",
"http://www.bourax.com/android/paradise/categories/sea.jpg",
"http://www.bourax.com/android/paradise/categories/love.jpg",
"http://www.bourax.com/android/paradise/categories/buildings.jpg",
"http://www.bourax.com/android/paradise/categories/paintings.jpg",
"http://www.bourax.com/android/paradise/categories/pink.jpg",
"http://www.bourax.com/android/paradise/categories/travel.jpg",
"http://www.bourax.com/android/paradise/categories/fantasy.jpg",
"http://www.bourax.com/android/paradise/categories/tree.jpg",
"http://www.bourax.com/android/paradise/categories/portrait.jpg",
"http://www.bourax.com/android/paradise/categories/top.jpg"
};
}
public class LazyAdapter extends BaseAdapter {
private Activity activity;
private String[] data;
private static LayoutInflater inflater=null;
public ImageLoader imageLoader;
public LazyAdapter(Activity a, String[] d) {
activity = a;
data=d;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader=new ImageLoader(activity.getApplicationContext());
}
public int getCount() {
return data.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public String[] Category={
"Nature",
"Animals",
"Colorful",
"Cars",
"City",
"Flowers",
"Girls",
"Sport",
"Cats & Dogs",
"Fish",
"Sea",
"Love",
"Buildings",
"Paintings",
"Pink",
"Travel",
"Fantasy",
"Tree",
"Portrait",
"Top Rated"
};
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.item, null);
TextView text=(TextView)vi.findViewById(R.id.text);
ImageView image=(ImageView)vi.findViewById(R.id.image);
text.setText(Category[position]);
imageLoader.DisplayImage(data[position], image);
return vi;
}
}
public class ImageLoader {
MemoryCache memoryCache=new MemoryCache();
FileCache fileCache;
private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
ExecutorService executorService;
Handler handler=new Handler();//handler to display images in UI thread
public ImageLoader(Context context){
fileCache=new FileCache(context);
executorService=Executors.newFixedThreadPool(5);
}
final int stub_id=R.drawable.stub;
public void DisplayImage(String url, ImageView imageView)
{
imageViews.put(imageView, url);
Bitmap bitmap=memoryCache.get(url);
if(bitmap!=null)
imageView.setImageBitmap(bitmap);
else
{
queuePhoto(url, imageView);
//imageView.setImageResource(stub_id);
}
}
private void queuePhoto(String url, ImageView imageView)
{
PhotoToLoad p=new PhotoToLoad(url, imageView);
executorService.submit(new PhotosLoader(p));
}
private Bitmap getBitmap(String url)
{
File f=fileCache.getFile(url);
//from SD cache
Bitmap b = decodeFile(f);
if(b!=null)
return b;
//from web
try {
Bitmap bitmap=null;
URL imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
InputStream is=conn.getInputStream();
OutputStream os = new FileOutputStream(f);
Utils.CopyStream(is, os);
os.close();
conn.disconnect();
bitmap = decodeFile(f);
return bitmap;
} catch (Throwable ex){
ex.printStackTrace();
if(ex instanceof OutOfMemoryError)
memoryCache.clear();
return null;
}
}
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream stream1=new FileInputStream(f);
BitmapFactory.decodeStream(stream1,null,o);
stream1.close();
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE=70;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
FileInputStream stream2=new FileInputStream(f);
Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
//Task for the queue
private class PhotoToLoad
{
public String url;
public ImageView imageView;
public PhotoToLoad(String u, ImageView i){
url=u;
imageView=i;
}
}
class PhotosLoader implements Runnable {
PhotoToLoad photoToLoad;
PhotosLoader(PhotoToLoad photoToLoad){
this.photoToLoad=photoToLoad;
}
#Override
public void run() {
try{
if(imageViewReused(photoToLoad))
return;
Bitmap bmp=getBitmap(photoToLoad.url);
memoryCache.put(photoToLoad.url, bmp);
if(imageViewReused(photoToLoad))
return;
BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad);
handler.post(bd);
}catch(Throwable th){
th.printStackTrace();
}
}
}
boolean imageViewReused(PhotoToLoad photoToLoad){
String tag=imageViews.get(photoToLoad.imageView);
if(tag==null || !tag.equals(photoToLoad.url))
return true;
return false;
}
//Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable
{
Bitmap bitmap;
PhotoToLoad photoToLoad;
public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;}
public void run()
{
if(imageViewReused(photoToLoad))
return;
if(bitmap!=null)
photoToLoad.imageView.setImageBitmap(bitmap);
// else
// photoToLoad.imageView.setImageResource(stub_id);
}
}
public void clearCache() {
memoryCache.clear();
fileCache.clear();
}
}
public class FileCache {
private File cacheDir;
public FileCache(Context context){
//Find the dir to save cached images
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"LazyList");
else
cacheDir=context.getCacheDir();
if(!cacheDir.exists())
cacheDir.mkdirs();
}
public File getFile(String url){
//I identify images by hashcode. Not a perfect solution, good for the demo.
String filename=String.valueOf(url.hashCode());
//Another possible solution (thanks to grantland)
//String filename = URLEncoder.encode(url);
File f = new File(cacheDir, filename);
return f;
}
public void clear(){
File[] files=cacheDir.listFiles();
if(files==null)
return;
for(File f:files)
f.delete();
}
}
Related
I am having an app that retrieves information from parse and display into a list view ,but when the app is run and the list view item is clicked it opens a new activity and display some images and text from parse.com but it shows nothing like the image below
Here is my code
main activity.java
public class MainActivity extends Activity
{
ListView listview;
List<ParseObject> ob;
ProgressDialog mProgressDialog;
FinalAdapter adapter;
private List<CodeList> codelist = null;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.beg_layout);
new RemoteDataTask().execute();
}
private class RemoteDataTask extends AsyncTask<Void, Void, Void>
{
#Override
protected void onPreExecute() {
super.onPreExecute();
// Create a progressdialog
mProgressDialog = new ProgressDialog(MainActivity.this);
// Set progressdialog title
mProgressDialog.setTitle("Testing");
// Set progressdialog message
mProgressDialog.setMessage("Loading. Please wait this may take few moments ....");
mProgressDialog.setIndeterminate(true);
// Show progressdialog
mProgressDialog.show();
}
#Override
protected Void doInBackground(Void... params)
{
codelist = new ArrayList<CodeList>();
try{
ParseQuery<ParseObject> query = new ParseQuery<ParseObject>(
"BeginnerActivity");
query.orderByAscending("_created_at");
ob = query.find();
for(ParseObject begactivity : ob){
ParseFile listimg = (ParseFile) begactivity.get("alphabetimg");
ParseFile levelimg = (ParseFile) begactivity.get("levelimg");
ParseFile apiimg = (ParseFile) begactivity.get("apiimg");
ParseFile descimgone = (ParseFile) begactivity.get("descimgone");
ParseFile descimgtwo = (ParseFile) begactivity.get("descimgtwo");
CodeList map = new CodeList();
map.setListHeading((String) begactivity.get("listheading"));
map.setSingleItemHeading((String) begactivity.get("heading"));
map.setDescription((String) begactivity.get("subheading"));
map.setApiText((String) begactivity.get("apitext"));
map.setFinalCodeText((String) begactivity.get("codetext"));
map.setAlphabetimg(listimg.getUrl());
map.setLevelImg(levelimg.getUrl());
map.setApiImg(apiimg.getUrl());
map.setPreviewImgOne(descimgone.getUrl());
map.setPreviewImgTwo(descimgtwo.getUrl());
codelist.add(map);
}
}catch(ParseException e){
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// Locate the listview in listview_main.xml
listview = (ListView) findViewById(R.id.beg_layoutListView);
// Pass the results into ListViewAdapter.java
adapter = new FinalAdapter(MainActivity.this,
codelist);
// Binds the Adapter to the ListView
listview.setAdapter(adapter);
// Close the progressdialog
mProgressDialog.dismiss();
}
}
}
codelist.java
public class CodeList
{
private String alphabetimg;
private String listHeading;
private String levelImg;
private String singleItemHeading;
private String description;
private String apiImg;
private String apiText;
private String previewImgOne;
private String previewImgTwo;
private String finalCodeText;
public void setAlphabetimg(String alphabetimg)
{
this.alphabetimg = alphabetimg;
}
public String getAlphabetimg()
{
return alphabetimg;
}
public void setListHeading(String listHeading)
{
this.listHeading = listHeading;
}
public String getListHeading()
{
return listHeading;
}
public void setLevelImg(String levelImg)
{
this.levelImg = levelImg;
}
public String getLevelImg()
{
return levelImg;
}
public void setSingleItemHeading(String singleItemHeading)
{
this.singleItemHeading = singleItemHeading;
}
public String getSingleItemHeading()
{
return singleItemHeading;
}
public void setDescription(String description)
{
this.description = description;
}
public String getDescription()
{
return description;
}
public void setApiImg(String apiImg)
{
this.apiImg = apiImg;
}
public String getApiImg()
{
return apiImg;
}
public void setApiText(String apiText)
{
this.apiText = apiText;
}
public String getApiText()
{
return apiText;
}
public void setPreviewImgOne(String previewImgOne)
{
this.previewImgOne = previewImgOne;
}
public String getPreviewImgOne()
{
return previewImgOne;
}
public void setPreviewImgTwo(String previewImgTwo)
{
this.previewImgTwo = previewImgTwo;
}
public String getPreviewImgTwo()
{
return previewImgTwo;
}
public void setFinalCodeText(String finalCodeText)
{
this.finalCodeText = finalCodeText;
}
public String getFinalCodeText()
{
return finalCodeText;
}
}
parse application.java
public class ParseApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
// Add your initialization code here
Parse.initialize(this, "4rOrqK23m0nVq187Of3rhDe0TK1R7FObdBWhfX10", "afKA4B9ohvk3M9pZNv9qK2ypbrdOpXi0FPnrXOu6");
ParseUser.enableAutomaticUser();
ParseACL defaultACL = new ParseACL();
// If you would like all objects to be private by default, remove this line.
defaultACL.setPublicReadAccess(true);
ParseACL.setDefaultACL(defaultACL, true);
}
}
final adapter.java
public class FinalAdapter extends BaseAdapter
{
Context context;
LayoutInflater inflater;
ImageLoader imageLoader;
private List<CodeList> codeList = null;
private ArrayList<CodeList> arraylist;
public FinalAdapter(Context context,
List<CodeList> codeList) {
this.context = context;
this.codeList = codeList;
inflater = LayoutInflater.from(context);
this.arraylist = new ArrayList<CodeList>();
this.arraylist.addAll(codeList);
imageLoader = new ImageLoader(context);
}
public class ViewHolder{
TextView listHeading;
ImageView alphabetList;
}
#Override
public int getCount()
{
return codeList.size();
}
#Override
public Object getItem(int position)
{
return codeList.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public View getView(final int position, View view, ViewGroup parent)
{
final ViewHolder holder;
if(view == null){
holder = new ViewHolder();
view = inflater.inflate(R.layout.beg_list_item,null);
holder.listHeading = (TextView) view.findViewById(R.id.beg_list_itemTextView);
holder.alphabetList = (ImageView) view.findViewById(R.id.beg_list_itemImageView);
view.setTag(holder);
}else{
holder = (ViewHolder) view.getTag();
}
holder.listHeading.setText(codeList.get(position).getListHeading());
imageLoader.DisplayImage(codeList.get(position).getAlphabetimg(),
holder.alphabetList);
view.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0){
Intent intent = new Intent(context, SingleItemView.class);
intent.putExtra("listheading",
(codeList.get(position).getListHeading()));
intent.putExtra("alphabetimg",
(codeList.get(position).getAlphabetimg()));
// Start SingleItemView Class
context.startActivity(intent);
}
});
return view;
}
}
singleitemview.java
public class SingleItemView extends Activity.
{
String heading;
String subHeading;
String levelImg;
String apiImg;
String apiText;
String descImgOne;
String descImgTwo;
String codeText;
ImageLoader imgloader = new ImageLoader(this);
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.singleitemview);
Intent i = getIntent();
heading= i.getStringExtra("heading");
subHeading = i.getStringExtra("subheading");
levelImg = i.getStringExtra("levelimg");
apiImg = i.getStringExtra("apiimg");
apiText = i.getStringExtra("apitext");
descImgOne = i.getStringExtra("descimgone");
descImgTwo = i.getStringExtra("descimgtwo");
codeText = i.getStringExtra("codetext");
TextView headingtxt = (TextView)findViewById(R.id.singleitemheading);
TextView subheadingtxt = (TextView)findViewById(R.id.singleitemsubheading);
TextView apitxt = (TextView)findViewById(R.id.singleitemviewapitext);
TextView codetxt = (TextView) findViewById(R.id.singleitemviewcodetext);
ImageView level =(ImageView) findViewById(R.id.levelimg);
ImageView api =(ImageView) findViewById(R.id.singleitemviewapiimg);
ImageView descone =(ImageView) findViewById(R.id.descriptionimgone);
ImageView desctwo =(ImageView) findViewById(R.id.descriptionimgtwo);
headingtxt.setText(heading);
subheadingtxt.setText(subHeading);
apitxt.setText(apiText);
codetxt.setText(codeText);
imgloader.DisplayImage(levelImg, level);
imgloader.DisplayImage(apiImg, api);
imgloader.DisplayImage(descImgOne, descone);
imgloader.DisplayImage(descImgTwo, desctwo);
}
}
image loaded.java
public class ImageLoader {
MemoryCache memoryCache = new MemoryCache();
FileCache fileCache;
private Map<ImageView, String> imageViews = Collections
.synchronizedMap(new WeakHashMap<ImageView, String>());
ExecutorService executorService;
// Handler to display images in UI thread
Handler handler = new Handler();
public ImageLoader(Context context) {
fileCache = new FileCache(context);
executorService = Executors.newFixedThreadPool(5);
}
final int stub_id = R.drawable.temp_img;
public void DisplayImage(String url, ImageView imageView) {
imageViews.put(imageView, url);
Bitmap bitmap = memoryCache.get(url);
if (bitmap != null)
imageView.setImageBitmap(bitmap);
else {
queuePhoto(url, imageView);
imageView.setImageResource(stub_id);
}
}
private void queuePhoto(String url, ImageView imageView) {
PhotoToLoad p = new PhotoToLoad(url, imageView);
executorService.submit(new PhotosLoader(p));
}
private Bitmap getBitmap(String url) {
File f = fileCache.getFile(url);
Bitmap b = decodeFile(f);
if (b != null)
return b;
// Download Images from the Internet
try {
Bitmap bitmap = null;
URL imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) imageUrl
.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
InputStream is = conn.getInputStream();
OutputStream os = new FileOutputStream(f);
Utils.CopyStream(is, os);
os.close();
conn.disconnect();
bitmap = decodeFile(f);
return bitmap;
} catch (Throwable ex) {
ex.printStackTrace();
if (ex instanceof OutOfMemoryError)
memoryCache.clear();
return null;
}
}
// Decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream stream1 = new FileInputStream(f);
BitmapFactory.decodeStream(stream1, null, o);
stream1.close();
// Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE = 70;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE
|| height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
FileInputStream stream2 = new FileInputStream(f);
Bitmap bitmap = BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
// Task for the queue
private class PhotoToLoad {
public String url;
public ImageView imageView;
public PhotoToLoad(String u, ImageView i) {
url = u;
imageView = i;
}
}
class PhotosLoader implements Runnable {
PhotoToLoad photoToLoad;
PhotosLoader(PhotoToLoad photoToLoad) {
this.photoToLoad = photoToLoad;
}
#Override
public void run() {
try {
if (imageViewReused(photoToLoad))
return;
Bitmap bmp = getBitmap(photoToLoad.url);
memoryCache.put(photoToLoad.url, bmp);
if (imageViewReused(photoToLoad))
return;
BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);
handler.post(bd);
} catch (Throwable th) {
th.printStackTrace();
}
}
}
boolean imageViewReused(PhotoToLoad photoToLoad) {
String tag = imageViews.get(photoToLoad.imageView);
if (tag == null || !tag.equals(photoToLoad.url))
return true;
return false;
}
// Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable {
Bitmap bitmap;
PhotoToLoad photoToLoad;
public BitmapDisplayer(Bitmap b, PhotoToLoad p) {
bitmap = b;
photoToLoad = p;
}
public void run() {
if (imageViewReused(photoToLoad))
return;
if (bitmap != null)
photoToLoad.imageView.setImageBitmap(bitmap);
else
photoToLoad.imageView.setImageResource(stub_id);
}
}
public void clearCache() {
memoryCache.clear();
fileCache.clear();
}
}
filecache.java
public class FileCache {
private File cacheDir;
public FileCache(Context context) {
// Find the dir to save cached images
if (android.os.Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED))
cacheDir = new File(
android.os.Environment.getExternalStorageDirectory(),
"ImgTxt");
else
cacheDir = context.getCacheDir();
if (!cacheDir.exists())
cacheDir.mkdirs();
}
public File getFile(String url) {
String filename = String.valueOf(url.hashCode());
// String filename = URLEncoder.encode(url);
File f = new File(cacheDir, filename);
return f;
}
public void clear() {
File[] files = cacheDir.listFiles();
if (files == null)
return;
for (File f : files)
f.delete();
}
}
memorycache.java
public class MemoryCache {
private static final String TAG = "MemoryCache";
// Last argument true for LRU ordering
private Map<String, Bitmap> cache = Collections
.synchronizedMap(new LinkedHashMap<String, Bitmap>(10, 1.5f, true));
// Current allocated size
private long size = 0;
// Max memory in bytes
private long limit = 1000000;
public MemoryCache() {
// Use 25% of available heap size
setLimit(Runtime.getRuntime().maxMemory() / 4);
}
public void setLimit(long new_limit) {
limit = new_limit;
Log.i(TAG, "MemoryCache will use up to " + limit / 1024. / 1024. + "MB");
}
public Bitmap get(String id) {
try {
if (!cache.containsKey(id))
return null;
return cache.get(id);
} catch (NullPointerException ex) {
ex.printStackTrace();
return null;
}
}
public void put(String id, Bitmap bitmap) {
try {
if (cache.containsKey(id))
size -= getSizeInBytes(cache.get(id));
cache.put(id, bitmap);
size += getSizeInBytes(bitmap);
checkSize();
} catch (Throwable th) {
th.printStackTrace();
}
}
private void checkSize() {
Log.i(TAG, "cache size=" + size + " length=" + cache.size());
if (size > limit) {
// Least recently accessed item will be the first one iterated
Iterator<Entry<String, Bitmap>> iter = cache.entrySet().iterator();
while (iter.hasNext()) {
Entry<String, Bitmap> entry = iter.next();
size -= getSizeInBytes(entry.getValue());
iter.remove();
if (size <= limit)
break;
}
Log.i(TAG, "Clean cache. New size " + cache.size());
}
}
public void clear() {
try {
cache.clear();
size = 0;
} catch (NullPointerException ex) {
ex.printStackTrace();
}
}
long getSizeInBytes(Bitmap bitmap) {
if (bitmap == null)
return 0;
return bitmap.getRowBytes() * bitmap.getHeight();
}
}
android manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mycompany.myapp" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name="ParseApplication"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SingleItemView">
</activity>
</application>
</manifest>
In the onclicklistener() add this code
intent.putExtra("levelimg",
(codeList.get(position).getLevelImg()));
intent.putExtra("heading",
(codeList.get(position).getSingleItemHeading()));
intent.putExtra("subheading",
(codeList.get(position).getDescription()));
intent.putExtra("apitext",
(codeList.get(position).getApiText()));
intent.putExtra("apiimg",
(codeList.get(position).getApiImg()));
intent.putExtra("descimgone",
(codeList.get(position).getPreviewImgOne()));
intent.putExtra("descimgtwo",
(codeList.get(position).getPreviewImgTwo()));
intent.putExtra("codetext",
(codeList.get(position).getFinalCodeText()));
My app retrieves information from parse and display it into a list view ,but when the app is run and the list view item is clicked it opens a new activity and display some images and text from parse.com but it shows nothing like the image below
Here is my code
MainActivity
public class MainActivity extends Activity
{
ListView listview;
List<ParseObject> ob;
ProgressDialog mProgressDialog;
FinalAdapter adapter;
private List<CodeList> codelist = null;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.beg_layout);
new RemoteDataTask().execute();
}
private class RemoteDataTask extends AsyncTask<Void, Void, Void>
{
#Override
protected void onPreExecute() {
super.onPreExecute();
// Create a progressdialog
mProgressDialog = new ProgressDialog(MainActivity.this);
// Set progressdialog title
mProgressDialog.setTitle("Testing");
// Set progressdialog message
mProgressDialog.setMessage("Loading. Please wait this may take few moments ....");
mProgressDialog.setIndeterminate(true);
// Show progressdialog
mProgressDialog.show();
}
#Override
protected Void doInBackground(Void... params)
{
codelist = new ArrayList<CodeList>();
try{
ParseQuery<ParseObject> query = new ParseQuery<ParseObject>(
"BeginnerActivity");
query.orderByAscending("_created_at");
ob = query.find();
for(ParseObject begactivity : ob){
ParseFile listimg = (ParseFile) begactivity.get("alphabetimg");
ParseFile levelimg = (ParseFile) begactivity.get("levelimg");
ParseFile apiimg = (ParseFile) begactivity.get("apiimg");
ParseFile descimgone = (ParseFile) begactivity.get("descimgone");
ParseFile descimgtwo = (ParseFile) begactivity.get("descimgtwo");
CodeList map = new CodeList();
map.setListHeading((String) begactivity.get("listheading"));
map.setSingleItemHeading((String) begactivity.get("heading"));
map.setDescription((String) begactivity.get("subheading"));
map.setApiText((String) begactivity.get("apitext"));
map.setFinalCodeText((String) begactivity.get("codetext"));
map.setAlphabetimg(listimg.getUrl());
map.setLevelImg(levelimg.getUrl());
map.setApiImg(apiimg.getUrl());
map.setPreviewImgOne(descimgone.getUrl());
map.setPreviewImgTwo(descimgtwo.getUrl());
codelist.add(map);
}
}catch(ParseException e){
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// Locate the listview in listview_main.xml
listview = (ListView) findViewById(R.id.beg_layoutListView);
// Pass the results into ListViewAdapter.java
adapter = new FinalAdapter(MainActivity.this,
codelist);
// Binds the Adapter to the ListView
listview.setAdapter(adapter);
// Close the progressdialog
mProgressDialog.dismiss();
}
}
}
CodeList
public class CodeList
{
private String alphabetimg;
private String listHeading;
private String levelImg;
private String singleItemHeading;
private String description;
private String apiImg;
private String apiText;
private String previewImgOne;
private String previewImgTwo;
private String finalCodeText;
public void setAlphabetimg(String alphabetimg)
{
this.alphabetimg = alphabetimg;
}
public String getAlphabetimg()
{
return alphabetimg;
}
public void setListHeading(String listHeading)
{
this.listHeading = listHeading;
}
public String getListHeading()
{
return listHeading;
}
public void setLevelImg(String levelImg)
{
this.levelImg = levelImg;
}
public String getLevelImg()
{
return levelImg;
}
public void setSingleItemHeading(String singleItemHeading)
{
this.singleItemHeading = singleItemHeading;
}
public String getSingleItemHeading()
{
return singleItemHeading;
}
public void setDescription(String description)
{
this.description = description;
}
public String getDescription()
{
return description;
}
public void setApiImg(String apiImg)
{
this.apiImg = apiImg;
}
public String getApiImg()
{
return apiImg;
}
public void setApiText(String apiText)
{
this.apiText = apiText;
}
public String getApiText()
{
return apiText;
}
public void setPreviewImgOne(String previewImgOne)
{
this.previewImgOne = previewImgOne;
}
public String getPreviewImgOne()
{
return previewImgOne;
}
public void setPreviewImgTwo(String previewImgTwo)
{
this.previewImgTwo = previewImgTwo;
}
public String getPreviewImgTwo()
{
return previewImgTwo;
}
public void setFinalCodeText(String finalCodeText)
{
this.finalCodeText = finalCodeText;
}
public String getFinalCodeText()
{
return finalCodeText;
}
}
ParseApplication
public class ParseApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
// Add your initialization code here
Parse.initialize(this, "4rOrqK23m0nVq187Of3rhDe0TK1R7FObdBWhfX10", "afKA4B9ohvk3M9pZNv9qK2ypbrdOpXi0FPnrXOu6");
ParseUser.enableAutomaticUser();
ParseACL defaultACL = new ParseACL();
// If you would like all objects to be private by default, remove this line.
defaultACL.setPublicReadAccess(true);
ParseACL.setDefaultACL(defaultACL, true);
}
}
FinalAdapter
public class FinalAdapter extends BaseAdapter
{
Context context;
LayoutInflater inflater;
ImageLoader imageLoader;
private List<CodeList> codeList = null;
private ArrayList<CodeList> arraylist;
public FinalAdapter(Context context,
List<CodeList> codeList) {
this.context = context;
this.codeList = codeList;
inflater = LayoutInflater.from(context);
this.arraylist = new ArrayList<CodeList>();
this.arraylist.addAll(codeList);
imageLoader = new ImageLoader(context);
}
public class ViewHolder{
TextView listHeading;
ImageView alphabetList;
}
#Override
public int getCount()
{
return codeList.size();
}
#Override
public Object getItem(int position)
{
return codeList.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public View getView(final int position, View view, ViewGroup parent)
{
final ViewHolder holder;
if(view == null){
holder = new ViewHolder();
view = inflater.inflate(R.layout.beg_list_item,null);
holder.listHeading = (TextView) view.findViewById(R.id.beg_list_itemTextView);
holder.alphabetList = (ImageView) view.findViewById(R.id.beg_list_itemImageView);
view.setTag(holder);
}else{
holder = (ViewHolder) view.getTag();
}
holder.listHeading.setText(codeList.get(position).getListHeading());
imageLoader.DisplayImage(codeList.get(position).getAlphabetimg(),
holder.alphabetList);
view.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0){
Intent intent = new Intent(context, SingleItemView.class);
intent.putExtra("listheading",
(codeList.get(position).getListHeading()));
intent.putExtra("alphabetimg",
(codeList.get(position).getAlphabetimg()));
// Start SingleItemView Class
context.startActivity(intent);
}
});
return view;
}
}
SingleItemView
public class SingleItemView extends Activity.
{
String heading;
String subHeading;
String levelImg;
String apiImg;
String apiText;
String descImgOne;
String descImgTwo;
String codeText;
ImageLoader imgloader = new ImageLoader(this);
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.singleitemview);
Intent i = getIntent();
heading= i.getStringExtra("heading");
subHeading = i.getStringExtra("subheading");
levelImg = i.getStringExtra("levelimg");
apiImg = i.getStringExtra("apiimg");
apiText = i.getStringExtra("apitext");
descImgOne = i.getStringExtra("descimgone");
descImgTwo = i.getStringExtra("descimgtwo");
codeText = i.getStringExtra("codetext");
TextView headingtxt = (TextView)findViewById(R.id.singleitemheading);
TextView subheadingtxt = (TextView)findViewById(R.id.singleitemsubheading);
TextView apitxt = (TextView)findViewById(R.id.singleitemviewapitext);
TextView codetxt = (TextView) findViewById(R.id.singleitemviewcodetext);
ImageView level =(ImageView) findViewById(R.id.levelimg);
ImageView api =(ImageView) findViewById(R.id.singleitemviewapiimg);
ImageView descone =(ImageView) findViewById(R.id.descriptionimgone);
ImageView desctwo =(ImageView) findViewById(R.id.descriptionimgtwo);
headingtxt.setText(heading);
subheadingtxt.setText(subHeading);
apitxt.setText(apiText);
codetxt.setText(codeText);
imgloader.DisplayImage(levelImg, level);
imgloader.DisplayImage(apiImg, api);
imgloader.DisplayImage(descImgOne, descone);
imgloader.DisplayImage(descImgTwo, desctwo);
}
}
ImageLoader
public class ImageLoader {
MemoryCache memoryCache = new MemoryCache();
FileCache fileCache;
private Map<ImageView, String> imageViews = Collections
.synchronizedMap(new WeakHashMap<ImageView, String>());
ExecutorService executorService;
// Handler to display images in UI thread
Handler handler = new Handler();
public ImageLoader(Context context) {
fileCache = new FileCache(context);
executorService = Executors.newFixedThreadPool(5);
}
final int stub_id = R.drawable.temp_img;
public void DisplayImage(String url, ImageView imageView) {
imageViews.put(imageView, url);
Bitmap bitmap = memoryCache.get(url);
if (bitmap != null)
imageView.setImageBitmap(bitmap);
else {
queuePhoto(url, imageView);
imageView.setImageResource(stub_id);
}
}
private void queuePhoto(String url, ImageView imageView) {
PhotoToLoad p = new PhotoToLoad(url, imageView);
executorService.submit(new PhotosLoader(p));
}
private Bitmap getBitmap(String url) {
File f = fileCache.getFile(url);
Bitmap b = decodeFile(f);
if (b != null)
return b;
// Download Images from the Internet
try {
Bitmap bitmap = null;
URL imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) imageUrl
.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
InputStream is = conn.getInputStream();
OutputStream os = new FileOutputStream(f);
Utils.CopyStream(is, os);
os.close();
conn.disconnect();
bitmap = decodeFile(f);
return bitmap;
} catch (Throwable ex) {
ex.printStackTrace();
if (ex instanceof OutOfMemoryError)
memoryCache.clear();
return null;
}
}
// Decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream stream1 = new FileInputStream(f);
BitmapFactory.decodeStream(stream1, null, o);
stream1.close();
// Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE = 70;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE
|| height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
FileInputStream stream2 = new FileInputStream(f);
Bitmap bitmap = BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
// Task for the queue
private class PhotoToLoad {
public String url;
public ImageView imageView;
public PhotoToLoad(String u, ImageView i) {
url = u;
imageView = i;
}
}
class PhotosLoader implements Runnable {
PhotoToLoad photoToLoad;
PhotosLoader(PhotoToLoad photoToLoad) {
this.photoToLoad = photoToLoad;
}
#Override
public void run() {
try {
if (imageViewReused(photoToLoad))
return;
Bitmap bmp = getBitmap(photoToLoad.url);
memoryCache.put(photoToLoad.url, bmp);
if (imageViewReused(photoToLoad))
return;
BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);
handler.post(bd);
} catch (Throwable th) {
th.printStackTrace();
}
}
}
boolean imageViewReused(PhotoToLoad photoToLoad) {
String tag = imageViews.get(photoToLoad.imageView);
if (tag == null || !tag.equals(photoToLoad.url))
return true;
return false;
}
// Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable {
Bitmap bitmap;
PhotoToLoad photoToLoad;
public BitmapDisplayer(Bitmap b, PhotoToLoad p) {
bitmap = b;
photoToLoad = p;
}
public void run() {
if (imageViewReused(photoToLoad))
return;
if (bitmap != null)
photoToLoad.imageView.setImageBitmap(bitmap);
else
photoToLoad.imageView.setImageResource(stub_id);
}
}
public void clearCache() {
memoryCache.clear();
fileCache.clear();
}
}
MemoryCache
public class MemoryCache {
private static final String TAG = "MemoryCache";
// Last argument true for LRU ordering
private Map<String, Bitmap> cache = Collections
.synchronizedMap(new LinkedHashMap<String, Bitmap>(10, 1.5f, true));
// Current allocated size
private long size = 0;
// Max memory in bytes
private long limit = 1000000;
public MemoryCache() {
// Use 25% of available heap size
setLimit(Runtime.getRuntime().maxMemory() / 4);
}
public void setLimit(long new_limit) {
limit = new_limit;
Log.i(TAG, "MemoryCache will use up to " + limit / 1024. / 1024. + "MB");
}
public Bitmap get(String id) {
try {
if (!cache.containsKey(id))
return null;
return cache.get(id);
} catch (NullPointerException ex) {
ex.printStackTrace();
return null;
}
}
public void put(String id, Bitmap bitmap) {
try {
if (cache.containsKey(id))
size -= getSizeInBytes(cache.get(id));
cache.put(id, bitmap);
size += getSizeInBytes(bitmap);
checkSize();
} catch (Throwable th) {
th.printStackTrace();
}
}
private void checkSize() {
Log.i(TAG, "cache size=" + size + " length=" + cache.size());
if (size > limit) {
// Least recently accessed item will be the first one iterated
Iterator<Entry<String, Bitmap>> iter = cache.entrySet().iterator();
while (iter.hasNext()) {
Entry<String, Bitmap> entry = iter.next();
size -= getSizeInBytes(entry.getValue());
iter.remove();
if (size <= limit)
break;
}
Log.i(TAG, "Clean cache. New size " + cache.size());
}
}
public void clear() {
try {
cache.clear();
size = 0;
} catch (NullPointerException ex) {
ex.printStackTrace();
}
}
long getSizeInBytes(Bitmap bitmap) {
if (bitmap == null)
return 0;
return bitmap.getRowBytes() * bitmap.getHeight();
}
}
FileCache
public class FileCache {
private File cacheDir;
public FileCache(Context context) {
// Find the dir to save cached images
if (android.os.Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED))
cacheDir = new File(
android.os.Environment.getExternalStorageDirectory(),
"ImgTxt");
else
cacheDir = context.getCacheDir();
if (!cacheDir.exists())
cacheDir.mkdirs();
}
public File getFile(String url) {
String filename = String.valueOf(url.hashCode());
// String filename = URLEncoder.encode(url);
File f = new File(cacheDir, filename);
return f;
}
public void clear() {
File[] files = cacheDir.listFiles();
if (files == null)
return;
for (File f : files)
f.delete();
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mycompany.myapp" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name="ParseApplication"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SingleItemView">
</activity>
</application>
</manifest>
I'm looking for an answer half a day, but I can't find anything although I thought it is a common problem. My Problem:
I have a ListView which has items of different sizes (heights). Every item contains an ImageView. The Image for this ImageView is loaded in background by an ImageLoader class:
imageLoader.DisplayImage(url, holder.image);
If i scroll down the ListView everything works fine. the images are loaded and display (of course at the bottom of the screen / list).
But If I scroll up and the image isn't stored in cache anymore, so the ImageLoader has to reload the image, the ListView jumps / the items are moved. I think it is because a new View is created on top of the list, with an ImageView with 0dp height. If the Image is loaded and set to the ImageView the height of the ImageView changes automatically from 0dp to the size of the Image. This would push the ListView down, I think.
I tried saving the height of the ImageViews if an Image is set and then set the height of the ImageView which is created on top to the saved height. But with no success..
I don't know if you can understand my problem :D I hope so :)
Thanks and have a nice day!
EDIT: Added ImageLoader Class
public class ImageLoader {
MemoryCache memoryCache=new MemoryCache();
FileCache fileCache;
int size;
Context context;
private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
private HashMap<String, Integer> imagesSizes;
ExecutorService executorService;
Handler handler=new Handler();//handler to display images in UI thread
public ImageLoader(Context context, int size){
fileCache=new FileCache(context);
this.context = context;
executorService=Executors.newFixedThreadPool(5);
this.size = size;
imagesSizes = new HashMap<String, Integer>();
}
final int stub_id=R.color.transparent;
public void DisplayImage(String url, ImageView imageView)
{
imageViews.put(imageView, url);
Bitmap bitmap=memoryCache.get(url);
if(bitmap!=null){
imageView.setImageBitmap(bitmap);
saveImageSize(imageView, url);
}
else
{
queuePhoto(url, imageView);
imageView.setImageResource(stub_id);
setImageSize(imageView, url);
}
}
public void DisplayImage(File file, ImageView imageView)
{
imageViews.put(imageView, file.getAbsolutePath());
Bitmap bitmap=memoryCache.get(file.getAbsolutePath());
if(bitmap!=null){
imageView.setImageBitmap(bitmap);
saveImageSize(imageView, file.getAbsolutePath());
}
else
{
queuePhoto(file, imageView);
imageView.setImageResource(stub_id);
setImageSize(imageView, file.getAbsolutePath());
}
}
private void saveImageSize(ImageView imageView, String url){
int height = imageView.getHeight();
imagesSizes.put(url, height);
System.out.println("IMAGE SIZE: Save: " + url + " " + height );
}
private void setImageSize(ImageView imageView, String url){
if(imageView != null && imagesSizes!=null && imagesSizes.containsKey(url)){
imageView.getLayoutParams().height = imagesSizes.get(url);
imageView.requestLayout();
System.out.println("IMAGE SIZE: Set: " + url + " " + imagesSizes.get(url) );
}
}
private void queuePhoto(String url, ImageView imageView)
{
PhotoToLoad p=new PhotoToLoad(url, imageView);
executorService.submit(new PhotosLoader(p));
}
private void queuePhoto(File file, ImageView imageView)
{
PhotoToLoad p=new PhotoToLoad(file, imageView);
executorService.submit(new PhotosLoader(p));
}
public Bitmap getImage(String url){
return getBitmap(url);
}
private Bitmap getBitmap(String url)
{
File f=fileCache.getFile(url);
//from SD cache
Bitmap b = decodeFile(f);
if(b!=null)
return b;
//from web
try {
Bitmap bitmap=null;
URL imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
InputStream is=conn.getInputStream();
OutputStream os = new FileOutputStream(f);
Utils.CopyStream(is, os);
os.close();
conn.disconnect();
bitmap = decodeFile(f);
return bitmap;
} catch (Throwable ex){
ex.printStackTrace();
if(ex instanceof OutOfMemoryError)
memoryCache.clear();
return null;
}
}
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream stream1=new FileInputStream(f);
BitmapFactory.decodeStream(stream1,null,o);
stream1.close();
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE=size;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
FileInputStream stream2=new FileInputStream(f);
Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
//Task for the queue
private class PhotoToLoad
{
public File file;
public String url;
public ImageView imageView;
public PhotoToLoad(String u, ImageView i){
url=u;
imageView=i;
file = null;
}
public PhotoToLoad(File file, ImageView i){
url=file.getAbsolutePath();
imageView=i;
this.file = file;
}
}
class PhotosLoader implements Runnable {
PhotoToLoad photoToLoad;
PhotosLoader(PhotoToLoad photoToLoad){
this.photoToLoad=photoToLoad;
}
#Override
public void run() {
try{
if(imageViewReused(photoToLoad))
return;
Bitmap bmp;
if(photoToLoad.file== null){
bmp=getBitmap(photoToLoad.url);
} else {
bmp=decodeFile(photoToLoad.file);
}
memoryCache.put(photoToLoad.url, bmp);
if(imageViewReused(photoToLoad))
return;
BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad);
handler.post(bd);
}catch(Throwable th){
th.printStackTrace();
}
}
}
boolean imageViewReused(PhotoToLoad photoToLoad){
String tag=imageViews.get(photoToLoad.imageView);
if(tag==null || !tag.equals(photoToLoad.url))
return true;
return false;
}
//Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable
{
Bitmap bitmap;
PhotoToLoad photoToLoad;
public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;}
public void run()
{
if(imageViewReused(photoToLoad))
return;
if(bitmap!=null)
photoToLoad.imageView.setImageBitmap(bitmap);
else
photoToLoad.imageView.setImageResource(stub_id);
if(photoToLoad.file== null){
setImageSize(photoToLoad.imageView, photoToLoad.url);
} else {
setImageSize(photoToLoad.imageView, photoToLoad.file.getAbsolutePath());
}
}
}
public void clearCache() {
memoryCache.clear();
fileCache.clear();
}
EDIT: Added Adapter:
public class LazyNewPostsAdapter extends BaseAdapter implements Constants{
private Activity activity;
private ArrayList<Image> data;
private static LayoutInflater inflater=null;
private ImageLoader imageLoader;
private AsyncHelper helper;
public static final int VIEW_TYPE_LOADING = 0;
public static final int VIEW_TYPE_ACTIVITY = 1;
private int imgposition;
Handler fmHandler = null;
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch(msg.what){
case HANDLER_NEW_POST_VOTE_IMAGE:
int position = msg.arg1;
JSONObject json;
try {
json = new JSONObject((String) msg.obj);
int success = json.getInt("success");
if(success == 1){
int i_id = json.getInt("i_id");
int votesUp = json.getInt("votes_up");
int votesDown = json.getInt("votes_down");
data.get(position).setVotesUp(votesUp);
data.get(position).setVotesDown(votesDown);
notifyDataSetChanged();
}
} catch (JSONException e) {
e.printStackTrace();
}
break;
case HANDLER_USER_REPORTED_IMAGE:
JSONObject json2 = Utils.createJSON((String)msg.obj);
System.out.println("REPORT IMAGE " + json2);
if(json2 != null){
try {
int success = json2.getInt("success");
if(success==1){
Toast.makeText(activity, "Image reported!", Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
break;
case HANDLER_IMAGE_SIZE_AVAILABLE:
String url = (String) msg.obj;
int height = msg.arg1;
int width = msg.arg2;
int imgPosition = findImageOfCertainURL(url);
System.out.println("GETVIEW HANDLER 1: IMAGE POSITION" + imgPosition);
if(imgPosition != -1){
data.get(imgPosition).setHeight(height);
data.get(imgPosition).setWidth(width);
}
Message copyMsg = new Message();
copyMsg.what = HANDLER_IMAGE_SIZE_AVAILABLE;
copyMsg.arg1 = height;
copyMsg.arg2 = width;
copyMsg.obj = url;
fmHandler.sendMessage(copyMsg);
notifyDataSetChanged();
break;
}
};
};
private int findImageOfCertainURL(String url){
for(int i = 0; i <data.size();i++){
if((URL_FOLDER_IMAGES + data.get(i).getUrl()).equalsIgnoreCase(url)){
return i;
}
}
return -1;
}
public LazyNewPostsAdapter(Activity a, ArrayList<Image> d, Handler fragmentHandler) {
activity = a;
data=d;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
helper = new AsyncHelper(activity, handler);
imageLoader=new ImageLoader(activity.getApplicationContext(), 600,handler) ;
fmHandler = fragmentHandler;
}
public void updateData(ArrayList<Image> d){
data = d;
notifyDataSetChanged();
}
public int getCount() {
return data.size()+1;
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int position) {
// TODO Auto-generated method stub
return (position >= data.size()) ? VIEW_TYPE_LOADING
: VIEW_TYPE_ACTIVITY;
}
#Override
public boolean isEnabled(int position) {
return getItemViewType(position) == VIEW_TYPE_ACTIVITY;
}
public Object getItem(int position) {
return (getItemViewType(position) == VIEW_TYPE_ACTIVITY) ? data.get(position) : null;
}
public long getItemId(int position) {
return (getItemViewType(position) == VIEW_TYPE_ACTIVITY) ? position
: -1;
}
public View getFooterView(int position, View convertView,
ViewGroup parent) {
// the ListView has reached the last row
TextView tvLastRow = new TextView(activity);
if(AsyncHelper.isDownloadingImages){
tvLastRow.setHint("Requesting new Images..");
} else {
tvLastRow.setHint("Reached the last row.");
}
tvLastRow.setGravity(Gravity.CENTER);
return tvLastRow;
}
private OnClickListener myHotButtonClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
int position = (Integer) v.getTag();
if(ActivityMain.user.isLoggedIn()){
data.get(position).setThisUserVote(1);
helper.vote_image(position, data.get(position).getId(), HOT);
} else {
Toast.makeText(activity, "Login to vote" , Toast.LENGTH_SHORT).show();
}
}
};
private OnClickListener myColdButtonClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
int position = (Integer) v.getTag();
if(ActivityMain.user.isLoggedIn()){
data.get(position).setThisUserVote(2);
helper.vote_image(position, data.get(position).getId(), COLD);
}else {
Toast.makeText(activity, "Login to vote" , Toast.LENGTH_SHORT).show();
}
}
};
private OnClickListener myOptionsButtonClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
final int position = (Integer) v.getTag();
Runnable optionsRunnable = new Runnable() {
#Override
public void run() {
openOptionsDialog(position);
}
};
handler.postDelayed(optionsRunnable, 500);
}
};
private void openOptionsDialog(final int imgposition){
final CharSequence[] items = {"Share", "Save", "Report"};
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("Options");
builder.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
if(item==0){
Utils.shareImage(activity, imageLoader.getImage(URL_FOLDER_IMAGES + data.get(imgposition).getUrl()) , data.get(imgposition).getTitle());
} else if(item==1) {
Utils.saveImage(imageLoader.getImage(URL_FOLDER_IMAGES + data.get(imgposition).getUrl()),activity);
} else if(item==2) {
openReportDialog(imgposition);
}
}
});
AlertDialog alert = builder.create();
alert.show();
}
private void openReportDialog(final int imgposition){
AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style.AppCompatAlertDialogStyle);
builder.setTitle("Report This Image?");
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
helper.reportImage(data.get(imgposition).getId());
}
});
builder.setNegativeButton("No", null);
AlertDialog alert = builder.create();
alert.show();
}
public View getView(final int position, View convertView, ViewGroup parent) {
if (getItemViewType(position) == VIEW_TYPE_LOADING) {
// display the last row
return getFooterView(position, convertView, parent);
}
View vi=convertView;
final ViewHolder holder;
final Image img = data.get(position);
boolean isViNull = false;
if(convertView==null){
vi = inflater.inflate(R.layout.item_new_posts, null);
holder = new ViewHolder();
isViNull = true;
holder.title=(BrushTextView)vi.findViewById(R.id.tv_newposts_title);
holder.image=(RatioImageView)vi.findViewById(R.id.iv_newposts_image);
holder.uploader = (BrushTextView) vi.findViewById(R.id.tv_newposts_uploader);
holder.upvotes = (BrushTextView) vi.findViewById(R.id.tv_newposts_upvotes);
holder.downvotes= (BrushTextView) vi.findViewById(R.id.tv_newposts_downvotes);
holder.options=(LinearLayout)vi.findViewById(R.id.ll_newposts_button_options);
holder.iv_hot=(ImageView)vi.findViewById(R.id.iv_newposts_button_upvote);
holder.iv_cold=(ImageView)vi.findViewById(R.id.iv_newposts_button_downvote);
holder.ll_hot=(LinearLayout)vi.findViewById(R.id.ll_newposts_button_upvote);
holder.ll_cold=(LinearLayout)vi.findViewById(R.id.ll_newposts_button_downvote);
vi.setTag(holder);
} else {
holder = (ViewHolder) vi.getTag();
}
if(img.getHeight() != 0 && img.getWidth() != 0){
holder.image.getLayoutParams().height = img.getHeight();
holder.image.getLayoutParams().width = img.getWidth();
holder.image.requestLayout();
}
holder.ll_hot.setTag(position);
holder.ll_hot.setOnClickListener(myHotButtonClickListener);
holder.ll_cold.setTag(position);
holder.ll_cold.setOnClickListener(myColdButtonClickListener);
holder.options.setTag(position);
holder.options.setOnClickListener(myOptionsButtonClickListener);
changeVoteButtonImages(img, holder.iv_hot, holder.iv_cold);
if(img.getTitle()!=null){
holder.title.setVisibility(View.VISIBLE);
holder.title.setText(img.getTitle());
} else {
holder.title.setVisibility(View.GONE);
}
holder.uploader.setText(img.getUploader());
holder.upvotes.setText(img.getVotesUp()+"");
holder.downvotes.setText(img.getVotesDown()+"");
String url = URL_FOLDER_IMAGES + img.getUrl();
System.out.println("GETVIEW NEW POST ADAPTER: height = " + img.getHeight() + " width = " + img.getWidth());
if(isViNull)
System.out.println("GETVIEW CONVERTVIEW: VI: " +vi.getHeight());
imageLoader.DisplayImage(url, holder.image);
return vi;
}
private void changeVoteButtonImages(Image image, ImageView upvote,ImageView downvote){
switch(image.getThisUserVote()){
case 0:
upvote.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_hot_0));
downvote.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_cold_0));
break;
case 1:
downvote.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_cold_0));
upvote.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_hot_1));
break;
case 2:
upvote.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_hot_0));
downvote.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_cold_1));
break;
}
}
static class ViewHolder {
public BrushTextView title, uploader, upvotes, downvotes;
public ImageView iv_hot,iv_cold;
public LinearLayout options, ll_hot,ll_cold;
public RatioImageView image;
}
}
And here is the Fragment, which contains the ListView
public class Fragment_New_Posts extends Fragment implements Constants, OnRefreshListener{
private static final String ARG_SECTION_NUMBER = "section_number";
private ListView list;
private LazyNewPostsAdapter adapter;
private Images images;
private ArrayList<Image> imagesList;
private SharedPreferences prefs;
private Editor editor;
private int visible_i_id;
private SwipeRefreshLayout swipeLayout;
private int option_image_filter;
private AsyncHelper helper;
private boolean onRefreshFired = false;
private Parcelable state;
public static Fragment_New_Posts newInstance(int sectionNumber) {
Fragment_New_Posts fragment = new Fragment_New_Posts();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public static Fragment_New_Posts newInstance(int sectionNumber, Images imgs) {
Fragment_New_Posts fragment = new Fragment_New_Posts(imgs);
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public void updateImages(Images images, boolean createNew, boolean loadOldImages){
int i_id_position = 0;
this.images = images;
if(!images.hasErrorOccured){
if(this.imagesList == null || createNew || onRefreshFired){
this.imagesList = images.getListOfImages();
} else {
this.imagesList.addAll(images.getListOfImages());
}
}
if(loadOldImages){
i_id_position = this.images.getIDPosition(visible_i_id);
}
if(onRefreshFired){
swipeLayout.setRefreshing(false);
onRefreshFired = false;
}
synchronized (adapter) {
adapter.updateData(this.imagesList);
if(list!=null && createNew){
if(loadOldImages){
list.setSelection(i_id_position);
} else {
list.setSelection(0);
}
}
}
}
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch(msg.what){
case HANDLER_MAIN_IMAGE_UPDATE:
String imagesString = (String) msg.obj;
Images imgs = new Images(imagesString);
updateImages(imgs, false, false);
if(imgs.hasErrorOccured){
Toast.makeText(getActivity(), "Can\'t get new Images", Toast.LENGTH_SHORT).show();
}
break;
case HANDLER_IMAGE_SIZE_AVAILABLE:
String url = (String) msg.obj;
int height = msg.arg1;
int width = msg.arg2;
int imgPosition = findImageOfCertainURL(url);
System.out.println("GETVIEW HANDLER 2: IMAGE POSITION" + imgPosition);
if(imgPosition != -1){
imagesList.get(imgPosition).setHeight(height);
imagesList.get(imgPosition).setWidth(width);
}
break;
}
};
};
private int findImageOfCertainURL(String url){
for(int i = 0; i <imagesList.size();i++){
if((URL_FOLDER_IMAGES + imagesList.get(i).getUrl()).equalsIgnoreCase(url)){
return i;
}
}
return -1;
}
public Fragment_New_Posts() {
}
public Fragment_New_Posts(Images imgs) {
this.images = imgs;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
System.out.println("NEW POST FRAGMENT ONCREATE");
View rootView = inflater.inflate(R.layout.fragment_new_posts, container, false);
prefs = getActivity().getSharedPreferences(PREF_WOODU, getActivity().MODE_PRIVATE);
editor = prefs.edit();
if(prefs!=null){
visible_i_id = prefs.getInt(PREF_NEW_POSTS_VISIBLE_I_ID, 0);
option_image_filter = prefs.getInt(PHP_TAG_IMAGE_FILTER, 0);
}
swipeLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swipe_container);
swipeLayout.setColorSchemeColors(R.color.red_hot);
swipeLayout.setOnRefreshListener(this);
helper = new AsyncHelper(getActivity(), handler);
imagesList = new ArrayList<Image>();
if(images != null){
imagesList = images.getListOfImages();
System.out.println("SAVE IMAGES: load: imgsList " + imagesList);
}
list = (ListView) rootView.findViewById(R.id.lv_new_posts);
adapter = new LazyNewPostsAdapter(getActivity(), imagesList, handler);
list.setAdapter(adapter);
list.setOnScrollListener(new EndlessScrollListener() {
#Override
public void onLoadMore(int page, int totalItemsCount) {
if(imagesList!=null && imagesList.size()!=0){
helper.getImageUpdate(imagesList.get(imagesList.size()-1).getId(), option_image_filter);
}
}
});
if(images != null){
updateImages(images, true, true);
}
return rootView;
}
#Override
public void onPause() {
int lastVisposition = list.getLastVisiblePosition();
if(lastVisposition>=0 && lastVisposition < this.imagesList.size()){
visible_i_id = this.imagesList.get(list.getFirstVisiblePosition()).getId();
editor.putInt(PREF_NEW_POSTS_VISIBLE_I_ID, visible_i_id);
editor.commit();
}
super.onPause();
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onDestroy() {
if(images != null){
editor.putString(PREF_NEW_POSTS_CURRENT_IMAGES, Utils.createJSONStringFromImageArrayList(imagesList, editor));
editor.commit();
}
super.onDestroy();
}
#Override
public void onRefresh() {
onRefreshFired = true;
if(prefs!=null){
option_image_filter = prefs.getInt(PHP_TAG_IMAGE_FILTER, 0);
}
helper.getImageUpdate(0, option_image_filter);
}
}
Now here are many many information and code. I hope that does not scare anyone to help :D
Thanks!!
Please, Please , Please don't "re-invent the Wheel" and use any lib out there for image loading, caching etc like Picasso, Fresco , Glide etc....
I probably solved the Problem.. Finally.. My idea of setting the height of the ImageView in getView wasn't so bad.. problem was:
My ImageView was wrapped inside a CardView in XML.. So I needed to change the Height of the CardView instead of the ImageView :)
WeakHashMap ... you are using weak references. Which does right that. Deletes objects when used no more. So, just change it to HashMap and you should be doing fine.
I have a listView with an adapter loading images from URLs through a ImageLoader class.
The problem is, the images on the screen are not displayed/loaded until the list item has been scrolled off screen.
So basically, the listView is shown, but no images are loaded until you scroll down and scroll back up again. This aplies to all the items in the list, when displaying them the first time no images are loaded until you scroll back to them.
I have not written the ImageLoader class myself and Im having a hard time understanding exactly why the images don't load on the first displaying. Have tried alot of different things with the queue but nothing seems to help.
The ImageLoader class:
public class ImageLoader {
//the simplest in-memory cache implementation. This should be replaced with something like SoftReference or BitmapOptions.inPurgeable(since 1.6)
private HashMap<String, Bitmap> cache=new HashMap<String, Bitmap>();
private File cacheDir;
public ImageLoader(Context context){
//Make the background thead low priority. This way it will not affect the UI performance
photoLoaderThread.setPriority(Thread.NORM_PRIORITY-1);
//Find the dir to save cached images
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"LazyList");
else
cacheDir=context.getCacheDir();
if(!cacheDir.exists())
cacheDir.mkdirs();
}
final int stub_id=R.drawable.nopic;
public void DisplayImage(String url, Activity activity, ImageView imageView, ProgressBar progressBar)
{
if(cache.containsKey(url)){
imageView.setImageBitmap(cache.get(url));
if (progressBar != null){
progressBar.setVisibility(View.GONE);
imageView.setVisibility(View.VISIBLE);
}
}else{
queuePhoto(url, activity, imageView, progressBar);
if(progressBar != null){
imageView.setVisibility(View.GONE); //ADDED
progressBar.setVisibility(View.VISIBLE);
} else {
imageView.setImageResource(stub_id);
}
}
}
private void queuePhoto(String url, Activity activity, ImageView imageView, ProgressBar progressBar)
{
//This ImageView may be used for other images before. So there may be some old tasks in the queue. We need to discard them.
photosQueue.Clean(imageView);
PhotoToLoad p = new PhotoToLoad(url, imageView, progressBar);
synchronized(photosQueue.photosToLoad){
photosQueue.photosToLoad.push(p);
photosQueue.photosToLoad.notifyAll();
}
//start thread if it's not started yet
if(photoLoaderThread.getState()==Thread.State.NEW)
photoLoaderThread.start();
}
private Bitmap getBitmap(String url)
{
//I identify images by hashcode. Not a perfect solution, good for the demo.
String filename=String.valueOf(url.hashCode());
File f=new File(cacheDir, filename);
//from SD cache
Bitmap b = decodeFile(f);
if(b!=null)
return b;
//from web
try {
Bitmap bitmap=null;
InputStream is=new URL(url).openStream();
OutputStream os = new FileOutputStream(f);
Utils.CopyStream(is, os);
os.close();
bitmap = decodeFile(f);
return bitmap;
} catch (Exception ex){
ex.printStackTrace();
return null;
}
}
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//Find the correct scale value. It should be the power of 2.
int requiredSize = 100;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<requiredSize || height_tmp/2<requiredSize)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
//Task for the queue
private class PhotoToLoad
{
public String url;
public ImageView imageView;
public ProgressBar progressBar;
public PhotoToLoad(String u, ImageView i, ProgressBar p){
url=u;
imageView=i;
progressBar = p;
}
}
PhotosQueue photosQueue=new PhotosQueue();
public void stopThread(){
photoLoaderThread.interrupt();
}
//stores list of photos to download
class PhotosQueue
{
private Stack<PhotoToLoad> photosToLoad=new Stack<PhotoToLoad>();
//removes all instances of this ImageView
public void Clean(ImageView image)
{
for(int j=0 ;j<photosToLoad.size();){
if(photosToLoad.get(j).imageView==image)
photosToLoad.remove(j);
else
++j;
}
}
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// PHOTOSLOADER: Thread
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
class PhotosLoader extends Thread {
public void run() {
try {
while(true)
{
//thread waits until there are any images to load in the queue
if(photosQueue.photosToLoad.size() == 0)
synchronized(photosQueue.photosToLoad){
photosQueue.photosToLoad.wait();
}
if(photosQueue.photosToLoad.size() != 0)
{
PhotoToLoad photoToLoad;
synchronized(photosQueue.photosToLoad){
photoToLoad = photosQueue.photosToLoad.pop(); photosQueue.photosToLoad.remove(photoToLoad);
}
Bitmap bmp = getBitmap(photoToLoad.url);
cache.put(photoToLoad.url, bmp);
Object tag = photoToLoad.imageView.getTag();
if(tag != null && ((String)tag).equals(photoToLoad.url)){
BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad.imageView, photoToLoad.progressBar);
Activity a = (Activity)photoToLoad.imageView.getContext();
a.runOnUiThread(bd);
}
}
if(Thread.interrupted())
break;
}
} catch (InterruptedException e) {
//allow thread to exit
}
}
}
PhotosLoader photoLoaderThread = new PhotosLoader();
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// BITMAP DISPLAYER
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable{
Bitmap bitmap;
ImageView imageView;
ProgressBar progressBar;
public BitmapDisplayer(Bitmap b, ImageView i, ProgressBar p){
bitmap = b;
imageView = i;
progressBar = p;
}
public void run(){
if(bitmap != null){
imageView.setImageBitmap(bitmap);
if (progressBar != null){
imageView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
}
}else{
if (progressBar != null){
progressBar.setVisibility(View.VISIBLE);
imageView.setVisibility(View.GONE);
}
}
}
}
public void clearCache() {
//clear memory cache
cache.clear();
//clear SD cache
File[] files = cacheDir.listFiles();
for(File f:files)
f.delete();
}
}
The Adapter:
public class Adapter_Agenda extends BaseAdapter {
// DEBUG
private final String TAG = this.getClass().getSimpleName();
private LayoutInflater inflater = null;
public ViewHolder holder;
private ArrayList<Agenda> agendas;
UnixTimeToStringConverter unixConverter;
ImageLoader imageLoader;
View vi;
public Adapter_Agenda(Context context, ArrayList<Agenda> agendas) {
this.agendas = agendas;
unixConverter = new UnixTimeToStringConverter();
imageLoader = new ImageLoader(context);
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
return agendas.size();
}
#Override
public Agenda getItem(int position) {
return agendas.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
vi = convertView;
if(convertView == null){
vi = inflater.inflate(R.layout.item_list_agenda, null);
holder = new ViewHolder();
holder.header = (TextView)vi.findViewById(R.id.item_list_header);
holder.image = (ImageView)vi.findViewById(R.id.item_list_image);
holder.time = (TextView)vi.findViewById(R.id.item_list_time);
holder.description = (TextView)vi.findViewById(R.id.item_list_description);
vi.setTag(holder);
holder = (ViewHolder)vi.getTag();
} else {
holder = (ViewHolder)vi.getTag();
}
holder.header.setText(agendas.get(position).getHeader());
imageLoader.DisplayImage(agendas.get(position).getImageURL(), activity, holder.image, null);
holder.time.setText(unixConverter.getUnixDateFormated(agendas.get(position).getStartTime()));
return vi;
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// VIEWHOLDER
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
public class ViewHolder{
public TextView time;
public ImageView image;
public TextView header;
public TextView description;
}
}
just put
holder.image.setTag(agendas.get(position).getImageURL());
before
imageLoader.DisplayImage(agendas.get(position).getImageURL(), activity, holder.image, null);
The Image will be downloaded in a new Thread. So what you are doing is an async file download.
The problem is that you "use" your image BEFORE it's actually downloaded. As a result no image can be shown.
What you have to do:
Create sth like a callback when a image has been downloaded. You can achive this by creating a interface which will be implemented by your adapter.
Whenever the interface method is been called you know, that an image has been downloaded and you can notify the adapter by calling "notifyDatasetChange()".
I have a custom ListView adapter which implements an ImageThreadLoader class. Unfortunately the class doesn't enable a cache option-download the images from the web and save them as cache.
And then I found this LazyList or here really useful, it behaves quite the same like my ImageThreadLoader class but it's able to save the images as cache. So, I want to implement its ImageLoader class to my current custom ListView adapter.
Unfortunately the structure of my codes and the Lazylist's is quite different, resulting some conflicts on my attempts.
For example, the LazyList use array of strings for the image URL, in the other hand I use JSON as the source of image URL.
That's why I need a help here to adapt my ListView adapter to this ImageLoader class.
Here are the codes:
ImageLoader Class which I want implement to my custom ListView adapter:
public class ImageLoader {
//the simplest in-memory cache implementation. This should be replaced with something like SoftReference or BitmapOptions.inPurgeable(since 1.6)
private HashMap<String, Bitmap> cache=new HashMap<String, Bitmap>();
private File cacheDir;
public ImageLoader(Context context){
//Make the background thead low priority. This way it will not affect the UI performance
photoLoaderThread.setPriority(Thread.NORM_PRIORITY-1);
//Find the dir to save cached images
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"Android/data/LazyList");
else
cacheDir=context.getCacheDir();
if(!cacheDir.exists())
cacheDir.mkdirs();
}
final int stub_id=R.drawable.stub;
public void DisplayImage(String url, Activity activity, ImageView imageView)
{
if(cache.containsKey(url))
imageView.setImageBitmap(cache.get(url));
else
{
queuePhoto(url, activity, imageView);
imageView.setImageResource(stub_id);
}
}
private void queuePhoto(String url, Activity activity, ImageView imageView)
{
//This ImageView may be used for other images before. So there may be some old tasks in the queue. We need to discard them.
photosQueue.Clean(imageView);
PhotoToLoad p=new PhotoToLoad(url, imageView);
synchronized(photosQueue.photosToLoad){
photosQueue.photosToLoad.push(p);
photosQueue.photosToLoad.notifyAll();
}
//start thread if it's not started yet
if(photoLoaderThread.getState()==Thread.State.NEW)
photoLoaderThread.start();
}
private Bitmap getBitmap(String url)
{
//I identify images by hashcode. Not a perfect solution, good for the demo.
String filename=String.valueOf(url.hashCode());
File f=new File(cacheDir, filename);
//from SD cache
Bitmap b = decodeFile(f);
if(b!=null)
return b;
//from web
try {
Bitmap bitmap=null;
InputStream is=new URL(url).openStream();
OutputStream os = new FileOutputStream(f);
Utils.CopyStream(is, os);
os.close();
bitmap = decodeFile(f);
return bitmap;
} catch (Exception ex){
ex.printStackTrace();
return null;
}
}
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE=70;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
//Task for the queue
private class PhotoToLoad
{
public String url;
public ImageView imageView;
public PhotoToLoad(String u, ImageView i){
url=u;
imageView=i;
}
}
PhotosQueue photosQueue=new PhotosQueue();
public void stopThread()
{
photoLoaderThread.interrupt();
}
//stores list of photos to download
class PhotosQueue
{
private Stack<PhotoToLoad> photosToLoad=new Stack<PhotoToLoad>();
//removes all instances of this ImageView
public void Clean(ImageView image)
{
for(int j=0 ;j<photosToLoad.size();){
if(photosToLoad.get(j).imageView==image)
photosToLoad.remove(j);
else
++j;
}
}
}
class PhotosLoader extends Thread {
public void run() {
try {
while(true)
{
//thread waits until there are any images to load in the queue
if(photosQueue.photosToLoad.size()==0)
synchronized(photosQueue.photosToLoad){
photosQueue.photosToLoad.wait();
}
if(photosQueue.photosToLoad.size()!=0)
{
PhotoToLoad photoToLoad;
synchronized(photosQueue.photosToLoad){
photoToLoad=photosQueue.photosToLoad.pop();
}
Bitmap bmp=getBitmap(photoToLoad.url);
cache.put(photoToLoad.url, bmp);
Object tag=photoToLoad.imageView.getTag();
if(tag!=null && ((String)tag).equals(photoToLoad.url)){
BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad.imageView);
Activity a=(Activity)photoToLoad.imageView.getContext();
a.runOnUiThread(bd);
}
}
if(Thread.interrupted())
break;
}
} catch (InterruptedException e) {
//allow thread to exit
}
}
}
PhotosLoader photoLoaderThread=new PhotosLoader();
//Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable
{
Bitmap bitmap;
ImageView imageView;
public BitmapDisplayer(Bitmap b, ImageView i){bitmap=b;imageView=i;}
public void run()
{
if(bitmap!=null)
imageView.setImageBitmap(bitmap);
else
imageView.setImageResource(stub_id);
}
}
public void clearCache() {
//clear memory cache
cache.clear();
//clear SD cache
File[] files=cacheDir.listFiles();
for(File f:files)
f.delete();
}
}
the custom list view adapter from the LazyList project:
public class LazyAdapter extends BaseAdapter {
private Activity activity;
private String[] data;
private static LayoutInflater inflater=null;
public ImageLoader imageLoader;
public LazyAdapter(Activity a, String[] d) {
activity = a;
data=d;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader=new ImageLoader(activity.getApplicationContext());
}
public int getCount() {
return data.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public static class ViewHolder{
public TextView text;
public ImageView image;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
ViewHolder holder;
if(convertView==null){
vi = inflater.inflate(R.layout.item, null);
holder=new ViewHolder();
holder.text=(TextView)vi.findViewById(R.id.text);;
holder.image=(ImageView)vi.findViewById(R.id.image);
vi.setTag(holder);
}
else
holder=(ViewHolder)vi.getTag();
holder.text.setText("item "+position);
holder.image.setTag(data[position]);
imageLoader.DisplayImage(data[position], activity, holder.image);
return vi;
}
}
and here's my custom ListView adapter:
ProjectAdapter class
public class ProjectAdapter extends ArrayAdapter<Project> {
int resource;
String response;
Context context;
private final static String TAG = "MediaItemAdapter";
private ImageThreadLoader imageLoader = new ImageThreadLoader();
//Initialize adapter
public ProjectAdapter(Context context, int resource, List<Project> items) {
super(context, resource, items);
this.resource=resource;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
TextView textTitle;
final ImageView image;
Project pro = getItem(position);
LinearLayout projectView;
//Inflate the view
if(convertView==null)
{
projectView = new LinearLayout(getContext());
String inflater = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater vi;
vi = (LayoutInflater)getContext().getSystemService(inflater);
vi.inflate(resource, projectView, true);
}
else
{
projectView = (LinearLayout) convertView;
}
try {
textTitle = (TextView)projectView.findViewById(R.id.txt_title);
image = (ImageView)projectView.findViewById(R.id.image);
} catch( ClassCastException e ) {
Log.e(TAG, "Your layout must provide an image and a text view with ID's icon and text.", e);
throw e;
}
Bitmap cachedImage = null;
try {
cachedImage = imageLoader.loadImage(pro.smallImageUrl, new ImageLoadedListener() {
public void imageLoaded(Bitmap imageBitmap) {
image.setImageBitmap(imageBitmap);
notifyDataSetChanged(); }
});
} catch (MalformedURLException e) {
Log.e(TAG, "Bad remote image URL: " + pro.smallImageUrl, e);
}
textTitle.setText(pro.project_title);
if( cachedImage != null ) {
image.setImageBitmap(cachedImage);
}
return projectView;
}
}
Thank you very much!!
EDIT
UPDATED:
ProjectList Activity
public class ProjectsList extends Activity {
/** Called when the activity is first created. */
//ListView that will hold our items references back to main.xml
ListView lstTest;
//Array Adapter that will hold our ArrayList and display the items on the ListView
ProjectAdapter arrayAdapter;
ProgressDialog dialog;
//List that will host our items and allow us to modify that array adapter
ArrayList<Project> prjcts=null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.projects_list);
//Initialize ListView
lstTest= (ListView)findViewById(R.id.lstText);
//Initialize our ArrayList
prjcts = new ArrayList<Project>();
//Initialize our array adapter notice how it references the listitems.xml layout
arrayAdapter = new ProjectAdapter(ProjectsList.this, R.layout.listitems,prjcts,ProjectsList.this);
//Set the above adapter as the adapter of choice for our list
lstTest.setAdapter(arrayAdapter);
if (isOnline())
{
//Instantiate the Web Service Class with he URL of the web service not that you must pass
//WebService webService = new WebService("http://notalentrocks.com/myplaceapp/projects.json");
WebService webService = new WebService("http://liebenwald.spendino.net/admanager/dev/android/projects.json");
//Pass the parameters if needed , if not then pass dummy one as follows
Map<String, String> params = new HashMap<String, String>();
params.put("var", "");
//Get JSON response from server the "" are where the method name would normally go if needed example
// webService.webGet("getMoreAllerts", params);
String response = webService.webGet("", params);
try
{
dialog = ProgressDialog.show(ProjectsList.this, "", "Fetching Projects...", true);
dialog.setCancelable(true);
dialog.setCanceledOnTouchOutside(true);
dialog.setOnCancelListener(new OnCancelListener() {
public void onCancel(DialogInterface dialog) {
}
});
//Parse Response into our object
Type collectionType = new TypeToken<ArrayList<Project>>(){}.getType();
//JSON expects an list so can't use our ArrayList from the lstart
List<Project> lst= new Gson().fromJson(response, collectionType);
//Now that we have that list lets add it to the ArrayList which will hold our items.
for(Project l : lst)
{
prjcts.add(l);
ConstantData.projectsList.add(l);
}
//Since we've modified the arrayList we now need to notify the adapter that
//its data has changed so that it updates the UI
arrayAdapter.notifyDataSetChanged();
dialog.dismiss();
}
catch(Exception e)
{
Log.d("Error: ", e.getMessage());
}
}
lstTest.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent care = new Intent(ProjectsList.this, ProjectDetail.class);
care.putExtra("spendino.de.ProjectDetail.position",position);
startActivity(care);
}
});
}
protected boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnected()) {
return true;
} else {
AlertDialog.Builder alertbox = new AlertDialog.Builder(this);
alertbox.setTitle("spendino Helfomat");
alertbox.setMessage ("Please check your internet connection");
alertbox.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//Main.this.finish();
}
});
alertbox.show();
return false;
}
}
}
UPDATED
Here's my stacktrace:
05-12 11:36:52.670: ERROR/AndroidRuntime(299): Caused by: java.lang.NullPointerException
05-12 11:36:52.670: ERROR/AndroidRuntime(299): at android.content.ContextWrapper.getCacheDir(ContextWrapper.java:183)
05-12 11:38:29.386: ERROR/AndroidRuntime(324): at spendino.de.ImageLoader.<init>(ImageLoader.java:41)
05-12 11:36:52.670: ERROR/AndroidRuntime(299): at spendino.de.Main.<init>(Main.java:56)
ImageLoader 41 is: cacheDir=context.getCacheDir();
Main 56 is: private ImageLoaderCache imageLoader = new ImageLoaderCache(Main.this);
Main.java
public class Main extends Activity {
/** Called when the activity is first created. */
ArrayList<Project> prjcts=null;
private final static String TAG = "MediaItemAdapter";
ImageLoader imageLoader;
private Activity activity;
ImageView image1;
ImageView image2;
ImageView image3;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (isOnline())
{
prjcts = new ArrayList<Project>();
WebService webService = new WebService("http://liebenwald.spendino.net/admanager/dev/android/projects.json");
Map<String, String> params = new HashMap<String, String>();
params.put("var", "");
String response = webService.webGet("", params);
imageLoader = new ImageLoader(Main.this);
try
{
Type collectionType = new TypeToken<ArrayList<Project>>(){}.getType();
List<Project> lst= new Gson().fromJson(response, collectionType);
for(Project l : lst)
{
prjcts.add(l);
ConstantData.projectsList.add(l);
}
}
catch(Exception e)
{
Log.d("Error: ", e.getMessage());
}
try {
image1 = (ImageView)findViewById(R.id.top1);
image2 = (ImageView)findViewById(R.id.top2);
image3 = (ImageView)findViewById(R.id.top3);
} catch( ClassCastException e ) {
Log.e(TAG, "Your layout must provide an image and a text view with ID's icon and text.", e);
throw e;
}
//randomize the index of image entry
int max = prjcts.size();
List<Integer> indices = new ArrayList<Integer>(max);
for(int c = 1; c < max; ++c)
{
indices.add(c);
}
Random r = new Random();
int arrIndex = r.nextInt(indices.size());
int randomIndex1 = indices.get(arrIndex);
indices.remove(arrIndex);
int arrIndex2 = r.nextInt(indices.size());
int randomIndex2 = indices.get(arrIndex2);
indices.remove(arrIndex2);
int arrIndex3 = r.nextInt(indices.size());
int randomIndex3 = indices.get(arrIndex3);
indices.remove(arrIndex3);
imageLazy(image1, prjcts.get(randomIndex1));
imageLazy(image2, prjcts.get(randomIndex2));
imageLazy(image3, prjcts.get(randomIndex3));
image1.setOnClickListener(new RandomClickListener(randomIndex1));
image2.setOnClickListener(new RandomClickListener(randomIndex2));
image3.setOnClickListener(new RandomClickListener(randomIndex3));
}
final Button project = (Button) findViewById(R.id.btn_projectslist);
final Button infos = (Button) findViewById(R.id.btn_infos);
final Button contact = (Button) findViewById(R.id.btn_contact);
project.setOnClickListener(project_listener);
infos.setOnClickListener(infos_listener);
contact.setOnClickListener(contact_listener);
}
/*
* isOnline - Check if there is a NetworkConnection
* #return boolean
*/
protected boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnected()) {
return true;
} else {
AlertDialog.Builder alertbox = new AlertDialog.Builder(this);
alertbox.setTitle("spendino Helfomat");
alertbox.setMessage ("Bitte überprüfen Sie Ihre Internetverbindung");
alertbox.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Main.this.finish();
}
});
alertbox.show();
return false;
}
}
public static class ViewHolder{
public ImageView image;
}
public void imageLazy(final ImageView image,Project pro)
{
imageLoadery.displayImage(pro.smallImageUrl, activity, image);
}
public void setImage(Bitmap cachedImage, final ImageView image, Project pro)
{
try {
cachedImage = imageLoader.loadImage(pro.smallImageUrl, new ImageLoadedListener()
{
public void imageLoaded(Bitmap imageBitmap)
{
image.setImageBitmap(imageBitmap);
}
});
} catch (MalformedURLException e) {
Log.e(TAG, "Bad remote image URL: " + pro.smallImageUrl, e);
}
if( cachedImage != null ) {
image.setImageBitmap(cachedImage);
}
}
public class RandomClickListener implements View.OnClickListener
{
private final int randomIndex;
public RandomClickListener(final int randomIndex)
{
this.randomIndex = randomIndex;
}
#Override
public void onClick(View v)
{
Intent top = new Intent(Main.this, ProjectDetail.class);
top.putExtra("spendino.de.ProjectDetail.position", randomIndex);
startActivity(top);
}
}
Stacktrace:
05-12 13:48:12.606: ERROR/AndroidRuntime(433): at spendino.de.ImageLoaderCache$PhotosLoader.run(ImageLoaderCache.java:244)
Seems that you did not use any view holder in your adapter
I have made changes in your classes.Hope it will works for you with out any difficulties
The ImageThreadLoader class
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Stack;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;
public class ImageThreadLoader {
//the simplest in-memory cache implementation. This should be replaced with something like SoftReference or BitmapOptions.inPurgeable(since 1.6)
/** The cache. */
private HashMap<String, Bitmap> cache=new HashMap<String, Bitmap>();
/** The cache dir. */
private File cacheDir;
/**
* Instantiates a new image loader.
*
* #param context the context
*/
public ImageThreadLoader(Context context){
//Make the background thead low priority. This way it will not affect the UI performance
photoLoaderThread.setPriority(Thread.NORM_PRIORITY-1);
//Find the dir to save cached images
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"cache_dir_img");
else
cacheDir=context.getCacheDir();
if(!cacheDir.exists())
cacheDir.mkdirs();
}
//This is used for a stub when the user can not see the actual image..
//this images will be seen
final int stub_id =R.drawable.sample_image;
/**
* Display image.
*
* #param url the url
* #param activity the activity
* #param imageView the image view
*/
public void displayImage(String url, Activity activity, ImageView imageView)
{
if(cache.containsKey(url))
imageView.setImageBitmap(cache.get(url));
else
{
queuePhoto(url, activity, imageView);
imageView.setImageResource(stub_id);
}
}
/**
* Queue photo.
*
* #param url the url
* #param activity the activity
* #param imageView the image view
*/
private void queuePhoto(String url, Activity activity, ImageView imageView)
{
//This ImageView may be used for other images before. So there may be some old tasks in the queue. We need to discard them.
photosQueue.Clean(imageView);
PhotoToLoad p=new PhotoToLoad(url, imageView);
synchronized(photosQueue.photosToLoad){
photosQueue.photosToLoad.push(p);
photosQueue.photosToLoad.notifyAll();
}
//start thread if it's not started yet
if(photoLoaderThread.getState()==Thread.State.NEW)
photoLoaderThread.start();
}
/**
* Gets the bitmap.
*
* #param url the url
* #return the bitmap
*/
private Bitmap getBitmap(String url)
{
//I identify images by hashcode. Not a perfect solution, good for the demo.
String filename=String.valueOf(url.hashCode());
File f=new File(cacheDir, filename);
//from SD cache
Bitmap b = decodeFile(f);
if(b!=null)
return b;
//from web
try {
Bitmap bitmap=null;
InputStream is=new URL(url).openStream();
OutputStream os = new FileOutputStream(f);
copyStream(is, os);
os.close();
bitmap = decodeFile(f);
return bitmap;
} catch (Exception ex){
ex.printStackTrace();
return null;
}
}
//decodes image and scales it to reduce memory consumption
/**
* Decode file.
*
* #param f the f
* #return the bitmap
*/
private Bitmap decodeFile(File f){
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE=70;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale++;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
//Task for the queue
/**
* The Class PhotoToLoad.
*/
private class PhotoToLoad
{
/** The url. */
public String url;
/** The image view. */
public ImageView imageView;
/**
* Instantiates a new photo to load.
*
* #param u the u
* #param i the i
*/
public PhotoToLoad(String u, ImageView i){
url=u;
imageView=i;
}
}
/** The photos queue. */
PhotosQueue photosQueue=new PhotosQueue();
/**
* Stop thread.
*/
public void stopThread()
{
photoLoaderThread.interrupt();
}
//stores list of photos to download
/**
* The Class PhotosQueue.
*/
class PhotosQueue
{
/** The photos to load. */
private Stack<PhotoToLoad> photosToLoad=new Stack<PhotoToLoad>();
//removes all instances of this ImageView
/**
* Clean.
*
* #param image the image
*/
public void Clean(ImageView image)
{
for(int j=0 ;j<photosToLoad.size();){
if(photosToLoad.get(j).imageView==image)
photosToLoad.remove(j);
else
++j;
}
}
}
/**
* The Class PhotosLoader.
*/
class PhotosLoader extends Thread {
/* (non-Javadoc)
* #see java.lang.Thread#run()
*/
public void run() {
try {
while(true)
{
//thread waits until there are any images to load in the queue
if(photosQueue.photosToLoad.size()==0)
synchronized(photosQueue.photosToLoad){
photosQueue.photosToLoad.wait();
}
if(photosQueue.photosToLoad.size()!=0)
{
PhotoToLoad photoToLoad;
synchronized(photosQueue.photosToLoad){
photoToLoad=photosQueue.photosToLoad.pop();
}
Bitmap bmp=getBitmap(photoToLoad.url);
cache.put(photoToLoad.url, bmp);
if(((String)photoToLoad.imageView.getTag()).equals(photoToLoad.url)){
BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad.imageView);
Activity a=(Activity)photoToLoad.imageView.getContext();
a.runOnUiThread(bd);
}
}
if(Thread.interrupted())
break;
}
} catch (InterruptedException e) {
//allow thread to exit
}
}
}
/** The photo loader thread. */
PhotosLoader photoLoaderThread=new PhotosLoader();
//Used to display bitmap in the UI thread
/**
* The Class BitmapDisplayer.
*/
class BitmapDisplayer implements Runnable
{
/** The bitmap. */
Bitmap bitmap;
/** The image view. */
ImageView imageView;
/**
* Instantiates a new bitmap displayer.
*
* #param b the b
* #param i the i
*/
public BitmapDisplayer(Bitmap b, ImageView i){bitmap=b;imageView=i;}
/* (non-Javadoc)
* #see java.lang.Runnable#run()
*/
public void run()
{
if(bitmap!=null)
imageView.setImageBitmap(bitmap);
else
imageView.setImageResource(stub_id);
}
}
/**
* Clear cache.
*/
public void clearCache() {
//clear memory cache
cache.clear();
//clear SD cache
File[] files=cacheDir.listFiles();
for(File f:files)
f.delete();
}
public static void copyStream(InputStream is, OutputStream os) {
final int buffer_size=1024;
try
{
byte[] bytes=new byte[buffer_size];
for(;;)
{
int count=is.read(bytes, 0, buffer_size);
if(count==-1)
break;
os.write(bytes, 0, count);
}
}
catch(Exception ex){}
}
}
Now your ProjectAdapter class
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class ProjectAdapter extends ArrayAdapter<Project> {
int resource;
String response;
Context context;
List<Project> items;
private ImageThreadLoader imageLoader;
LayoutInflater mInflater;
Activity activity;
// Initialize adapter
public ProjectAdapter(Context context, int resource, List<Project> items,
Activity activity) {
super(context, resource, items);
this.resource = resource;
imageLoader = new ImageThreadLoader(context);
this.items = items;
mInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.activity = activity;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
// Inflate the view
if (convertView == null) {
convertView = mInflater.inflate(resource, null);
holder = new ViewHolder();
holder.image = (ImageView) convertView.findViewById(R.id.image);
holder.textTitle = (TextView) convertView
.findViewById(R.id.txt_title);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Project project = items.get(position);
holder.textTitle.setText(project.project_title);
String imageurl = project.smallImageUrl;
holder.image.setTag(imageurl);
imageLoader.displayImage(imageurl, activity, holder.image);
return convertView;
}
static class ViewHolder {
TextView textTitle;
ImageView image;
}
And at last when you set the adapter in your ListView after getting the web data, use this
your_listview.setAdapter(your_ProjectAdapter_instance );
your_ProjectAdapter_instance .notifyDataSetChanged();
i do have the sam eproblem of different datatype other than String array but I am using Arraylist(but not JASON) so I do changes in the code of Fedor and below is my implementation, hope this help
LazyAdapter
public LazyAdapter(Activity a, ArrayList<?> mStatus)
{
activity = a;
data = mStatus;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader = new ImageLoader(activity.getApplicationContext());
}
public int getCount()
{
if(data != null && data.size() > 15)
return data.size();
else
return 15;
}
I found that even if the files in sdcard it doesnt load becuase its checking for that object which goes null if you change the activity on which list is implemented so I changed getBitmap() code also
ImageLoader
private Bitmap getBitmap(String urlString)
{
String filename = String.valueOf(urlString.substring(urlString.lastIndexOf("/") + 1));
File f = new File(cacheDir, filename);
try
{
if(!f.exists())
{
Bitmap bitmap = null;
InputStream is = new URL(urlString).openStream();
OutputStream os = new FileOutputStream(f);
Globals.CopyStream(is, os);
os.close();
bitmap = decodeFile(f);
return bitmap;
}
else
{
Bitmap bitmap = decodeFile(f);
return bitmap;
}
}
catch (Exception ex)
{
ex.printStackTrace();
BitmapDrawable mDrawable = (BitmapDrawable) context.getResources().getDrawable(R.drawable.placeholder);
return mDrawable.getBitmap();
}
}
Stackoverflow member Fedor posted some source for a cached ImageLoader in answer to this question. Android - How do I do a lazy load of images in ListView The source is here source. His answer got 100+ upvotes. I found it worked very well caching Flickr images of mine. You should be able to adapt it for your use.
You haven't set the image tag when sending into the lazy loader class.
Bitmap cachedImage = null;
try {
cachedImage = imageLoader.loadImage(pro.smallImageUrl, new ImageLoadedListener() {
public void imageLoaded(Bitmap imageBitmap) {
image.setImageBitmap(imageBitmap);
notifyDataSetChanged(); }
});
} catch (MalformedURLException e) {
Log.e(TAG, "Bad remote image URL: " + pro.smallImageUrl, e);
}
What is private ImageThreadLoader imageLoader = new ImageThreadLoader(); ? Can I see that class?