strange behaviour with selecting and showing images from sdcard - android

I have made a simple android application that displays images in a gridview and you can select some images and send them. This is my getView method.
public View getView(int position, View convertView, ViewGroup parent)
{
View v;
if (convertView == null)
{
LayoutInflater li = getLayoutInflater();
v = li.inflate(R.layout.imageview, null);
final CheckBox cb = (CheckBox) v.findViewById(R.id.checkbox);
cb.setOnCheckedChangeListener(new AddPhotos());
ImageView iv = (ImageView) v.findViewById(R.id.image);
//make image clickable so that it is checked when clicked on the image
iv.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
cb.setChecked((cb.isChecked() ? false : true));
}
});
imagecursor.moveToPosition(position);
uriList.add(imagecursor.getString(image_column_index));
File image = new File(imagecursor.getString(image_column_index));
Bitmap actualBitmap = resizeBitMapImage(image.getPath(), image_width, image_height);
iv.setImageBitmap(actualBitmap);
iv.setLayoutParams(new FrameLayout.LayoutParams(95, 95));
System.gc();
}
else
{
v = convertView;
System.gc();
}
return v;
}
}
Now the problem wit this was that for less images i.e when all images are displayed without any need to scroll, it was working fine. But if there were images not visible and you have to scroll down, then it showed a strange behavior by repeating the earlier images and changing the checked state of the images when you scroll down or up. I changed the getView method like
public View getView(int position, View convertView, ViewGroup parent)
{
View v;
if (convertView == null)
{
LayoutInflater li = getLayoutInflater();
v = li.inflate(R.layout.imageview, null);
}
else
{
v = convertView;
System.gc();
}
final CheckBox cb = (CheckBox) v.findViewById(R.id.checkbox);
cb.setOnCheckedChangeListener(new AddPhotos());
ImageView iv = (ImageView) v.findViewById(R.id.image);
// make image clickable so that it is checked when clicked on the image
iv.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
cb.setChecked((cb.isChecked() ? false : true));
}
});
imagecursor.moveToPosition(position);
uriList.add(imagecursor.getString(image_column_index));
File image = new File(imagecursor.getString(image_column_index));
Bitmap actualBitmap = resizeBitMapImage(image.getPath(), image_width, image_height);
iv.setImageBitmap(actualBitmap);
iv.setLayoutParams(new FrameLayout.LayoutParams(95, 95));
System.gc();
return v;
}
}
Now the order of the images is not changing but scrolling up or down throws an ANR and the checked state is also changed (i guess randomly). the traces.txt shows that it is coming from bitMapImage = BitmapFactory.decodeFile(filePath, options); line in the resizeBitMapImage method which is as below
public static Bitmap resizeBitMapImage(String filePath, int targetWidth, int targetHeight)
{
Bitmap bitMapImage = null;
// First, get the dimensions of the image
Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
double sampleSize = 0;
// Only scale if we need to
// (16384 buffer for img processing)
Boolean scaleByHeight = Math.abs(options.outHeight - targetHeight) >= Math.abs(options.outWidth - targetWidth);
if (options.outHeight * options.outWidth * 2 >= 1638)
{
// Load, scaling to smallest power of 2 that'll get it <= desired
// dimensions
sampleSize = scaleByHeight ? options.outHeight / targetHeight : options.outWidth / targetWidth;
sampleSize = (int) Math.pow(2d, Math.floor(Math.log(sampleSize) / Math.log(2d)));
}
// Do the actual decoding
options.inJustDecodeBounds = false;
options.inTempStorage = new byte[128];
while (true)
{
try
{
options.inSampleSize = (int) sampleSize;
bitMapImage = BitmapFactory.decodeFile(filePath, options);
break;
}
catch (Exception ex)
{
try
{
sampleSize = sampleSize * 2;
}
catch (Exception ex1)
{
}
}
}
return bitMapImage;
}
Now i am very new to android development and am very confused. Please any help will be greatly appreciated
EDIT: The images are being added to gridview and the getView method is for the imageAdapter for this gridview.

Related

Android: To get a image from server

