I have the following GridView:
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(context);
imageView.setScaleType(ScaleType.CENTER_CROP);
} else {
imageView = (ImageView) convertView;
}
if (mTemplates.get(position).getResource() != 0) {
LogService.log("", "zzzzzzzzzzzzzzzz======loaded from resource" + mTemplates.get(position).getResource() + "???????????" + mTemplates.size());
imageView.setImageResource(mTemplates.get(position).getResource());
} else {
imageView.setImageDrawable(mTemplates.get(position).getDrawableThumbnail());
// imageView.setImageResource(mTemplates.get(0).getResource());
LogService.log("", "zzzzzzzzzzzzzzzz======loaded from drawable");
LogService.log("", "=========SIZE: " + mTemplates.size());
}
return imageView;
}
Now I have some elements that do not have resources in the Drawables, but instead in a folder on the sdcard, so I create a drawable from the source of this pictures, and try to load that drawable on the gridview:
imageView.setImageDrawable(mTemplates.get(position).getDrawableThumbnail());
But its like the gridview does not recognise these, and if its on the same collumn with other pictures it is shown, but if its on another collumn (lower), it will only show 2-3mm of the picture (also doesn't recognise its position like its not therE).
If I hardcode and use the first picture from Resources like this:
imageView.setImageResource(mTemplates.get(0).getResource());
It all works, what could be the issue?
Because the actually size of the pic, is the small size, but when loading an imageView from Resources it strectches it to its parents size.
Resolved this issue by calculating the height needed, and then load all the pictures with that height:
public AdapterGridView(Context c) {
context = c;
DisplayMetrics metrics = new DisplayMetrics();
((Activity) c).getWindowManager().getDefaultDisplay().getMetrics(metrics);
if (Constants.IS_TABLET) {
height = metrics.widthPixels / 9 - (int) Util.pxFromDp(2, c);
} else {
height = metrics.widthPixels / 4 - (int) Util.pxFromDp(2, c);
}
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(context);
} else {
imageView = (ImageView) convertView;
}
imageView.setScaleType(ScaleType.CENTER_CROP);
imageView.setAdjustViewBounds(true);
if (mTemplates.get(position).getResource() != 0) {
imageView.setImageResource(mTemplates.get(position).getResource());
} else {
imageView.setImageDrawable(mTemplates.get(position).getDrawableThumbnail());
}
imageView.setLayoutParams(new LayoutParams(height, height));
return imageView;
}
Related
If I have (1)(2)(3)(4)(5)(6)(7)(8) images in GridView show - > (1)(2)(3)(4)(1)(2)(3)(4) which this code and this work which very good performance.
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {//here
// if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(300, 300));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
File imgFile = new File(ImagesApi.getCalculatedList().get(
position));
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile
.getAbsolutePath());
imageView.setImageBitmap(Bitmap.createScaledBitmap(myBitmap,
(int) (myBitmap.getWidth() * 0.12),
(int) (myBitmap.getHeight() * 0.12), true));
myBitmap.recycle();
} else {
imageView = (ImageView) convertView;
}
return imageView;
}
public int getCount() {
return ImagesApi.getCalculatedList().size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return position;
}
If I add if (convertView == null || position != convertView.getId()) { and imageView.setId(position); in "//here" I get images in GridView which correct order but which very very bad performance. Ui thread go very very slow.
ImagesApi.getCalculatedList() is constant ArrayList of image paths
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolderList holder;
if (convertView == null) {
holder = new ViewHolderList();
convertView = LayoutInflater.from(context)
.inflate(R.layout.children_row_list, null);
position=position+2;
Log.d("list position::", ""+position);
holder.img_children_view=(ImageView)convertView.findViewById(R.id.image_children);
holder.text_child_name=(TextView)convertView.findViewById(R.id.text_children_name);
holder.text_child_month=(TextView)convertView.findViewById(R.id.text_children_month);
holder.text_group_name=(TextView)convertView.findViewById(R.id.text_children_group);
holder.img_children_view1=(ImageView)convertView.findViewById(R.id.image_children1);
holder.text_child_name1=(TextView)convertView.findViewById(R.id.text_children_name1);
holder.text_child_month1=(TextView)convertView.findViewById(R.id.text_children_month1);
holder.text_group_name1=(TextView)convertView.findViewById(R.id.text_children_group1);
Resources r = getResources();
float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 90, r.getDisplayMetrics());
int pixel_height = (int) pixels;
holder.img_children_view.setLayoutParams(new LinearLayout.LayoutParams(80 , 80));
holder.img_children_view1.setLayoutParams(new LinearLayout.LayoutParams(80 , 80));
convertView.setTag(holder);
}
else{
holder = (ViewHolderList) convertView.getTag();
}
if(position %2 == 0){
// System.out.println(position + " is even number.");
holder.text_child_name.setText(children_list.get(position).getFirst_name());
holder.text_child_name.setText(children_list.get(position).getFirst_name());
holder.text_child_month.setText(display_month);
holder.text_group_name.setText(children_list.get(position).getGroup_name());
Bitmap bitmap = decodeFile(new File( Environment.getExternalStorageDirectory()+"/com.x/y/"+children_list.get(position).getPhoto()), ConfigurationData.staffImageSize,ConfigurationData.staffImageSize);
//holder.img_children_view.setImageBitmap(bitmap);
}
else{
// System.out.println(position+ " is odd number.");
holder.text_child_name1.setText(children_list.get(position).getFirst_name());
holder.text_child_name1.setText(children_list.get(position).getFirst_name());
holder.text_child_month1.setText(display_month);
holder.text_group_name1.setText(children_list.get(position).getGroup_name());
Bitmap bitmap1 = decodeFile(new File( Environment.getExternalStorageDirectory()+"/com.x/y/"+children_list.get(position).getPhoto()), ConfigurationData.staffImageSize,ConfigurationData.staffImageSize);
//holder.img_children_view1.setImageBitmap(bitmap1);
}
return convertView;
} //closing getview
}
I suggest using android's GridView with parameter numColumns equals 2
GridView # developer.android.com
Create Gridview with number of columns 2 android:numColumns="2".
In xml:
<GridView
android:id="#+id/sdcard"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_vertical|center_horizontal"
android:gravity="center_vertical|center_horizontal"
android:numColumns="2">
</GridView>
And in java code :
public View getView(int position, View convertView,
ViewGroup parent) {
final ViewHolderList holder;
if (convertView == null) {
holder = new ViewHolderList();
convertView = LayoutInflater.from(context)
.inflate(R.layout.children_row_list, null);
position=position+2;
Log.d("list position::", ""+position);
holder.img_children_view=(ImageView)convertView.findViewById(R.id.image_children);
holder.text_child_name=(TextView)convertView.findViewById(R.id.text_children_name);
holder.text_child_month=(TextView)convertView.findViewById(R.id.text_children_month);
holder.text_group_name=(TextView)convertView.findViewById(R.id.text_children_group);
holder.img_children_view1=(ImageView)convertView.findViewById(R.id.image_children1);
holder.text_child_name1=(TextView)convertView.findViewById(R.id.text_children_name1);
holder.text_child_month1=(TextView)convertView.findViewById(R.id.text_children_month1);
holder.text_group_name1=(TextView)convertView.findViewById(R.id.text_children_group1);
Resources r = getResources();
float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 90, r.getDisplayMetrics());
int pixel_height = (int) pixels;
holder.img_children_view.setLayoutParams(new LinearLayout.LayoutParams(80 , 80));
holder.img_children_view1.setLayoutParams(new LinearLayout.LayoutParams(80 , 80));
convertView.setTag(holder);
}
else{
holder = (ViewHolderList) convertView.getTag();
}
// System.out.println(position + " is even number.");
holder.text_child_name.setText(children_list.get(position).getFirst_name());
holder.text_child_name.setText(children_list.get(position).getFirst_name());
holder.text_child_month.setText(display_month);
holder.text_group_name.setText(children_list.get(position).getGroup_name());
Bitmap bitmap = decodeFile(new File( Environment.getExternalStorageDirectory()+"/com.x/y/"+children_list.get(position).getPhoto()), ConfigurationData.staffImageSize,ConfigurationData.staffImageSize);
//holder.img_children_view.setImageBitmap(bitmap);
return convertView;
} //closing getview
}
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.
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.
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.