I am developing an Android application for tablet which will be used as a catalog of many products (around 10 000).
I display them in a gridview, I only display the 250 first, and if I reach the end of these 250 I load 250 more.
My problem is the pictures. My application seems to work when I scroll not quickly, it is smooth, and there is no problems but it can use 300 or 400 MB of RAM, so I guess I'm doing something badly. I heard that I'm supposed to use WeakReferences but I'm not sure how to use them... That was for the first "problem". (It is not really important since the user may only use this application, and if it works very well... But yes, if I can improve it I will try)
The other big problem here is that when I do something like :
Scroll fast to the bottom
Immediately scroll fast to the top
Some pictures of the "bottom" are displayed on the pictures of the "top" (and not temporarly, they change again only if I scroll and come back at them).
What I know actually :
The mechanism of the griview reuse the views. If I have 10 views visibles, When the 5 first are not visibles, they are used for the 5 next ones that will be visible. I don't know how many view are in this "recycler".
This means that when I scroll to the bottom I see the 5 views which were not visible in the place of the 5 next ones for a few moment then the good views are loaded. To not have this bad effect, I set a picture white (the color of my background) using the method setRecyclerListener().
I don't "recycle" / use the good way to load my pictures and recycle them but don't know how to make it better
I use animations, I don't think there is any link with my problem due to them
I load the pictures in AsyncTask, that seems to work, but the picures are always loaded (in fast scroll too) which is not really a good thing
When scrolling bottom then top quickly sometimes I have the wrong pictures displayed. It may happen in other cases.
public class ProduitsAdapter extends ArrayAdapter<Article> {
private final Activity context;
private ArrayList<Article> params;
private Resources res;
static class ViewHolder {
public TextView numero;
public TextView design;
public ImageView image;
public ImageSwitcher imgSwitcher;
public ImageView codeBarre;
public TextView codeBarreText;
public TextView colisage;
public TextView col3;
public TextView col4;
public TextView col5;
public String image_string = "";
public boolean found = true;
public ImageView nouveaute;
}
public ProduitsAdapter(Activity context, ArrayList<Article> params) {
super(context, R.layout.list_single, params);
res = Catalogue.activity.getResources();
this.context = context;
this.params = params;
}
public int getCount() {
return params.size();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if (rowView == null) {
LayoutInflater inflater = context.getLayoutInflater();
ViewHolder viewHolder = new ViewHolder();
if (Catalogue.type_aff.equals("list")) {
rowView = inflater.inflate(R.layout.list_single, null);
viewHolder.numero = (TextView) rowView
.findViewById(R.id.numero);
viewHolder.design = (TextView) rowView
.findViewById(R.id.designation);
viewHolder.col3 = (TextView) rowView.findViewById(R.id.col3);
viewHolder.col4 = (TextView) rowView.findViewById(R.id.col4);
viewHolder.col5 = (TextView) rowView.findViewById(R.id.col5);
} else {
rowView = inflater.inflate(R.layout.fragment_grid_item, null);
viewHolder.numero = (TextView) rowView
.findViewById(R.id.numero);
viewHolder.design = (TextView) rowView
.findViewById(R.id.designation);
viewHolder.colisage = (TextView) rowView
.findViewById(R.id.grid_colisage);
viewHolder.codeBarre = (ImageView) rowView
.findViewById(R.id.code_barre);
viewHolder.codeBarreText = (TextView) rowView
.findViewById(R.id.code_barre_text);
viewHolder.nouveaute = (ImageView) rowView
.findViewById(R.id.img_nouveaute);
}
viewHolder.image = (ImageView) rowView.findViewById(R.id.img);
rowView.setTag(viewHolder);
}
ViewHolder holder = (ViewHolder) rowView.getTag();
if (Catalogue.type_aff.equals("list")) {
holder.col3.setText(params.get(position).getColonne_pref(3));
holder.col4.setText(params.get(position).getColonne_pref(4));
holder.col5.setText(params.get(position).getColonne_pref(5));
} else {
if (params.get(position).isNouveaute()) {
holder.nouveaute.setImageResource(R.drawable.nouveaute);
holder.nouveaute.setVisibility(ImageView.VISIBLE);
} else
holder.nouveaute.setVisibility(ImageView.GONE);
holder.colisage.setText(params.get(position).getColisage());
if (ProduitsFragment.barcodeVisible) {
holder.codeBarreText.setText(params.get(position)
.getGencodNegoce());
}
}
holder.numero.setText(params.get(position).getCodeArt());
holder.design.setText(params.get(position).getDesignation_pref());
// This is how I store my pictures, because finding one picture in a folder of 10 000 pictures takes too much time
String pattern_deb = holder.numero.getText() + "";
String chemin = Environment.getExternalStorageDirectory().getPath()
+ res.getString(R.string.chemin_app_data)
+ MainActivity.listDossiersSocietes
.get(MainActivity.societeSelected)
+ res.getString(R.string.chemin_dossier_photos);
for (int i = 0; i < pattern_deb.length() - 2; i++) {
chemin += "/" + pattern_deb.charAt(i);
}
chemin += "/";
File f = new File(chemin + params.get(position).getFichierPhoto());
if (f.exists()) {
holder.image_string = f.getAbsolutePath();
new loadImagesFromFileThread(holder, position).execute();
if (!Catalogue.type_aff.equals("list")
&& ProduitsFragment.barcodeVisible)
new loadBarCodeThread(holder, position).execute();
} else {
holder.image.setImageResource(R.drawable.notfound300);
}
return rowView;
}
private BitmapDrawable loadImagesFromFile(ViewHolder holder, int position) {
holder.found = true;
File bmp = new File(holder.image_string);
if (bmp.exists() && !bmp.isDirectory()) {
if (position < ProduitsFragment.gridView.getFirstVisiblePosition()
&& position > ProduitsFragment.gridView
.getLastVisiblePosition()) {
holder.found = false;
return null;
} else {
if (holder.image.getVisibility() == ImageView.VISIBLE) {
holder.found = false;
return null;
}
}
Bitmap myBitmap = BitmapFactory.decodeFile(bmp.getAbsolutePath());
int width = myBitmap.getWidth();
int height = myBitmap.getHeight();
int newWidth = 200;
int newHeight = 200;
if (Catalogue.type_aff.equals("list")) {
newWidth = 40;
newHeight = 40;
} else {
if (Catalogue.nbGrid == 5) {
newWidth = 200;
newHeight = 200;
}
if (Catalogue.nbGrid == 3) {
newWidth = 300;
newHeight = 300;
}
}
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(myBitmap, 0, 0, width,
height, matrix, true);
BitmapDrawable bmd = new BitmapDrawable(context.getResources(),
resizedBitmap);
return bmd;
} else {
holder.found = false;
return null;
}
}
private class loadImagesFromFileThread extends
AsyncTask<Void, Void, BitmapDrawable> {
ViewHolder holder;
int position;
public loadImagesFromFileThread(ViewHolder holder, int position) {
this.holder = holder;
this.position = position;
this.holder.image.setVisibility(ImageView.INVISIBLE);
}
#Override
protected BitmapDrawable doInBackground(Void... params) {
return loadImagesFromFile(holder, position);
}
#Override
protected void onPostExecute(BitmapDrawable bmd) {
if (ProduitsFragment.isNotScrolling) {
if (bmd != null) {
holder.image.setImageDrawable(bmd);
if (holder.image.getVisibility() != ImageView.VISIBLE
&& !(position < ProduitsFragment.gridView
.getFirstVisiblePosition() && position > ProduitsFragment.gridView
.getLastVisiblePosition())) {
Animation fadeIn = new AlphaAnimation(0, 1);
fadeIn.setInterpolator(new DecelerateInterpolator());
fadeIn.setDuration(500);
fadeIn.setStartOffset(500);
holder.image.startAnimation(fadeIn);
holder.image.setVisibility(ImageView.VISIBLE);
}
} else {
if (position < ProduitsFragment.gridView
.getFirstVisiblePosition()
&& position > ProduitsFragment.gridView
.getLastVisiblePosition()) {
Log.e("DEBUG", "...");
} else {
if (holder.image.getVisibility() != ImageView.VISIBLE) {
if (!holder.found) {
if (Catalogue.type_aff.equals("list")) {
holder.image
.setImageResource(R.drawable.notfound40);
} else {
if (Catalogue.nbGrid == 5) {
holder.image
.setImageResource(R.drawable.notfound200);
}
if (Catalogue.nbGrid == 3) {
holder.image
.setImageResource(R.drawable.notfound300);
}
}
Animation fadeIn = new AlphaAnimation(0, 1);
fadeIn.setInterpolator(new DecelerateInterpolator());
fadeIn.setDuration(500);
holder.image.startAnimation(fadeIn);
holder.image.setVisibility(ImageView.VISIBLE);
} else {
Animation fadeIn = new AlphaAnimation(0, 1);
fadeIn.setInterpolator(new DecelerateInterpolator());
fadeIn.setDuration(500);
holder.image.startAnimation(fadeIn);
}
holder.image.setVisibility(ImageView.VISIBLE);
}
}
}
}
}
}
}
I would appreciate any help to correct the problem of the wrong pictures, and if anyone can explain me how to load them properly with some code if possible (without using 300 MB of RAM) that would be really nice.
Related
I wants google ads in my listview at specific positions in portrait mode.
it causes error when clicking at ads and when back to app.
and sometimes when no error occur the ads view height increase and ads are floating when scroll listview.
public class ListAdaptor extends BaseAdapter {
private Context context;
AdView adView = null;
private ArrayList<String> titleList, descriptionList, pubDateList,
thumbnailList;
// int count = 2;
// private Context context;
private int listCount = 15;
//private final float mDensity;
int imageSize = 50;
LayoutInflater inflater;
int pageNumber = 0;
public ListAdaptor(Context c, ArrayList<String> titleList,
ArrayList<String> descriptionList, ArrayList<String> pubDateList,
ArrayList<String> thumbnailList, int pageNumber) {
context = c;
this.titleList = titleList;
this.descriptionList = descriptionList;
this.pubDateList = pubDateList;
this.thumbnailList = thumbnailList;
this.pageNumber = pageNumber;
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
// Log.d("imageSize "+display.getWidth(),"=="+imageSize);
imageSize = size.x / 3;
// Log.d("imageSize "+display.getHeight(),"="+imageSize);
//mDensity = c.getResources().getDisplayMetrics().density;
inflater = LayoutInflater.from(c);
// for (int i = 2; i < titleList.size(); i = i + 6) {
// titleList.add(i, "null");
// descriptionList.add(i, "");
// thumbnailList.add(i, "");
// pubDateList.add(i, "");
// i++;
// }
listCount = titleList.size();
}
#Override
public int getCount() {
return listCount;
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#SuppressWarnings("deprecation")
#SuppressLint("InflateParams")
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if (titleList.get(position).equalsIgnoreCase("null")) {
if (convertView == null || !(convertView instanceof AdView))
{
// Create a new AdView
if(adView == null)
{
try{
// Create a banner ad. The ad size and ad unit ID must be set before calling loadAd.
adView = new AdView(context.getApplicationContext());
adView.setAdSize(com.google.android.gms.ads.AdSize.BANNER);
adView.setAdUnitId(context.getString(R.string.banner_ad_unit_id));
// Convert the default layout parameters so that they play nice
// with
// ListView.
float density = context.getResources().getDisplayMetrics().density;
int height = Math.round(AdSize.BANNER.getHeight() * density);
AbsListView.LayoutParams params = new AbsListView.LayoutParams(
AbsListView.LayoutParams.FILL_PARENT, height);
adView.setLayoutParams(params);
AdRequest adRequest = new AdRequest.Builder().
addTestDevice(Secure.getString(context.getContentResolver()
,Secure.ANDROID_ID)).build();
adView.loadAd(adRequest);
adView.setAdListener(new AdListener() {
#Override
public void onAdOpened() {
// Save app state before going to the ad overlay.
}
});
}catch(Exception e){e.printStackTrace();}
}
return adView;
} else {
// Don’t instantiate new AdView, reuse old one
return convertView;
}
} else {
if (convertView == null || convertView instanceof AdView) {
view = inflater.inflate(R.layout.card_item, null);
// view.setLayoutParams(new
// ListView.LayoutParams(LayoutParams.MATCH_PARENT,(int) (90 *
// mDensity + 0.5f)));
} else {
view = convertView;
}
ImageView imgCardLitImage = (ImageView) view
.findViewById(R.id.imgCardLitImage);
TextView tvCardLitTitle = (TextView) view
.findViewById(R.id.tvCardLitTitle);
TextView tvCardListPubDate = (TextView) view
.findViewById(R.id.tvPubDate);
TextView tvCardLitDescription = (TextView) view
.findViewById(R.id.tvDescription);
ImageView imageVideoOverLay = (ImageView) view
.findViewById(R.id.imageVideoOverLay);
if (pageNumber == 1)
imageVideoOverLay.setVisibility(View.VISIBLE);
else
imageVideoOverLay.setVisibility(View.GONE);
/*
* If ImageList item is not available ,then display Description with
* Title
*/
if (thumbnailList.get(position) == null
&& descriptionList.get(position) != null) {
tvCardLitDescription.setVisibility(View.VISIBLE);
tvCardLitDescription.setText(descriptionList.get(position));
} else {
tvCardLitDescription.setVisibility(View.GONE);
}
tvCardLitTitle.setText(titleList.get(position));
tvCardListPubDate.setText(pubDateList.get(position));
// imgCardLitImage.getLayoutParams().width = (int) (370 * mDensity +
// 0.5f);
// imgCardLitImage.getLayoutParams().height = (int) (220 * mDensity
// + 0.5f);
/* Loading Card list Images */
try {
new ImageLoader(context, imageSize).DisplayImage(
thumbnailList.get(position), imgCardLitImage);
} catch (Exception e) {
e.printStackTrace();
}
}
return view;
}
}
I'm using GridView for my crossword puzzle. And after scrolling the gridview messed up, all the black parts (non leter box) showing letters which not suppose to happen.
Here is my adapter. Can anyone help? Thanks
private class CrossWordPuzzleAdapter extends BaseAdapter {
private Context mContext;
private int mWidth, mHeight;
public CrossWordPuzzleAdapter(Context c, int width, int height) {
mContext = c;
mWidth = width;
mHeight = height;
}
public int getCount() {
return mWidth * mHeight;
}
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) {
ViewHolder holder = null;
LayoutInflater mInflater = (LayoutInflater) mContext
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.box_layout, null);
holder = new ViewHolder();
holder.numberText = (TextView) convertView.findViewById(R.id.numberText);
holder.charText = (GridViewItem) convertView.findViewById(R.id.charText);
convertView.setTag(holder);
} else
holder = (ViewHolder) convertView.getTag();
int x = -1, y = -1;
if (position < mWidth) {
x = position;
y = 0;
} else {
x = position % mWidth;
y = position / mHeight;
}
if (mPuzzleBoard.getCharPlace(x, y) != '\0' && mPuzzleBoard.getCharPlace(x, y) != ' ') {
String questionNoStr = mPuzzleBoard.getQuestionNo(x, y);
holder.numberText.setText(questionNoStr);
if (isRevealed) {
holder.charText.setText("" + Character.toString(mPuzzleBoard.getCharPlace(x, y)).toUpperCase());
holder.charText.setTextColor(Color.GREEN);
}
holder.charText.setBackground(getResources().getDrawable(R.drawable.letter_box_white));
} else {
holder.charText.setBackground(getResources().getDrawable(R.drawable.letter_box_black));
convertView.setSelected(false);
}
return convertView;
}
I finally found the solution. The error box showing letters are actually previous boxes of Views that contains letters previously. So, after scrolling the position are all messed up, and even though I have set the box colour to black, but I didn't set the box to be empty.
so this is what I do:
else {
holder.numberText.setText(""); //<< reset the box to empty
holder.charText.setText(""); //<< reset the box to empty
holder.charText.setBackground(getResources().getDrawable(R.drawable.letter_box_black));
convertView.setSelected(false);
}
I use custom CursorAdapter with custom items.
I need height of view to resize Bitmap from assets folder and set this resized bitmap to ImegeView in list item;
#Override
public void bindView(View view, final Context context, final Cursor cursor) {
final ViewHolder holder = (ViewHolder) view.getTag();
final int imgCol = cursor.getColumnIndex(TableOdelice.COLUMN_URL);
int titleCol = cursor.getColumnIndex(TableOdelice.COLUMN_TITRE);
final int themeCol = cursor.getColumnIndex(TableOdelice.COLUMN_THEME);
String tempPath = getPath(cursor.getString(themeCol), cursor.getString(imgCol));
final String path = tempPath.replace(".", "c.");
String[] arr = cursor.getString(titleCol).split("\\*");
holder.title.setText(arr[0]);
holder.subTitle.setText(arr[1]);
if (itemHeight > 0) {
showThumb(itemHeight, holder.img, path);
} else {
final ImageView v = holder.mainImage;
v.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
itemHeight = v.getHeight();
showThumb(itemHeight, holder.img, path);
}
});
}
}
private void showThumb(int height, final ImageView iv, final String path) {
if (thumbs.containsKey(path)) {
iv.setImageBitmap(thumbs.get(path));
} else {
InputStream is = null;
try {
is = context.getAssets().open(path);
} catch (IOException e) {
Log.d("no file at path", path);
e.printStackTrace();
}
if (is != null) {
Bitmap btm = btmHelper.scaleToHeight(BitmapFactory.decodeStream(is);, height);
thumbs.put(path, btm);
iv.setImageBitmap(btm);
}
}
}
For getting view height I use OnGlobalLayoutListener() of view.
But it's very slow ...
Any ideas?
I find answer for my question.
Using this construction I get a correct width or height of view inside adapter for each view.
final ImageView v = holder.mainImage;
v.post(new Runnable() {
#Override
public void run() {
itemHeight = v.getHeight();
Log.d("Height", "" + itemHeight);
}
});
}
Maybe it will help somebody :)
Just give it a try may be it will be faster
v.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
itemHeight = v.getHeight();
showThumb(itemHeight, holder.img, path);
v.getViewTreeObserver().removeGlobalOnLayoutListener( ActivityInsatance);
}
});
If you have top or bottom margins, a bug will appear. When you will scroll this listview, a height of each row will increase. In case of v.getViewTreeObserver().addOnGlobalLayoutListener it will grow infinitely. So, my solution follows.
holder.layout.post(new Runnable() {
#Override
public void run() {
int height = holder.layout.getMeasuredHeight(); // Total row height.
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) holder.textView.getLayoutParams();
holder.textView.setHeight(height - lp.topMargin - lp.bottomMargin);
});
where holder.layout is a link to root RelativeLayout of an adapter's row.
I am using a GridView to display images. The images are downloaded from a feed and added to a BitmapCache. The GridView is inside of a ViewFlipper (which has a ListView as second View). I'm using GridView for the first time but I've worked with Adapters many times when I used ListViews.
At the moment, the feed only delivers two images. But when I start my Fragment containing the GridView I get an OutOfMemoryError caused bei BitmapFactory.decodeStream(). When I took a deeper look into the logcat, I noticed that getView() inside of my Adapter for the GridView is called many many times.
I know that it's nothing special if getView() is called more than once, but the getView()-method in my Adapter gets called over 120 times only for position 0. And I don't really understand why it's called so often. But I'm pretty sure that this caused my memory problem as this method tries to load a bitmap over 100 times in just a few seconds.
As I'm already trying to recycle my view with a ViewHolder I'm quite helpless at the moment and I hope somebody can explain me this massive calls of getView() and/or might give me a hint to solve my problem.
The getView()-mthod of my adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.pictures_grid_item, parent, false);
holder.image = (ImageView) convertView.findViewById(R.id.picturesGridImage);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
holder.image.setImageBitmap(null);
}
Picture picture = (Picture) pictureList.get(position);
String imageUrl = picture.getUrl();
if (!TextUtils.isEmpty(imageUrl)) {
holder.image.setTag(imageUrl);
ImageLoader.getInstance(context).loadImageWithTagCheck(holder.image);
}
return convertView;
}
private static class ViewHolder {
ImageView image;
}
The loadImageWithTagCheck()-method just checks if the image has already been downloaded (which deffinitely should be the case)
The Fragment which holds the View:
public class PicturesFragment extends BaseFragment {
private List<Parcelable> pictureList;
private PicturesGridAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.pictures_fragment, container, false);
// TODO: Remove final after development
final MediaActivity activity = (MediaActivity) getActivity();
pictureList = activity.getPictures();
adapter = new PicturesGridAdapter(activity, pictureList);
GridView gridview = (GridView) view.findViewById(R.id.picturesGrid);
gridview.setAdapter(adapter);
gridview.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
Toast.makeText(activity, "" + position, Toast.LENGTH_SHORT).show();
}
});
return view;
}
}
BTW: I'm not using *wrap_content* anywhere.
Edit:
Here's the code of the imageloader. Ofcourse, the ImageLoader is the problem which causes the outOfMemoryError. But I think that the problem is rather something with the adapter because 120 calls of getView() for position 0 just after creating the view can't be right. And the Adapter is just created once so it's >120 calls in a single instance of my adapter.
(this is a pretty huge and complex project so the "simple" imageloader has a lot of code)
public void loadImageWithTagCheck(final ImageView view) {
final String url = (String) view.getTag();
final Handler uiHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
}
};
if (imageHandler != null) {
imageHandler.post(new Runnable() {
#Override
public void run() {
final Bitmap bmp = getImage(url, view);
uiHandler.post(new Runnable() {
#Override
public void run() {
String tagUrl = (String) view.getTag();
if (tagUrl.equals(url) && bmp != null
&& !bmp.isRecycled()) {
scaleBitmapAndAdjustViewByHeight(view, bmp);
} else if (bmp != null) {
bmp.recycle();
}
}
});
}
});
}
}
private Bitmap getImage(String url, View v) {
Bitmap bmp = null;
if (url != null && !TextUtils.isEmpty(url)) {
String md5Url = Utility.md5(url);
if (cache.containsKey(md5Url)) {
bmp = cache.getBitmap(md5Url);
} else {
HttpGet httpGet = new HttpGet();
HttpClient httpClient = new DefaultHttpClient();
HttpResponse response = null;
try {
URI uri = new URI(url);
httpGet.setURI(uri);
response = httpClient.execute(httpGet);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity entity = response.getEntity();
if (entity != null) {
final BufferedInputStream buffIn = new BufferedInputStream(
entity.getContent(), Utils.IO_BUFFER_SIZE);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.outWidth = v.getWidth();
options.outHeight = v.getHeight();
options.inPurgeable = true;
options.inInputShareable = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
bmp = BitmapFactory.decodeStream(buffIn, null,
options);
}
}
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
if (bmp != null) {
cache.put(md5Url, bmp);
}
}
}
return bmp;
}
private void scaleBitmapAndAdjustViewByHeight(final ImageView view,
final Bitmap bmp) {
ViewTreeObserver vto = view.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
view.getViewTreeObserver().removeOnGlobalLayoutListener(
this);
} else {
view.getViewTreeObserver().removeGlobalOnLayoutListener(
this);
}
// Get current dimensions
int width = bmp.getWidth();
int height = bmp.getHeight();
// 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.
int imageViewHeightFromXMLinPixels = view.getHeight();
float xScale = (float) ((imageViewHeightFromXMLinPixels * 2.75) / width);
float yScale = ((float) imageViewHeightFromXMLinPixels)
/ 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
Bitmap scaledBitmap = Bitmap.createBitmap(bmp, 0, 0, width,
height, matrix, true);
width = scaledBitmap.getWidth(); // re-use
view.setImageBitmap(scaledBitmap);
view.getLayoutParams().width = width;
}
});
view.requestLayout();
}
Get rid of the scaleBitmapAndAdjustViewByHeight(...) method.
Instead, do a simple view.setImageBitmap(bmp).
Why?
scaleBitmapAndAdjustViewByHeight(...) calls view.requestLayout() which probably leads to calling your adapters getView(...) and ends in a deadlock and finally the OutOfMemoryError.
I am new to android. I am displaying images in gridview by using AsyncTask. But there are some issues like:
1: onScroll AsyncTask tasks gets call again.
2: Images are not displaying correctly ( Once I scroll it shows top image and load the original latter).
here is my code:
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater layoutInflater = (LayoutInflater) ctx
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ListRowHolder listRowHolder;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.ll_sponsor_list_item,
parent, false);
listRowHolder = new ListRowHolder();
listRowHolder.imgSponsor = (ImageView) convertView
.findViewById(R.id.imggrid_item_image);
convertView.setTag(listRowHolder);
} else {
listRowHolder = (ListRowHolder) convertView.getTag();
}
try {
task = new BitmapWorkerTask(listRowHolder.imgSponsor);
task.image_path = ImageName.get(position);
task.execute(1);
} catch (Exception e) {
if (thisLogger != null) {
thisLogger.error(e.toString());
thisLogger.error("\r\n");
}
}
return convertView;
}
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private String image_path;
public BitmapWorkerTask(ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
}
#Override
protected Bitmap doInBackground(Integer... params) {
try {
while (running) {
Bitmap picture = BitmapFactory.decodeFile(image_path);
int width = picture.getWidth();
int height = picture.getHeight();
float aspectRatio = (float) width / (float) height;
int newWidth = 98;
int newHeight = (int) (98 / aspectRatio);
Log.v("ImageList", "L");
return picture = Bitmap.createScaledBitmap(picture,
newWidth, newHeight, true);
}
} catch (Exception e) {
if (thisLogger != null) {
thisLogger.error(e.toString());
thisLogger.error("\r\n");
}
}
return null;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
Please let me know whats wrong here.