I used a ListView which contains a ImageView and a TextView. I want to get a image from server. I debug the code below, which told me that I can get the image successful, but when return, the image disappeared. I don't know why. I am the new begginner of android. Hope anyone can help me.
The ListView Adapter class:
public View getView(int position, View convertView, ViewGroup parent) {
News news = getItem(position);
View view = LayoutInflater.from(getContext()).inflate(resourceId, null);
newsImage = (ImageView) view.findViewById(R.id.news_image);
newsTitle = (TextView) view.findViewById(R.id.news_title);
newsTitle.setText(news.getTitle());
bitmap = HttpUtil.sendImageRequest(news.getImageUrl());
newsImage.setImageBitmap(ImageUtility.ImageSolution(bitmap, newsImage));
return view;
}
the sendImageRequest method:
public static Bitmap sendImageRequest(final String address){
final Bitmap[] bitmap = new Bitmap[1];
new Thread(new Runnable() {
#Override
public void run() {
HttpURLConnection connection = null;
try {
connection = (HttpURLConnection) new URL(address).openConnection();
connection.setRequestMethod("GET");
connection.setDoInput(true);
InputStream in = connection.getInputStream();
bitmap[0] = BitmapFactory.decodeStream(in);
} catch (java.io.IOException e) {
e.printStackTrace();
} finally {
if (connection != null){
connection.disconnect();
}
}
}
}).start();
return bitmap[0];
}
the ImageSolution method:
public static Bitmap ImageSolution (Bitmap bitmap, ImageView imageView){
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int newWidth = imageView.getWidth();
int newHeight = imageView.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width,
height, matrix, true);
return resizedBitmap;
}
the address is http://p2.zhimg.com/10/7b/107bb4894b46d75a892da6fa80ef504a.jpg.
Thank you so much.
You can use a third party library named Glide , which is recommended by google . To add this library , add the the following dependency in your build.gradle file , in module app .
dependencies {
compile 'com.github.bumptech.glide:glide:3.5.2'
compile 'com.android.support:support-v4:22.0.0'
}
And then you can simply load image in following way
Glide.with(context)
.load(news.getImageUrl())
.into(newsImage);
bitmap = HttpUtil.sendImageRequest(news.getImageUrl());
bitmap will always be empty as it is an image request. The function starts a thread but returns immediately. So returns an empty bitmap.
newsImage.setImageBitmap(ImageUtility.ImageSolution(bitmap, newsImage));
If you then try to set that empty bitmap to an imageview things go wrong.
Redesign your app. Only when the thread finishes there is a valid bitmap. And then you can use it.
Why don't you use the Picasso library?
It's really easy to use
Picasso.with(context).load(news.getImageUrl()).into(newsImage);
And it provides caching and image transformations.
Make a viewHolder class inside adapter class,
private static class ViewHolder {
public TextView newsTitle = null;
public ImageView newsImage = null;
}
then code your getView like,
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder itemHolder;
View view = convertView;
if (view == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
itemHolder = new ViewHolder();
view = inflater.inflate(layoutResID, parent, false);
itemHolder.newsImage = (ImageView) view.findViewById(R.id.news_image);
itemHolder.newsTitle = (TextView) view.findViewById(R.id.news_title);
view.setTag(itemHolder);
} else {
itemHolder = (viewHolder) view.getTag();
}
News news = getItem(position);
itemHolder.newsTitle.setText(news.getTitle());
bitmap = HttpUtil.sendImageRequest(news.getImageUrl());
itemHolder.newsImage.setImageBitmap(ImageUtility.ImageSolution(bitmap, newsImage));
return view;
}
or, you can use picasso, it is easy to use...
add this line inside dependencies,
compile 'com.squareup.picasso:picasso:2.5.0'
and for loading image code for loading image will be,
Picasso.with(context).load(news.getImageUrl()).into(itemHolder.newsImage);

How to add TextView inside a GridView filled with ImageView

