I have used the async task to download the data and then showing those images in the list view I used the cache to store the images as they are repeating but not in an order. But the images gets jumbled up and sometimes they don't download. I tried searching this, but couldn't find that.
This was one of mine dream company question and i didn't clear because of this.
Please help me around.
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final String BASE_URL = "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=android&start=";
private static final String IMAGE_JSON_KEY = "unescapedUrl";
private static final String RESULTS_JSON_KEY = "results";
private static final String RESPONSE_DATA_JSON_KEY = "responseData";
private int mCurrentPage;
private ListView mListView;
private Context mContext;
ArrayList<String> mImageUrls;
private LruCache<String, Bitmap> mCache;
private CustomListAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Get memory class of this device, exceeding this amount will throw an
// OutOfMemory exception.
final int memClass = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = 1024 * 1024 * memClass / 8;
// Initialize variables
mContext = this;
mCache = new LruCache<String, Bitmap>(cacheSize) {
#Override
protected int sizeOf(String key, Bitmap value) {
// The cache size will be measured in bytes rather than number of items.
return value.getByteCount();
}
};
mListView = (ListView) findViewById(R.id.list_view);
mAdapter = new CustomListAdapter();
mImageUrls = new ArrayList<>();
// If the urls are wrong then
if (mImageUrls.isEmpty() || checkDiff()) {
fetchNewImageUrls();
}
// Set the adapter to the list view
mListView.setAdapter(mAdapter);
}
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private String mUrl;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
#Override
protected Bitmap doInBackground(String... params) {
String imageUrl = params[0];
mUrl = imageUrl;
Bitmap bitmap = getBitmapFromMemCache(imageUrl);
if (bitmap == null) {
try {
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
// Closing the stream after getting the sample size
InputStream inputStream = connection.getInputStream();
byte[] imageByteArray = convertToByteArray(inputStream);
bitmap = decodeSampledBitmap(imageByteArray, 200, 200);
inputStream.close();
if (bitmap != null) {
Log.d(TAG, "Image downloaded: " + imageUrl);
addBitmapToMemoryCache(imageUrl, bitmap);
} else {
Log.d(TAG, "Null Bitmap downloaded for: " + imageUrl);
}
connection.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} else {
Log.d(TAG, "Already present in the Cache");
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = (ImageView) imageViewReference.get();
if (imageView != null && imageView.getTag().equals(mUrl)) {
imageView.setImageBitmap(bitmap);
}
}
}
}
public class CustomListAdapter extends BaseAdapter {
#Override
public int getCount() {
return mImageUrls.size();
}
#Override
public Object getItem(int position) {
return mImageUrls.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.d(TAG, "Get View is called for position: " + position);
View view = convertView;
Holder holder = null;
// Holder represents the elements of the view to use
// Here are initialized
if (view == null) {
view = LayoutInflater.from(mContext).inflate(R.layout.row_item, parent, false);
holder = new Holder();
holder.mRowImage = (ImageView) view.findViewById(R.id.image_view);
holder.mRowText = (TextView) view.findViewById(R.id.row_text);
view.setTag(holder);
} else {
holder = (Holder) view.getTag();
}
// Set default image background
holder.mRowImage.setImageResource(R.drawable.ic_launcher);
// here do operations in holder variable example
holder.mRowText.setText("Image Number: " + position);
// Set the tag for the imageview
holder.mRowImage.setTag(mImageUrls.get(position));
new BitmapWorkerTask(holder.mRowImage).execute(mImageUrls.get(position));
return view;
}
}
public static class Holder {
TextView mRowText;
ImageView mRowImage;
}
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return (Bitmap) mCache.get(key);
}
public Bitmap decodeSampledBitmap(byte[] imageByteArray, int reqWidth, int reqHeight) {
Bitmap bm = null;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length, options);
return bm;
}
public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
Log.d(TAG, "Sample size is: " + inSampleSize);
return inSampleSize;
}
private void fetchNewImageUrls() {
new AsyncTask<String, Void, Boolean>() {
#Override
protected Boolean doInBackground(String... params) {
try {
StringBuilder response = new StringBuilder();
URL url = new URL(params[0]);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
response.append(inputLine);
in.close();
connection.disconnect();
String resp = response.toString();
Log.d(TAG, "Response is: " + response);
// Parsing the response
JSONObject jsonObject = new JSONObject(resp);
JSONObject jsonObject1 = jsonObject.getJSONObject(RESPONSE_DATA_JSON_KEY);
JSONArray jsonArray = jsonObject1.getJSONArray(RESULTS_JSON_KEY);
for (int i = 0; i < 4; i++) {
JSONObject dataObject = jsonArray.getJSONObject(i);
mImageUrls.add(dataObject.getString(IMAGE_JSON_KEY));
}
mCurrentPage++;
Log.d(TAG, "Number of image urls are: " + mImageUrls.size());
return true;
} catch (JSONException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
#Override
protected void onPostExecute(Boolean value) {
super.onPostExecute(value);
if (checkDiff() && value) {
Log.d(TAG, "Again fetching the Images");
fetchNewImageUrls();
}
if (!value) {
Log.d(TAG, "Error while getting the response");
}
mAdapter.notifyDataSetChanged();
}
}.execute(BASE_URL + mCurrentPage);
}
private boolean checkDiff() {
int diff = mImageUrls.size() - mCurrentPage * 4;
Log.d(TAG, "Diff is: " + diff);
return diff < 8;
}
public static byte[] convertToByteArray(InputStream input) {
byte[] buffer = new byte[8192];
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}
return output.toByteArray();
}
}
Since you do not cancel the unfinished "out of view" downloads these may interfere with your gui.
Example
listview line1 shows item#1 with has an async task to download image "a" not completed yet
scroll down, line1 is now invisible;
listview line8 becomes visible recycling item#1 new async task to download image "x"
async task to download image "a" finishes displaying wrong image. Line8 shows image "a" instead of "x"
to solve this you have to cancel the pending unnecessary unfinished async task-s
public static class Holder {
ImageView mRowImage;
String mImageUrl;
// neccessary to cancel unfinished download
BitmapWorkerTask mDownloader;
}
static class BitmapWorkerTask extends AsyncTask<Holder, Void, Bitmap> {
Holder mHolder;
protected Bitmap doInBackground(Holder... holders) {
mHolder = holders[0];
...
}
protected void onPostExecute(...) {
mHolder.mDownloader = null;
if (!isCancelled()) {
this.mHolder.mRowImage.setImageBitmap(image);
}
this.mHolder = null;
}
}
public class CustomListAdapter extends BaseAdapter {
#Override
public View getView(int position, ...) {
...
if (view == null) {
holder = ...
...
} else {
holder = (Holder) view.getTag();
}
...
// cancel unfinished mDownloader
if (holder.mDownloader != null) {
holder.mDownloader.cancel(false);
holder.mDownloader = null;
}
holder.mImageUrl = mImageUrls.get(position);
holder.mDownloader = new BitmapWorkerTask()
holder.mDownloader.execute(holder);
}
}
Here is a working example for this combination of Adapter + Holder + AsyncTask
[Update]
Potential problems with this solution.
Most modern android versions execute only one async task at a time. If you are fetching the images via the web you cannot download multible images at the same time. See running-parallel-asynctask#stackoverflow for details.
There may be promlems with configuration change(like orientation). See #Selvin-s comment below. I have posted this question "what-happens-with-view-references-in-unfinished-asynctask-after-orientation-chan#stackoverflow" to find out more about it.
Related
Hi in the below I am displaying images from sdcard.sdcard means storing into locally.but while privew the images it was showing some black color after image got displaying.
want to display smooth preview with black screen.i am unable to figure out the issue.can any one help me.
java
public class ImageGallery extends Activity {
Bundle bundle;
String catid, temp, responseJson;
JSONObject json;
ImageView imageViewPager;
// for parsing
JSONObject o1, o2;
JSONArray a1, a2;
int k;
Boolean toggleTopBar;
ArrayList<String> imageThumbnails;
ArrayList<String> imageFull;
public static int imagePosition=0;
SubsamplingScaleImageView imageView, imageViewPreview, fullImage ;
ImageView thumb1, back;
private LinearLayout thumb2;
RelativeLayout topLayout, stripeView;
RelativeLayout thumbnailButtons;
FrameLayout gridFrame;
//SharedPreferences data
SharedPreferences s1;
SharedPreferences.Editor editor;
int swipeCounter;
ParsingForFinalImages parsingObject;
int position_grid;
SharedPreferences p;
Bitmap bm;
int numOfImagesInsidee;
LinearLayout backLinLayout;
public static boolean isThumb2=false;
public static boolean isThumb1=false;
public static ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_gallery);
//isThumb2=false;
toggleTopBar = false;
//position_grid=getIntent().getExtras().getInt("position");
thumbnailButtons = (RelativeLayout)findViewById(R.id.thumbnailButtons);
topLayout = (RelativeLayout)findViewById(R.id.topLayout);
//fullImage = (SubsamplingScaleImageView)findViewById(R.id.fullimage);
backLinLayout = (LinearLayout)findViewById(R.id.lin_back);
backLinLayout.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent io = new Intent(getBaseContext(), MainActivity.class);
// clear the previous activity and start a new task
// System.gc();
// io.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(io);
finish();
}
});
ConnectionDetector cd = new ConnectionDetector(getBaseContext());
Boolean isInternetPresent = cd.isConnectingToInternet();
thumb1 = (ImageView)findViewById(R.id.thumb1);
thumb2 = (LinearLayout)findViewById(R.id.thumb2);
stripeView = (RelativeLayout)findViewById(R.id.stripeView) ;
gridFrame = (FrameLayout)findViewById(R.id.gridFrame);
thumb1.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
stripeView.setVisibility(View.GONE);
gridFrame.setVisibility(View.VISIBLE);
viewPager.setVisibility(View.GONE);
//fullImage.setVisibility(View.GONE);
thumb1.setClickable(false);
isThumb1=true;
isThumb2=false;
Log.i("Thumb Position 1",""+ImageGallery.imagePosition);
viewPager.removeAllViews();
Fragment newFragment = new GridFragment2();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.gridFrame, newFragment).commit();
}
});
thumb2.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
// stripeView.setVisibility(View.VISIBLE);
stripeView.setVisibility(View.GONE);
gridFrame.setVisibility(View.VISIBLE);
viewPager.setVisibility(View.GONE);
// fullImage.setVisibility(View.GONE);
thumb1.setClickable(true);
isThumb2=true;
isThumb1=false;
Log.i("Thumb Position 2",""+ImageGallery.imagePosition);
viewPager.removeAllViews();
Fragment newFragment = new ImageStripeFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.gridFrame, newFragment).commit();
}
});
// allow networking on main thread
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
/*bundle = getIntent().getExtras();
catid = bundle.getString("catid");*/
// Toast.makeText(getBaseContext(), catid, Toast.LENGTH_LONG).show();
// making json using the catalogue id we got
p = getSharedPreferences("gridData", Context.MODE_APPEND);
catid = p.getString("SelectedCatalogueIdFromGrid1", "");
int clickedListPos = p.getInt("clickedPosition", 0);
imageViewPreview = (SubsamplingScaleImageView)findViewById(R.id.preview);
imageThumbnails = new ArrayList<String>();
imageFull = new ArrayList<String>();
s1 = this.getSharedPreferences("data", Context.MODE_APPEND);
editor = s1.edit();
Log.d("catidfnl", catid);
numOfImagesInsidee = p.getInt("numberOfItemsSelectedFromGrid1", 0);
Log.d("blingbling2", String.valueOf(numOfImagesInsidee));
// adding downloaded images to arraylist
for(int m=0;m<numOfImagesInsidee;m++){
imageThumbnails.add(Environment.getExternalStorageDirectory()+"/"+"thumbImage" + catid + m+".png");
imageFull.add(Environment.getExternalStorageDirectory()+"/"+"fullImage" + catid + m+".png");
// imageFull.add("file://" + Environment.getExternalStorageDirectory() + "/" + "fullImage32.png");
}
viewPager = (ViewPager) findViewById(R.id.pager);
ImagePagerAdapter adapter = new ImagePagerAdapter();
viewPager.setAdapter(adapter);
// SubsamplingScaleImageView fullImage = new SubsamplingScaleImageView(ImageGallery.this);
// code to display image in a horizontal strip starts here
LinearLayout layout = (LinearLayout) findViewById(R.id.linear);
for (int i = 0; i < imageThumbnails.size(); i++) {
imageView = new SubsamplingScaleImageView(this);
imageView.setId(i);
imageView.setPadding(2, 2, 2, 2);
// Picasso.with(this).load("file://"+imageThumbnails.get(i)).into(imageView);
// imageView.setScaleType(ImageView.ScaleType.FIT_XY);
layout.addView(imageView);
ViewGroup.LayoutParams params = imageView.getLayoutParams();
params.width = 200;
params.height = 200;
imageView.setLayoutParams(params);
imageView.setZoomEnabled(false);
imageView.setDoubleTapZoomScale(0);
imageView.setImage(ImageSource.uri(imageThumbnails.get(0)));
imageView.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
imageView.setZoomEnabled(false);
imageViewPreview.setImage(ImageSource.uri(imageFull.get(view.getId())));
imageView.recycle();
imageViewPreview.recycle();
}
});
}
// code to display image in a horizontal strip ends here
imageViewPreview.setZoomEnabled(false);
/*imageViewPreview.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
imageViewPreview.setZoomEnabled(false);
stripeView.setVisibility(View.GONE);
gridFrame.setVisibility(View.GONE);
viewPager.setVisibility(View.VISIBLE);
}
});*/
imageViewPreview.setOnClickListener(new DoubleClickListener() {
#Override
public void onSingleClick(View v) {
Log.d("yo click", "single");
}
#Override
public void onDoubleClick(View v) {
Log.d("yo click", "double");
}
});
}
public abstract class DoubleClickListener implements View.OnClickListener {
private static final long DOUBLE_CLICK_TIME_DELTA = 300;//milliseconds
long lastClickTime = 0;
#Override
public void onClick(View v) {
long clickTime = System.currentTimeMillis();
if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){
onDoubleClick(v);
} else {
onSingleClick(v);
}
lastClickTime = clickTime;
}
public abstract void onSingleClick(View v);
public abstract void onDoubleClick(View v);
}
// #Override
// public void onBackPressed() {
// Intent io = new Intent(getBaseContext(), MainActivity.class);
// // clear the previous activity and start a new task
// super.onBackPressed();
// finish();
// // System.gc();
// // io.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
// startActivity(io);
// }
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_image_gallery, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private class ImagePagerAdapter extends PagerAdapter {
/* private int[] mImages = new int[] {
R.drawable.scroll3,
R.drawable.scroll1,
R.drawable.scroll2,
R.drawable.scroll4
};*/
/* private String[] description=new String[]
{
"One","two","three","four"
};
*/
#Override
public int getCount() {
Log.i("Image List Size", "" + imageFull.size());
return imageFull.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((SubsamplingScaleImageView) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Context context = ImageGallery.this;
SubsamplingScaleImageView fullImage = new SubsamplingScaleImageView(ImageGallery.this);
// for placeholder
// fullImage.setImage(ImageSource.resource(R.drawable.tan2x));
if(!GridFragment2.isSelectedGrid2&&!ImageStripeFragment.isImageStripe) {
imagePosition = position;
fullImage.setImage(ImageSource.uri(imageFull.get(imagePosition)));
}
/* else if(!ImageStripeFragment.isImageStripe)
{
imagePosition = position;
fullImage.setImage(ImageSource.uri(imageFull.get(imagePosition)));
}
else if(ImageStripeFragment.isImageStripe)
{
position=imagePosition;
viewPager.setCurrentItem(imagePosition);
fullImage.setImage(ImageSource.uri(imageFull.get(position)));
}*/
else
{
position=imagePosition;
viewPager.setCurrentItem(imagePosition);
fullImage.setImage(ImageSource.uri(imageFull.get(position)));
//viewPager.removeAllViews();
}
// ImageView imageViewPager = new ImageView(context);
// ImageView imageViewPager = new ImageView(getApplicationContext());
// SubsamplingScaleImageView fullImage = new SubsamplingScaleImageView(ImageGallery.this);
GridFragment2.isSelectedGrid2=false;
ImageStripeFragment.isImageStripe=false;
// Log.i("Image Resource", "" + ImageSource.uri(imageFull.get(position)));
// imageViewPager.setImageBitmap(BitmapFactory.decodeFile(imageFull.get(position)));
// imageViewPager.setImageBitmap(myBitmap);
// fullImage.setImage(ImageSource.bitmap(bmImg));
//imageView.setImageResource(Integer.parseInt(imageFull.get(position)));
/*int padding = context.getResources().getDimensionPixelSize(
R.dimen.padding_medium);
imageView.setPadding(padding, padding, padding, padding);*/
/*imageView.setScaleType(ImageView.ScaleType.CENTER);
imageView.setImageResource(Integer.parseInt(imageFull.get(position)));
if(position==3)
{
}*/
// Log.i("Image Position",""+position);
/*text.setText(description[position]);
Log.i("Text Position",""+position);*/
/*switch(position)
{
case 0:
String pos=String.valueOf(position);
text.setText(pos);
break;
case 1:
String pos1=String.valueOf(position);
text.setText(pos1);
break;
case 2:
String pos2=String.valueOf(position);
text.setText(pos2);
break;
case 3:
String pos3=String.valueOf(position);
text.setText(pos3);
break;
}*/
fullImage.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
if (toggleTopBar == false) {
// thumbnailButtons.setVisibility(View.GONE);
thumbnailButtons.animate()
.translationY(-2000)
.setDuration(1000)
.start();
toggleTopBar = true;
} else if (toggleTopBar == true) {
// thumbnailButtons.setVisibility(View.VISIBLE);
thumbnailButtons.animate()
.translationY(0)
.setDuration(1000)
.start();
toggleTopBar = false;
}
}
});
((ViewPager) container).addView(fullImage, 0);
return fullImage;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((SubsamplingScaleImageView) object);
}
/* #Override
public void destroyItem(View collection, int position, Object o) {
Log.d("DESTROY", "destroying view at position " + position);
View view = (View) o;
((ViewPager) collection).removeView(view);
view = null;
}*/
}
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
}
use this ImageLoader Class
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
int stub_id;
int widht;
public ImageLoader(Context context, int stub_idx) {
fileCache = new FileCache(context);
executorService = Executors.newFixedThreadPool(5);
stub_id = stub_idx;
}
public void DisplayImage(String url, ImageView imageView, int widht, ProgressBar bar) {
this.widht = widht;
imageViews.put(imageView, url);
Bitmap bitmap = memoryCache.get(url);
if (bitmap != null)
{
bar.setVisibility(View.GONE);
imageView.setImageBitmap(bitmap);
}
else {
queuePhoto(url, imageView, widht, bar);
imageView.setImageResource(stub_id);
}
}
private void queuePhoto(String url, ImageView imageView, int w, ProgressBar bar) {
PhotoToLoad p = new PhotoToLoad(url, imageView, bar);
executorService.submit(new PhotosLoader(p, w));
}
public Bitmap getBitmap(String url, int w) {
File f = fileCache.getFile(url);
// from SD cache
Bitmap b = decodeFile(f, w);
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, w);
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, int w) {
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 = w;
System.out.println("screen wdth " + widht);
int width_tmp = o.outWidth, height_tmp = o.outHeight;
System.out.println("image with === " + width_tmp);
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) {
Log.e(e.getMessage(), "");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
// Task for the queue
private class PhotoToLoad {
public String url;
public ImageView imageView;
public ProgressBar bar;
public PhotoToLoad(String u, ImageView i, ProgressBar progressBar) {
url = u;
imageView = i;
bar = progressBar;
}
}
class PhotosLoader implements Runnable {
PhotoToLoad photoToLoad;
int w;
PhotosLoader(PhotoToLoad photoToLoad, int w) {
this.photoToLoad = photoToLoad;
this.w = w;
}
#Override
public void run() {
try {
if (imageViewReused(photoToLoad))
return;
Bitmap bmp = getBitmap(photoToLoad.url, w);
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);
return tag == null || !tag.equals(photoToLoad.url);
}
// 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);
photoToLoad.bar.setVisibility(View.GONE);
}
}
public void clearCache() {
memoryCache.clear();
fileCache.clear();
}
Then make new class for File cache
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 = url.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();
}
}
Then last make Memory cache class , all three seperatly class
public class MemoryCache {
private static final String TAG = "MemoryCache";
private Map<String, Bitmap> cache=Collections.synchronizedMap(
new LinkedHashMap<String, Bitmap>(10,1.5f,true));//Last argument true for LRU ordering
private long size=0;//current allocated size
private long limit=1000000;//max memory in bytes
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;
//NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
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){
Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated
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{
//NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
cache.clear();
size=0;
}catch(NullPointerException ex){
ex.printStackTrace();
}
}
long getSizeInBytes(Bitmap bitmap) {
if(bitmap==null)
return 0;
return bitmap.getRowBytes() * bitmap.getHeight();
}
I am using curlview for curl effect my data contain images for each page in curlview with my code i got blank pages without image which I seted in imageurllist doing json parsing how i got images instead of blank pages.
This is my code.
public class CurlActivity extends Activity {
private CurlView mCurlView;
public String cid;
public ArrayList<String>magazineidlist;
public String middata;
public String url;
public String imgurl;
public Bitmap bitmap;
public ImageLoader imageloder;
public ImageView imageView;
public ArrayList<String>imageurllist;
public GridImageAdapter gadapter;
public CurlActivity c;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_curl);
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
getAllMagazineById();
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
if(bundle!=null){
cid = bundle.getString("mid");
Log.d("magazine id", cid);
}
int index = 0;
if (getLastNonConfigurationInstance() != null) {
index = (Integer) getLastNonConfigurationInstance();
}
mCurlView = (CurlView) findViewById(R.id.curl);
}
#Override
public void onPause() {
super.onPause();
mCurlView.onPause();
}
#Override
public void onResume() {
super.onResume();
mCurlView.onResume();
}
#Override
public Object onRetainNonConfigurationInstance() {
return mCurlView.getCurrentIndex();
}
/**
* Bitmap provider.
*/
private class PageProvider implements CurlView.PageProvider {
// Bitmap resources.
private int[] mBitmapIds = { R.layout.sample};
//LinearLayout llout = (LinearLayout) findViewById(R.layout.sample);
#SuppressWarnings("unused")
//ImageView imageView = (ImageView) findViewById(R.id.imageviewsample);
#Override
public int getPageCount() {
return imageurllist.size();
}
private Bitmap loadBitmap(int width, int height, int index) {
LayoutInflater inflater =
(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Log.d("index",String.valueOf(index));
View v = inflater.inflate((mBitmapIds[index]),null);
v.measure(
MeasureSpec.makeMeasureSpec(width,MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight()
,Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.draw(c);
return b;
}
#Override
public void updatePage(CurlPage page, int width, int height, int index) {
switch (index) {
// First case is image on front side, solid colored back.
default:
Bitmap front = loadBitmap(width, height, 0);
page.setTexture(front, CurlPage.SIDE_FRONT);
page.setColor(Color.rgb(180, 180, 180), CurlPage.SIDE_BACK);
break;
/*// Third case is images on both sides.
case 2: {
Bitmap front = loadBitmap(width, height, 1);
Bitmap back = loadBitmap(width, height, 3);
page.setTexture(front, CurlPage.SIDE_FRONT);
page.setTexture(back, CurlPage.SIDE_BACK);
break;
}
// Fourth case is images on both sides - plus they are blend against
// separate colors.
case 3: {
Bitmap front = loadBitmap(width, height, 2);
Bitmap back = loadBitmap(width, height, 1);
page.setTexture(front, CurlPage.SIDE_FRONT);
page.setTexture(back, CurlPage.SIDE_BACK);
page.setColor(Color.argb(127, 170, 130, 255),
CurlPage.SIDE_FRONT);
page.setColor(Color.rgb(255, 190, 150), CurlPage.SIDE_BACK);
break;
}
// Fifth case is same image is assigned to front and back. In this
// scenario only one texture is used and shared for both sides.
case 4:
Bitmap front = loadBitmap(width, height, 0);
page.setTexture(front, CurlPage.SIDE_BOTH);
page.setColor(Color.argb(127, 255, 255, 255),
CurlPage.SIDE_BACK);
break;*/
}
}
}
/**
* CurlView size changed observer.
*/
class SizeChangedObserver implements CurlView.SizeChangedObserver {
#Override
public void onSizeChanged(int w, int h) {
if (w > h) {
mCurlView.setViewMode(CurlView.SHOW_TWO_PAGES);
mCurlView.setMargins(.1f, .05f, .1f, .05f);
} else {
mCurlView.setViewMode(CurlView.SHOW_ONE_PAGE);
//mCurlView.setMargins(.1f, .1f, .1f, .1f);
}
}
}
public Bitmap GetBitmapfromUrl(String scr) {
try {
URL url=new URL(scr);
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input=connection.getInputStream();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeStream(input, null, options);
// Bitmap bmp = BitmapFactory.decodeStream(input);
return bitmap;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public void getAllMagazineById() {
new AsyncTask<Void, Void, String>() {
ProgressDialog mProgressDialog;
protected void onPostExecute(String result) {
mProgressDialog.dismiss();
magazineidlist = new ArrayList<String>();
imageurllist = new ArrayList<String>();
//imageloder = new ImageLoader(CurlActivity.this);
// LayoutInflater factory = LayoutInflater.from(CurlActivity.this);
// View child = factory.inflate(R.layout.sample, null);
// imageView = (ImageView)child.findViewById(R.id.imageviewsample);
//imageView = (ImageView)findViewById(R.id.imageviewsample);
try {
JSONObject jsob = new JSONObject(result.toString());
if (jsob.getString("msg").equalsIgnoreCase("Success")) {
JSONArray datajson = jsob.getJSONArray("data");
for (int i = 0; i < datajson.length(); i++) {
JSONObject c = datajson.getJSONObject(i);
middata = c.getString("magazine_id");
imgurl = c.getString("image_url");
magazineidlist.add(middata);
imageurllist.add(imgurl);
Log.d("imageurllist value at index" +i, imageurllist.get(i));
//imageloder.DisplayImage(imageurllist.get(i),imageView);
String url = imageurllist.get(i);
Log.d("url val", url);
}
gadapter = new GridImageAdapter(c, imageurllist);
mCurlView.setPageProvider(new PageProvider());
mCurlView.setSizeChangedObserver(new SizeChangedObserver());
mCurlView.setCurrentIndex(0);
mCurlView.setBackgroundColor(0xFF202830);
} else if(jsob.getString("msg").equalsIgnoreCase("Failure")) {
System.out.println("not a valid data");
}
else
{
System.out.println("error");
}
} catch (Exception e) {
Log.e("error", "" + e);
}
}
private void startActivity(Intent i) {
// TODO Auto-generated method stub
}
#Override
protected String doInBackground(Void... arg0) {
// Creating service handler class instance
try {
HttpPost httppost1 = null;
HttpClient httpclient1 = new DefaultHttpClient();
httppost1 = new HttpPost(JsonKey.MAIN_URL);
// Add your data
List<NameValuePair> nameValuePairs1 = new ArrayList<NameValuePair>(
2);
nameValuePairs1.add(new BasicNameValuePair("action",
"GetMagazinePageImagesbyid"));
nameValuePairs1.add(new BasicNameValuePair("iMagezineId",
cid));
httppost1.setEntity(new UrlEncodedFormEntity(
nameValuePairs1));
// Execute HTTP Post Request
HttpResponse response1 = httpclient1.execute(httppost1);
BufferedReader in1 = new BufferedReader(
new InputStreamReader(response1.getEntity()
.getContent()));
StringBuffer sb1 = new StringBuffer("");
String line1 = "";
while ((line1 = in1.readLine()) != null) {
sb1.append(line1);
}
in1.close();
Log.e(" Get All magazine original data", sb1.toString());
return sb1.toString();
} catch (Exception e) {
Log.e("Get All magazine response problem", "" + e);
return " ";
}
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
mProgressDialog = new ProgressDialog(CurlActivity.this);
mProgressDialog.setTitle("");
mProgressDialog.setCanceledOnTouchOutside(false);
mProgressDialog.setMessage("Please Wait...");
mProgressDialog.show();
}
}.execute();
}
public static Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
// Log exception
return null;
}
}
Bitmap drawable_from_url(String url) throws java.net.MalformedURLException, java.io.IOException {
Bitmap x;
HttpURLConnection connection = (HttpURLConnection)new URL(url) .openConnection();
connection.setRequestProperty("User-agent","Mozilla/4.0");
connection.connect();
InputStream input = connection.getInputStream();
x = BitmapFactory.decodeStream(input);
return x;
}
public class GridImageAdapter extends BaseAdapter {
public Context mContext;
// public final String[] web;
// final int ImageId[];
public CurlActivity activity;
public ImageLoader imageloader;
// Constructor
public GridImageAdapter(CurlActivity c, ArrayList<String> imageUrl) {
// TODO Auto-generated constructor stub
mContext = c;
imageurllist = imageUrl;
imageloader = new ImageLoader(CurlActivity.this);
}
public int getCount() {
return imageurllist.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
View grid;
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
grid = new View(mContext);
grid = inflater.inflate(R.layout.sample, null);
ImageView img = (ImageView) grid.findViewById(R.id.imageviewsample);
imageloader.DisplayImage(imageurllist.get(position), img);
}
/*
* ImageView imageView; if (convertView == null) { imageView = new
* ImageView(mContext); imageView.setLayoutParams(new
* GridView.LayoutParams(85, 85));
* imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
* imageView.setPadding(8, 8, 8, 8); }
*/else {
grid = (View) convertView;
}
/*
* imageView.setImageResource(mThumbIds[position]); return
* imageView;
*/
return grid;
}
// Keep all Images in array
/*
* public Integer[] mThumbIds = { R.drawable.nightlife,
* R.drawable.coffee, R.drawable.shopping, R.drawable.seeanddo,
*
* };
*/
public Bitmap StringToBitMap(String encodedString) {
try {
byte[] encodeByte = Base64
.decode(encodedString, Base64.DEFAULT);
Bitmap bitmap = BitmapFactory.decodeByteArray(encodeByte, 0,
encodeByte.length);
return bitmap;
} catch (Exception e) {
e.getMessage();
return null;
}
}
}
}
I want to crate curlview with dynemic data. I used imageview to display image into curlview because my api contain image in data. but image is not displayed into imageview how i do this?
Below is my code.
public class CurlActivity extends Activity {
private CurlView mCurlView;
public String cid;
public ArrayList<String>magazineidlist;
public String middata;
public String url;
public String imgurl;
public Bitmap bitmap;
public ImageLoader imageloder;
public ImageView imageView;
public ArrayList<String>imageurllist;
public GridImageAdapter gadapter;
public CurlActivity c;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_curl);
gadapter = new GridImageAdapter(c, imageurllist);
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
getAllMagazineById();
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
if(bundle!=null){
cid = bundle.getString("mid");
Log.d("magazine id", cid);
}
int index = 0;
if (getLastNonConfigurationInstance() != null) {
index = (Integer) getLastNonConfigurationInstance();
}
mCurlView = (CurlView) findViewById(R.id.curl);
}
#Override
public void onPause() {
super.onPause();
mCurlView.onPause();
}
#Override
public void onResume() {
super.onResume();
mCurlView.onResume();
}
#Override
public Object onRetainNonConfigurationInstance() {
return mCurlView.getCurrentIndex();
}
/**
* Bitmap provider.
*/
private class PageProvider implements CurlView.PageProvider {
// Bitmap resources.
private int[] mBitmapIds = { R.layout.sample};
//LinearLayout llout = (LinearLayout) findViewById(R.layout.sample);
#SuppressWarnings("unused")
//ImageView imageView = (ImageView) findViewById(R.id.imageviewsample);
#Override
public int getPageCount() {
return imageurllist.size();
}
private Bitmap loadBitmap(int width, int height, int index) {
LayoutInflater inflater =
(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Log.d("index",String.valueOf(index));
View v = inflater.inflate(mBitmapIds[index],null);
v.measure(
MeasureSpec.makeMeasureSpec(width,MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight()
,Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.draw(c);
return b;
}
#Override
public void updatePage(CurlPage page, int width, int height, int index) {
switch (index) {
// First case is image on front side, solid colored back.
default:
Bitmap front = loadBitmap(width, height, 0);
page.setTexture(front, CurlPage.SIDE_FRONT);
page.setColor(Color.rgb(180, 180, 180), CurlPage.SIDE_BACK);
break;
/*// Third case is images on both sides.
case 2: {
Bitmap front = loadBitmap(width, height, 1);
Bitmap back = loadBitmap(width, height, 3);
page.setTexture(front, CurlPage.SIDE_FRONT);
page.setTexture(back, CurlPage.SIDE_BACK);
break;
}
// Fourth case is images on both sides - plus they are blend against
// separate colors.
case 3: {
Bitmap front = loadBitmap(width, height, 2);
Bitmap back = loadBitmap(width, height, 1);
page.setTexture(front, CurlPage.SIDE_FRONT);
page.setTexture(back, CurlPage.SIDE_BACK);
page.setColor(Color.argb(127, 170, 130, 255),
CurlPage.SIDE_FRONT);
page.setColor(Color.rgb(255, 190, 150), CurlPage.SIDE_BACK);
break;
}
// Fifth case is same image is assigned to front and back. In this
// scenario only one texture is used and shared for both sides.
case 4:
Bitmap front = loadBitmap(width, height, 0);
page.setTexture(front, CurlPage.SIDE_BOTH);
page.setColor(Color.argb(127, 255, 255, 255),
CurlPage.SIDE_BACK);
break;*/
}
}
}
/**
* CurlView size changed observer.
*/
class SizeChangedObserver implements CurlView.SizeChangedObserver {
#Override
public void onSizeChanged(int w, int h) {
if (w > h) {
mCurlView.setViewMode(CurlView.SHOW_TWO_PAGES);
mCurlView.setMargins(.1f, .05f, .1f, .05f);
} else {
mCurlView.setViewMode(CurlView.SHOW_ONE_PAGE);
//mCurlView.setMargins(.1f, .1f, .1f, .1f);
}
}
}
public Bitmap GetBitmapfromUrl(String scr) {
try {
URL url=new URL(scr);
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input=connection.getInputStream();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeStream(input, null, options);
// Bitmap bmp = BitmapFactory.decodeStream(input);
return bitmap;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public void getAllMagazineById() {
new AsyncTask<Void, Void, String>() {
ProgressDialog mProgressDialog;
protected void onPostExecute(String result) {
mProgressDialog.dismiss();
magazineidlist = new ArrayList<String>();
imageurllist = new ArrayList<String>();
//imageloder = new ImageLoader(CurlActivity.this);
// LayoutInflater factory = LayoutInflater.from(CurlActivity.this);
// View child = factory.inflate(R.layout.sample, null);
// imageView = (ImageView)child.findViewById(R.id.imageviewsample);
//imageView = (ImageView)findViewById(R.id.imageviewsample);
try {
JSONObject jsob = new JSONObject(result.toString());
if (jsob.getString("msg").equalsIgnoreCase("Success")) {
JSONArray datajson = jsob.getJSONArray("data");
for (int i = 0; i < datajson.length(); i++) {
JSONObject c = datajson.getJSONObject(i);
middata = c.getString("magazine_id");
imgurl = c.getString("image_url");
magazineidlist.add(middata);
imageurllist.add(imgurl);
Log.d("imageurllist value at index" +i, imageurllist.get(i));
//imageloder.DisplayImage(imageurllist.get(i),imageView);
String url = imageurllist.get(i);
Log.d("url val", url);
}
mCurlView.setPageProvider(new PageProvider());
mCurlView.setSizeChangedObserver(new SizeChangedObserver());
//mCurlView.setCurrentIndex(0);
mCurlView.setBackgroundColor(0xFF202830);
} else if(jsob.getString("msg").equalsIgnoreCase("Failure")) {
System.out.println("not a valid data");
}
else
{
System.out.println("error");
}
} catch (Exception e) {
Log.e("error", "" + e);
}
}
private void startActivity(Intent i) {
// TODO Auto-generated method stub
}
#Override
protected String doInBackground(Void... arg0) {
// Creating service handler class instance
try {
HttpPost httppost1 = null;
HttpClient httpclient1 = new DefaultHttpClient();
httppost1 = new HttpPost(JsonKey.MAIN_URL);
// Add your data
List<NameValuePair> nameValuePairs1 = new ArrayList<NameValuePair>(
2);
nameValuePairs1.add(new BasicNameValuePair("action",
"GetMagazinePageImagesbyid"));
nameValuePairs1.add(new BasicNameValuePair("iMagezineId",
cid));
httppost1.setEntity(new UrlEncodedFormEntity(
nameValuePairs1));
// Execute HTTP Post Request
HttpResponse response1 = httpclient1.execute(httppost1);
BufferedReader in1 = new BufferedReader(
new InputStreamReader(response1.getEntity()
.getContent()));
StringBuffer sb1 = new StringBuffer("");
String line1 = "";
while ((line1 = in1.readLine()) != null) {
sb1.append(line1);
}
in1.close();
Log.e(" Get All magazine original data", sb1.toString());
return sb1.toString();
} catch (Exception e) {
Log.e("Get All magazine response problem", "" + e);
return " ";
}
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
mProgressDialog = new ProgressDialog(CurlActivity.this);
mProgressDialog.setTitle("");
mProgressDialog.setCanceledOnTouchOutside(false);
mProgressDialog.setMessage("Please Wait...");
mProgressDialog.show();
}
}.execute();
}
public static Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
// Log exception
return null;
}
}
Bitmap drawable_from_url(String url) throws java.net.MalformedURLException, java.io.IOException {
Bitmap x;
HttpURLConnection connection = (HttpURLConnection)new URL(url) .openConnection();
connection.setRequestProperty("User-agent","Mozilla/4.0");
connection.connect();
InputStream input = connection.getInputStream();
x = BitmapFactory.decodeStream(input);
return x;
}
public class GridImageAdapter extends BaseAdapter {
public Context mContext;
// public final String[] web;
// final int ImageId[];
public CurlActivity activity;
public ImageLoader imageloader;
// Constructor
public GridImageAdapter(CurlActivity c, ArrayList<String> imageUrl) {
// TODO Auto-generated constructor stub
mContext = c;
imageurllist = imageUrl;
imageloader = new ImageLoader(CurlActivity.this);
}
public int getCount() {
return imageurllist.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
View grid;
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
grid = new View(mContext);
grid = inflater.inflate(R.layout.sample, null);
ImageView img = (ImageView) grid.findViewById(R.id.imageviewsample);
imageloader.DisplayImage(imageurllist.get(position), img);
}
/*
* ImageView imageView; if (convertView == null) { imageView = new
* ImageView(mContext); imageView.setLayoutParams(new
* GridView.LayoutParams(85, 85));
* imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
* imageView.setPadding(8, 8, 8, 8); }
*/else {
grid = (View) convertView;
}
/*
* imageView.setImageResource(mThumbIds[position]); return
* imageView;
*/
return grid;
}
// Keep all Images in array
/*
* public Integer[] mThumbIds = { R.drawable.nightlife,
* R.drawable.coffee, R.drawable.shopping, R.drawable.seeanddo,
*
* };
*/
public Bitmap StringToBitMap(String encodedString) {
try {
byte[] encodeByte = Base64
.decode(encodedString, Base64.DEFAULT);
Bitmap bitmap = BitmapFactory.decodeByteArray(encodeByte, 0,
encodeByte.length);
return bitmap;
} catch (Exception e) {
e.getMessage();
return null;
}
}
}
}
I am struggling to update a list view with data from a database, this works nicely by using a SimpleCursorAdapter. But the image view on the rows is not updated on the activity start, I have to scroll through the list a few times and only then the images are loaded in the image view.
This is the binder i am using for the SimpleCursorAdapter:
private class PromotionViewBinder implements SimpleCursorAdapter.ViewBinder {
private int done;
public boolean setViewValue(View view, Cursor cursor, int index) {
Log.e(""+cursor.getCount(),"");
View tmpview = view;
if (index == cursor.getColumnIndex(PromotionsTable.SEEN_COL)) {
boolean read = cursor.getInt(index) > 0 ? true : false;
TextView title = (TextView) tmpview;
if (!read) {
title.setTypeface(Typeface.DEFAULT_BOLD, 0);
} else {
title.setTypeface(Typeface.DEFAULT);
}
return true;
} else if (tmpview.getId() == R.id.promotions_list_row_image){
String imageURL = cursor.getString(index);
Log.e("",imageURL);
imageRetriever.displayImage(imageURL, (ImageView)tmpview);
return true;
} else {
return false;
}
}
}
The image retriever class is the LazyList example from here. As you will see this is using a runnable to retrieve the images and once the task is done is automatically updating the given imageView...Do you think that the reference to the imageView is lost somewhere on the way?
Thanx in advance,
Nick
package com.tipgain.promotions;
The image retriever class:
/**
* This class is used for retrieving images from a given web link. it uses local
* storage and memory to store the images. Once a image is downloaded
* successfully the UI gets updated automatically.
*
*
*/
public class ImageRetriever {
private final String TAG = ImageRetriever.class.getName();
private MemoryImageCache memoryImgCache = new MemoryImageCache();
private LocalStorageImageCache localFileCache;
private Map<ImageView, String> imageViewHolders = Collections
.synchronizedMap(new WeakHashMap<ImageView, String>());
private ExecutorService execService;
final int defaultImageID = R.drawable.photo_not_available;
public ImageRetriever(Context context) {
localFileCache = new LocalStorageImageCache(context);
execService = Executors.newFixedThreadPool(5);
}
public void displayImage(String url, ImageView imageView) {
imageViewHolders.put(imageView, url);
Bitmap bmp = memoryImgCache.retrieve(url);
if (bmp != null) {
Log.e("case 1", " " + (bmp != null));
imageView.setImageBitmap(bmp);
} else {
Log.e("case 2", " " + (bmp == null));
addImageToQueue(url, imageView);
imageView.setImageResource(defaultImageID);
}
}
private void addImageToQueue(String url, ImageView imageView) {
NextImageToLoad img = new NextImageToLoad(url, imageView);
execService.submit(new ImagesRetriever(img));
}
/**
* This method is used for retrieving the Bitmap Image.
*
* #param url
* String representing the url pointing to the image.
* #return Bitmap representing the image
*/
private Bitmap getBitmap(String url) {
File imageFile = localFileCache.getFile(url);
// trying to get the bitmap from the local storage first
Bitmap bmp = decodeImageFile(imageFile);
if (bmp != null)
return bmp;
// if the file was not found locally we retrieve it from the web
try {
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(imageFile);
Utils.CopyStream(is, os);
os.close();
bmp = decodeImageFile(imageFile);
return bmp;
} catch (MalformedURLException e) {
Log.e(TAG, e.getMessage());
} catch (FileNotFoundException e) {
Log.e(TAG, e.getMessage());
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
return null;
}
/**
* This method is used for decoding a given image file. Also, to reduce
* memory, the image is also scaled.
*
* #param imageFile
* #return
*/
private Bitmap decodeImageFile(File imageFile) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(imageFile), null,
options);
// Find the correct scale value. It should be the power of 2.
// Deciding the perfect scaling value. (^2).
final int REQUIRED_SIZE = 100;
int tmpWidth = options.outWidth, tmpHeight = options.outHeight;
int scale = 1;
while (true) {
if (tmpWidth / 2 < REQUIRED_SIZE
|| tmpHeight / 2 < REQUIRED_SIZE)
break;
tmpWidth /= 2;
tmpHeight /= 2;
scale *= 2;
}
// decoding using inSampleSize
BitmapFactory.Options option2 = new BitmapFactory.Options();
option2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(imageFile),
null, option2);
} catch (FileNotFoundException e) {
Log.e(TAG, e.getLocalizedMessage());
}
return null;
}
private boolean reusedImage(NextImageToLoad image) {
Context c = image.imageView.getContext();
c.getContentResolver().notifyChange(PromotionsProvider.CONTENT_URI, null);
String tag = imageViewHolders.get(image.imageView);
if ((tag == null) || (!tag.equals(image.url)))
return true;
return false;
}
/**
* Clears the Memory and Local cache
*/
public void clearCache() {
memoryImgCache.clear();
localFileCache.clear();
}
/**
* This class implements a runnable that is used for updating the promotions
* images on the UI
*
*
*/
class UIupdater implements Runnable {
Bitmap bmp;
NextImageToLoad image;
public UIupdater(Bitmap bmp, NextImageToLoad image) {
this.bmp = bmp;
this.image = image;
Log.e("", "ui updater");
}
public void run() {
Log.e("ui updater", "ui updater");
if (reusedImage(image))
return;
Log.e("nick", "" + (bmp == null) + " chberugv");
if (bmp != null){
image.imageView.setImageBitmap(bmp);
Context c = image.imageView.getContext();
c.getContentResolver().notifyChange(PromotionsProvider.CONTENT_URI, null);
}else
image.imageView.setImageResource(defaultImageID);
}
}
private class ImagesRetriever implements Runnable {
NextImageToLoad image;
ImagesRetriever(NextImageToLoad image) {
this.image = image;
}
public void run() {
Log.e("images retirever", " images retriever");
if (reusedImage(image))
return;
Bitmap bmp = getBitmap(image.url);
memoryImgCache.insert(image.url, bmp);
if (reusedImage(image))
return;
UIupdater uiUpdater = new UIupdater(bmp, image);
Activity activity = (Activity) image.imageView.getContext();
activity.runOnUiThread(uiUpdater);
//Context c = image.imageView.getContext();
//c.getContentResolver().notifyChange(PromotionsProvider.CONTENT_URI, null);
}
}
/**
* This class encapsulates the image being downloaded.
*
* #author Nicolae Anca
*
*/
private class NextImageToLoad {
public String url;
public ImageView imageView;
public NextImageToLoad(String u, ImageView i) {
url = u;
imageView = i;
}
}
}
Modified Runnable:
class UIupdater implements Runnable {
Bitmap bmp;
NextImageToLoad image;
public UIupdater(Bitmap bmp, NextImageToLoad image) {
this.bmp = bmp;
this.image = image;
}
public void run() {
if (reusedImage(image))
return;
if (bmp != null){
image.imageView.setImageBitmap(bmp);
Context c = image.imageView.getContext();
c.getContentResolver().notifyChange(PromotionsProvider.CONTENT_URI, null);
}else
image.imageView.setImageResource(defaultImageID);
}
}
Thats an interesting way to do what you are doing. Have you tried extending the Simple Cursor Adapter?
What you do is implement a ViewHolder and put your imageview in it.
Then in your ImageRetriever, write a Listener which will be called once the image is ready and retrieved.
Implement this listener in the Viewholder.
You create the view in getView() and request for the image in BindView().
Once the image gets loaded, the list will be refreshed automatically.
one way to do it is by calling notifyDataSetChenged on listview, and another was is to have adapter as member variable and when something changes on listview you call a function that assigns new listadapter to member adapter. That way your list will be redraw on change.
I guess, you have to use some handler, calling after image load, which will call notifyDataSetChanged for list adapter
I have a ListView with rows which may have, or not, a picture. When there is a picture I start an image loader based on http://developer.android.com/resources/samples/XmlAdapters/src/com/example/android/xmladapters/ImageDownloader.html. One of my modifications is to replace the Color drawable shown while the image is loading by an animated image (a spinning wheel). In order to do that I set a spinner Bitmap in the constructor and I animate it in the download(String url, ImageView imageView) method, if the image to be downloaded is not in the cache. I clear the animation when the image is loaded and set to the ImageView.
The issue is that with the animation code
Animation rotate_picture = AnimationUtils.loadAnimation(context, R.anim.rotate_picture);
imageView.startAnimation(rotate_picture);
in the download method of my ImageDownloader, my adapter goes crazy and sometimes set the animation to downloaded images, or set the default picture to row with no picture.
When I comment these two lines everything is ok (except the spinner is not animated of course).
Anybody can help?
adapter's getView
#Override
public View getView(int position, View convertView, final ViewGroup parent) {
View row = convertView;
ItemHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new ItemHolder();
holder.title = (TextView)row.findViewById(R.id.title);
holder.date = (TextView)row.findViewById(R.id.date);
holder.desc = (EllipsizingTextView)row.findViewById(R.id.desc);
holder.pic = (ImageView)row.findViewById(R.id.pic);
row.setTag(holder);
}
else
{
holder = (ItemHolder)row.getTag();
}
Item item = data.get(position);
holder.title.setText(item.title);
holder.date.setText(Utils.UnixTime2String(item.published, "/"));
holder.desc.setMaxLines(3);
holder.desc.setText(item.descriptionintro);
if(item.list_images.size()>0){
holder.pic.setVisibility(View.VISIBLE);
imageLoader.download(GlobalData.BASE_URL + item.list_images.get(0), (ImageView) holder.pic);
}
else{
holder.pic.setVisibility(View.GONE);
holder.pic.setImageResource(0);
}
return row;
}
ImageDownloader
public class ImageDownloader {
private static final String LOG_TAG = "ImageDownloader";
private Integer xbound, ybound;
private static Context context;
private static Bitmap defaultPic;
public ImageDownloader(Context context, Bitmap defaultPic, Integer xbound, Integer ybound){
ImageDownloader.context = context;
ImageDownloader.defaultPic = defaultPic;
this.xbound = xbound;
this.ybound = ybound;
}
/**
* Download the specified image from the Internet and binds it to the provided ImageView. The
* binding is immediate if the image is found in the cache and will be done asynchronously
* otherwise. A null bitmap will be associated to the ImageView if an error occurs.
*
* #param url The URL of the image to download.
* #param imageView The ImageView to bind the downloaded image to.
*/
public void download(String url, ImageView imageView) {
resetPurgeTimer();
Bitmap bitmap = getBitmapFromCache(url);
if (bitmap == null) {
//Animation rotate_picture = AnimationUtils.loadAnimation(context, R.anim.rotate_picture);
//imageView.startAnimation(rotate_picture);
forceDownload(url, imageView);
} else {
cancelPotentialDownload(url, imageView);
imageView.setImageBitmap(bitmap);
}
}
/*
* Same as download but the image is always downloaded and the cache is not used.
* Kept private at the moment as its interest is not clear.
private void forceDownload(String url, ImageView view) {
forceDownload(url, view, null);
}
*/
/**
* Same as download but the image is always downloaded and the cache is not used.
* Kept private at the moment as its interest is not clear.
*/
private void forceDownload(String url, ImageView imageView) {
// State sanity: url is guaranteed to never be null in DownloadedDrawable and cache keys.
if (url == null) {
imageView.setImageDrawable(null);
return;
}
if (cancelPotentialDownload(url, imageView)) {
BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);
imageView.setImageDrawable(downloadedDrawable);
task.execute(url);
}
}
/**
* Returns true if the current download has been canceled or if there was no download in
* progress on this image view.
* Returns false if the download in progress deals with the same url. The download is not
* stopped in that case.
*/
private static boolean cancelPotentialDownload(String url, ImageView imageView) {
BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
if (bitmapDownloaderTask != null) {
String bitmapUrl = bitmapDownloaderTask.url;
if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
bitmapDownloaderTask.cancel(true);
} else {
// The same URL is already being downloaded.
return false;
}
}
return true;
}
/**
* #param imageView Any imageView
* #return Retrieve the currently active download task (if any) associated with this imageView.
* null if there is no such task.
*/
private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) {
if (imageView != null) {
Drawable drawable = imageView.getDrawable();
if (drawable instanceof DownloadedDrawable) {
DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable;
return downloadedDrawable.getBitmapDownloaderTask();
}
}
return null;
}
Bitmap downloadBitmap(String url) {
//final int IO_BUFFER_SIZE = 4 * 1024;
final HttpClient client = new DefaultHttpClient();
final HttpGet getRequest = new HttpGet(url);
try {
HttpResponse response = client.execute(getRequest);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
return null;
}
final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
try {
inputStream = entity.getContent();
return BitmapFactory.decodeStream(new FlushedInputStream(inputStream), null, null);
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (IOException e) {
getRequest.abort();
} catch (IllegalStateException e) {
getRequest.abort();
} catch (Exception e) {
getRequest.abort();
}
return null;
}
/*
* Cancel and remove download task for a given ImageView. Done when going previous/next to avoid "out of memory" when clicking fast
*/
void cancelDownload(ImageView imageView){
BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
if (bitmapDownloaderTask != null) {
bitmapDownloaderTask.cancel(true);
removeBitmapDownloaderTask(imageView);
}
}
private static boolean removeBitmapDownloaderTask(ImageView imageView) {
if (imageView != null) {
Drawable drawable = imageView.getDrawable();
if (drawable instanceof DownloadedDrawable) {
DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable;
downloadedDrawable.clearBitmapDownloaderTask();
return true;
}
}
return false;
}
/*
* An InputStream that skips the exact number of bytes provided, unless it reaches EOF.
*/
static class FlushedInputStream extends FilterInputStream {
public FlushedInputStream(InputStream inputStream) {
super(inputStream);
}
#Override
public long skip(long n) throws IOException {
long totalBytesSkipped = 0L;
while (totalBytesSkipped < n) {
long bytesSkipped = in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L) {
int b = read();
if (b < 0) {
break; // we reached EOF
} else {
bytesSkipped = 1; // we read one byte
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}
/**
* The actual AsyncTask that will asynchronously download the image.
*/
class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
private String url;
private final WeakReference<ImageView> imageViewReference;
public BitmapDownloaderTask(ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
}
/**
* Actual download method.
*/
#Override
protected Bitmap doInBackground(String... params) {
url = params[0];
return downloadBitmap(url);
}
/**
* Once the image is downloaded, associates it to the imageView
*/
#Override
protected void onPostExecute(Bitmap bitmap) {
if (isCancelled()) {
bitmap = null;
}
if(bitmap != null ){
addBitmapToCache(url, bitmap);
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
// Change bitmap only if this process is still associated with it
// Or if we don't use any bitmap to task association (NO_DOWNLOADED_DRAWABLE mode)
if (this == bitmapDownloaderTask) {
if(xbound!=null && ybound!=null){
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int xbounding = dpToPx(xbound);
int ybounding = dpToPx(ybound);
// Determine how much to scale: the dimension requiring less scaling is
// closer to the its side. This way the image always stays inside your
// bounding box AND either x/y axis touches it.
float xScale = ((float) xbounding) / width;
float yScale = ((float) ybounding) / height;
float scale = (xScale <= yScale) ? xScale : yScale;
// Create a matrix for the scaling and add the scaling data
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
// Create a new bitmap and convert it to a format understood by the ImageView
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
width = scaledBitmap.getWidth(); // re-use
height = scaledBitmap.getHeight(); // re-use
BitmapDrawable result = new BitmapDrawable(scaledBitmap);
// Apply the scaled bitmap
imageView.setImageDrawable(result);
// Now change ImageView's dimensions to match the scaled image
//LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) imageView.getLayoutParams();
//params.width = width;
//params.height = height;
//imageView.setLayoutParams(params);
}
else{
imageView.clearAnimation();
imageView.setImageBitmap(bitmap);
}
}
}
}
}
}
private int dpToPx(int dp)
{
float density = context.getResources().getDisplayMetrics().density;
return Math.round((float)dp * density);
}
/**
* A fake Drawable that will be attached to the imageView while the download is in progress.
*
* <p>Contains a reference to the actual download task, so that a download task can be stopped
* if a new binding is required, and makes sure that only the last started download process can
* bind its result, independently of the download finish order.</p>
*/
static class DownloadedDrawable extends BitmapDrawable {
private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;
public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {
super(context.getResources(), defaultPic);
bitmapDownloaderTaskReference =
new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);
}
public BitmapDownloaderTask getBitmapDownloaderTask() {
return bitmapDownloaderTaskReference.get();
}
public void clearBitmapDownloaderTask() {
bitmapDownloaderTaskReference.clear();
}
}
/*
*
* Image loaded listener
*
*/
OnImageDownloaderListener onImageDownloaderListener = null;
public interface OnImageDownloaderListener {
public abstract void onImageLoaded(int tag);
}
public void setOnImageDownloaderListener(OnImageDownloaderListener listener) {
onImageDownloaderListener = listener;
}
private void OnImageLoaded(int tag){
if(onImageDownloaderListener!=null) {
onImageDownloaderListener.onImageLoaded(tag);
}
}
/*
* Cache-related fields and methods.
*
* We use a hard and a soft cache. A soft reference cache is too aggressively cleared by the
* Garbage Collector.
*/
private static final int HARD_CACHE_CAPACITY = 20;
private static final int DELAY_BEFORE_PURGE = 10 * 1000; // in milliseconds
// Hard cache, with a fixed maximum capacity and a life duration
private final HashMap<String, Bitmap> sHardBitmapCache =
new LinkedHashMap<String, Bitmap>(HARD_CACHE_CAPACITY / 2, 0.75f, true) {
#Override
protected boolean removeEldestEntry(LinkedHashMap.Entry<String, Bitmap> eldest) {
if (size() > HARD_CACHE_CAPACITY) {
// Entries push-out of hard reference cache are transferred to soft reference cache
sSoftBitmapCache.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue()));
return true;
} else
return false;
}
};
// Soft cache for bitmaps kicked out of hard cache
private final static ConcurrentHashMap<String, SoftReference<Bitmap>> sSoftBitmapCache =
new ConcurrentHashMap<String, SoftReference<Bitmap>>(HARD_CACHE_CAPACITY / 2);
private final Handler purgeHandler = new Handler();
private final Runnable purger = new Runnable() {
public void run() {
clearCache();
}
};
/**
* Adds this bitmap to the cache.
* #param bitmap The newly downloaded bitmap.
*/
private void addBitmapToCache(String url, Bitmap bitmap) {
if (bitmap != null) {
synchronized (sHardBitmapCache) {
sHardBitmapCache.put(url, bitmap);
}
}
}
/**
* #param url The URL of the image that will be retrieved from the cache.
* #return The cached bitmap or null if it was not found.
*/
private Bitmap getBitmapFromCache(String url) {
// First try the hard reference cache
synchronized (sHardBitmapCache) {
final Bitmap bitmap = sHardBitmapCache.get(url);
if (bitmap != null) {
// Bitmap found in hard cache
// Move element to first position, so that it is removed last
sHardBitmapCache.remove(url);
sHardBitmapCache.put(url, bitmap);
return bitmap;
}
}
// Then try the soft reference cache
SoftReference<Bitmap> bitmapReference = sSoftBitmapCache.get(url);
if (bitmapReference != null) {
final Bitmap bitmap = bitmapReference.get();
if (bitmap != null) {
// Bitmap found in soft cache
return bitmap;
} else {
// Soft reference has been Garbage Collected
sSoftBitmapCache.remove(url);
}
}
return null;
}
/**
* Clears the image cache used internally to improve performance. Note that for memory
* efficiency reasons, the cache will automatically be cleared after a certain inactivity delay.
*/
public void clearCache() {
sHardBitmapCache.clear();
sSoftBitmapCache.clear();
}
/**
* Allow a new delay before the automatic cache clear is done.
*/
private void resetPurgeTimer() {
purgeHandler.removeCallbacks(purger);
purgeHandler.postDelayed(purger, DELAY_BEFORE_PURGE);
}
}