I have a GridView where I add images directly with ImageView (I don't use an XML for the image). Now, I want to add image name at the bottom of each cell using a TextView. How can I do it? Thanks in advance.
Custom Adapter Class:
public class GridViewImageAdapter extends BaseAdapter {
private Activity _activity;
private ArrayList<String> _filePaths = new ArrayList<String>();
private int imageWidth;
private GridView imageCarrete;
public GridViewImageAdapter(Activity activity, ArrayList<String> filePaths,
int imageWidth, GridView imageCarrete) {
this._activity = activity;
this._filePaths = filePaths;
this.imageWidth = imageWidth;
this.imageCarrete = imageCarrete;
}
#Override
public int getCount() {
return this._filePaths.size();
}
#Override
public Object getItem(int position) {
return this._filePaths.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(_activity);
} else {
imageView = (ImageView) convertView;
}
// get screen dimensions
Bitmap image = decodeFile(_filePaths.get(position), imageWidth,
imageWidth);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(imageWidth,
imageWidth));
imageView.setImageBitmap(image);
// Listener del GridView
imageCarrete.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
Intent i = new Intent(_activity, FullScreenViewActivity.class);
i.putExtra("position", position);
_activity.startActivityForResult(i, 1234);
}
});
return imageView;
}
/*
* Resizing image size
*/
public static Bitmap decodeFile(String filePath, int WIDTH, int HIGHT) {
try {
File f = new File(filePath);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
final int REQUIRED_WIDTH = WIDTH;
final int REQUIRED_HIGHT = HIGHT;
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_WIDTH
&& o.outHeight / scale / 2 >= REQUIRED_HIGHT)
scale *= 2;
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
public void remove(String path){
_filePaths.remove(path);
}
}
GridView XML
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/grid_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:numColumns="auto_fit"
android:gravity="center"
android:stretchMode="columnWidth"
android:background="#000000">
</GridView>
Within your getView() method, replace your ImageView with a TextView with a drawable:
TextView tv = new TextView(context);
tv.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
you will supply the drawable to the top and 0 to the rest, ie:
tv.setCompoundDrawablesWithIntrinsicBounds(0, yourDrawable, 0, 0);
Just create a LinearLayout as you are creating Imagview in getView() method... add ImageView and TextView to it with addView() method.... have a look ..
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout _ll;
if (convertView == null) {
_ll = new LinearLayout(mContext);
_ll.setOrientation(LinearLayout.VERTICAL);
ImageView img = new ImageView(mContext);
img.setLayoutParams(new LinearLayout.LayoutParams(100, 100)); // your image size
img.setBackgroundResource(images[position]); // here pass your array list position
_ll.addView(img);
TextView text = new TextView(mContext);
text.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
text.setText("dsaf");
text.setGravity(Gravity.CENTER);
_ll.addView(text);
} else {
_ll = (LinearLayout) convertView;
}
return _ll;
}
You can also use RelativeLayout if you want to overlay your text over image..

Gridview wrong image when scrolling

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.

OutOfMemoryError caused by multiple (>120) calls of getView in GridView

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.

Android grid view load Image effectively

I am new to android. I have more than thousand images in a directory. I am showing images thumb in grid view. With following code It's works. but the problem is it takes 45 second to load the view. I need it as: Display grid with loader and load Images one by one. So user can not wait for last image to load.
The code is:
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 {
listRowHolder.imgSponsor
.setImageBitmap(decodeSampledBitmapFromResource(
ImageName.get(position)));
} catch (Exception e) {
Toast.makeText(ctx, e + "", Toast.LENGTH_SHORT).show();
}
return convertView;
}
public static Bitmap decodeSampledBitmapFromResource(String fileName) {
Bitmap picture = BitmapFactory.decodeFile(fileName);
int width = picture.getWidth();
int height = picture.getWidth();
float aspectRatio = (float) width / (float) height;
int newWidth = 98;
int newHeight = (int) (98 / aspectRatio);
return picture = Bitmap.createScaledBitmap(picture, newWidth,
newHeight, true);
}
The reason it is slow is because you are decoding the file AND generating the scaled bitmap on your UI thread, for many images. Because you are doing long operations, you will need to do lazy loading of your images.
The premise is similar to the solution in the link (you can use a Handler) but you will be decoding the file and scaling the Bitmaps instead of downloading the image there.

Categories

Resources