Guys my program takes really long to open my gallery activity. I have gone through my code and I think I have found whats making the the activity slow down. I think its the part where the image gets decoded. It slows down when there are many images in my gallery and it looks like it takes time to decode them all.
This is my code
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(_activity);
} else {
imageView = (ImageView) convertView;
}
// THIS BELOW IN SEPARATE THREAD
Bitmap image = decodeFile(_filePaths.get(position), imageWidth, imageWidth);
// THIS ABOVE IN SEPARATE THREAD
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(imageWidth,
imageWidth));
imageView.setImageBitmap(image);
// image view click listener
imageView.setOnClickListener(new OnImageClickListener(position));
return imageView;
}
I think putting the image decoding line in a separate thread might speed up te program. Can anyone tell me how to do it?
You can not use a thread like that. Your whole function will still have to wait for the image to get decoded before returning, because you are returning imageView variable.
First of all, why are you casting convertView to an ImageView, I highly doubt its a good idea to do that. You might have to change your xml and add an imageView, if its missing. Then get a reference to that imageView in this function by using something like
final ImageView listImage = (ImageView) convertView.findViewById(R.id.listImage);
Finally, fire off your thread and set the image into this listImage variable, while returning convertView. Use an ExecuterService.
Here is a simple example.
private final ExecutorService executorService = Executors.newCachedThreadPool();
private final int layoutResourceId; //set this
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null){
LayoutInflater inflater = (_activity).getLayoutInflater();
convertView = inflater.inflate(layoutResourceId, parent, false);
}
final ImageView listImage = (ImageView) convertView.findViewById(R.id.listImage);
// THIS BELOW IN SEPARATE THREAD
executorService.submit(new Runnable() {
#Override
public void run() {
Bitmap image = decodeFile(_filePaths.get(position), imageWidth, imageWidth);
listImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
listImage.setLayoutParams(new GridView.LayoutParams(imageWidth, imageWidth));
listImage.setImageBitmap(image);
listImage.setOnClickListener(new OnImageClickListener(position));
}
});
return convertView;
}
I hope you got the general idea.
I highly suggest you use Picasso. Google it. You can do all this without having to implement your own threading, get the advantage of caching and do it in far lesser lines of code. You will run out of memory on low end devices because you are not recycling your bitmap.
Related
I'm using Grid View in order to show images I have stored, but as I scroll down the images disappear in Image View and don't load again.I also use thread for loading images into Image View.
Here is my code(also these codes are in my grid view adapter class) :
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
Log.e("sara" , "this part takes time");
LayoutInflater inflater = getLayoutInflater();
convertView = getLayoutInflater().inflate(R.layout.gallery_gridsq, parent, false);
iv = (ImageView) convertView.findViewById(R.id.icon);
file = new File(Uri.parse(getItem(position).toString()).getPath());
new myTask(iv, file).execute();
return convertView;
}
private class myTask extends AsyncTask <Void , Void ,Bitmap> {
ImageView iv;
File file;
public myTask(ImageView iv, File file) {
this.iv=iv;
this.file= file;
}
#Override
protected Bitmap doInBackground(Void... params) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inJustDecodeBounds = false;
options.inSampleSize = 8;
try {
bmp = BitmapFactory.decodeStream(new FileInputStream(file), null, options);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return bmp;
}
#Override
protected void onPostExecute(Bitmap aVoid) {
iv.setImageBitmap(aVoid);
}
}
I can think of the memory issue that caused me the similar trouble.
Check if your getView is still called when you scroll down with your log: Log.e("sara" , "this part takes time");
If that line is called when you scroll down, check the memory from android monitor provided in the android studio.
click android monitor at the bottom > monitors> and observe if memory reaches the cap depending on the set up (probably 128 or 256MB).
If so you are having issues with memory. The very possible reason is that you are not recycling the list and the memory is stacking. At the peak of memory, the images will not be loaded.
It should be implemented in a way that the images that you already loaded be deleted as you scroll down and load new images.
Also, try using glide for it has a good solution with memory issues and generally better in many fields than bitmapfactory.
I am newbie to native android development. I am working on android studio. I have 3 tabs. One is for map second is for camera to take pictures and 3rd is for pictures in which all taken were to be shown. I have implemented map and camera, for viewing image i am following this tutorial. Here in a class i added Bitmap image = Bitmap image = decodeFile(_filePaths.get(position), imageWidth, imageWidth);
But it's showing me error Cannot Resolve method decodeFile. I have searched for it and couldn't find any solution for it.
Below is my code
#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);
// image view click listener
imageView.setOnClickListener(new OnImageClickListener(position));
return imageView;
}
Any help would be highly appreciated.
it is custom method defined in the class (in the tutorial you should have missed to copy a method named decodeFile() ) check again ..
Use this
Bitmap image = BitmapFactory.decodeFile(_filePaths.get(position), imageWidth, imageWidth);
This question already has answers here:
Strange OutOfMemory issue while loading an image to a Bitmap object
(44 answers)
Closed 9 years ago.
Hello I have created an Application.
In application i loading the several images from URL. But during the loading of images i get the Out Of Memory exception.
Give me solution about this problem.
Well, Now image loading time from internet has many solution. You may also use this library "Android-Query" https://code.google.com/p/android-query/wiki/ImageLoading .It will give you all the required activity.Make sure what you want to do ? and read library wiki page. and solve image loading restriction.
This is my code:-
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
}
ImageView imageview = (ImageView) v.findViewById(R.id.icon);
AQuery aq = new AQuery(convertView);
String imageUrl = "http://www.vikispot.com/z/images/vikispot/android-w.png";
aq.id(imageview).progress(this).image(imageUrl, true, true, 0, 0, new BitmapAjaxCallback(){
#Override
public void callback(String url, ImageView iv, Bitmap bm, AjaxStatus status){
iv.setImageBitmap(bm);
}
});
}
return v;
}
it should be solve your lazy loading
I am giving Picasso a try for some easier memory management with images. I have just been trying to implement it within my fragment however I can't seem to get it to work.
mainLayout.setBackground(new BitmapDrawable(getResources(), Picasso.with(mainLayout.getContext()).load(R.drawable.background2).get()));
Where mainLayout is a LinearLayout. I also tried this:
Picasso.with(getActivity().getApplicationContext()).load(R.drawable.background2).into(imageView1);
I have tried Picasso.with(this)... but this doesn't work at all.
I keep getting an Exception of:
java.lang.IllegalStateException: Method call should not happen from the main thread.
at com.squareup.picasso.Utils.checkNotMain(Utils.java:71)
at com.squareup.picasso.RequestCreator.get(RequestCreator.java:206)
at ...
where I called it.
Anyone experience this or know how to use this properly with fragments?
The exception message states it pretty clear.
The .get() message is not async, hence will do the work (network, read file,... whatever) on the main thread, which you should avoid whenever possible.
Your code for setting the image to an imageView seems correct to me, though.
I think it is also possible to do the same with the mainLayout (Picasso will then set the drawable/Bitmap to the background automatically).
If I'm wrong here, have a look at the Target.class which comes with Picasso. You could load the image into a target, which must provide handlers for success and error. Within the success handler you will get the bitmap once it is loaded and can set it to your bakground.
There are a few solutions, which might work in your case.
[EDIT]
When using the get() Method provided by Picasso the loading will take place in the thread you are currently working in, which is clearly stated in the sources:
https://github.com/square/picasso/blob/master/picasso/src/main/java/com/squareup/picasso/RequestCreator.java
/** Synchronously fulfill this request. Must not be called from the main thread. */
public Bitmap get() throws IOException {[...]}
In your case I would use the Target interface, which provides callbacks when the image is loaded.
Picasso.with(getActivity()).load(R.drawable.background2).into(new Target(){
#Override
public void onBitmapLoaded(Bitmap bitmap, LoadedFrom from) {
mainLayout.setBackground(new BitmapDrawable(context.getResources(), bitmap));
}
#Override
public void onBitmapFailed(final Drawable errorDrawable) {
Log.d("TAG", "FAILED");
}
#Override
public void onPrepareLoad(final Drawable placeHolderDrawable) {
Log.d("TAG", "Prepare Load");
}
});
As you are using an internal resource here, why don't you just do the following?
mainLayout.setBackgroundResource(R.drawable.background2);
Hope this helps.
Regards
Try it
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
holder = new ViewHolder();
v = vi.inflate(Resource, null);
holder.imageview = (ImageView) v.findViewById(R.id.news_img);
holder.tvName = (TextView) v.findViewById(R.id.news_title);
holder.tvDate = (TextView) v.findViewById(R.id.news_time);
v.setTag(holder);
} else {
holder = (ViewHolder) v.getTag();
}
holder = (ViewHolder )v.getTag();
Picasso.with(context).load(postList.get(position).getThumbnail()).into(holder.imageview);
holder.tvName.setText(postList.get(position).getTitle());
holder.tvDate.setText(postList.get(position).getDate());
return v;
}
I have a GridView with 4 columns and n-rows. Each cell is simply an ImageView. My custom adapter's getView() code looks like this:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
} else {
imageView = (ImageView) convertView;
}
imageView.setLayoutParams(new GridView.LayoutParams(100, 100));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setPadding(1, 1, 1, 1);
//imageView.setAdjustViewBounds(true);
if(imageLoader != null) {
String url = randomImage();
imageView.setContentDescription(url);
imageLoader.DisplayImage(url, imageView);
}
return imageView;
}
The imageLoader will pick a random URL and in the background, go fetch it and update the ImageView accordingly. That works fine and dandy. The problem is that the resulting images seem to be using a scale type of FIT_START instead of FIT_XY. I'm explicitly setting this to FIT_XY and even set it again inside of the code that sets the imageView's drawable... still its not FIT_XY and i'm stumped. Ideas?
Edited to remove the call to setAdjustViewBounds().
So I just found the issue. I was using Romain Guy's code for creating a RoundedDrawable from a bitmap -- to get rounded corners, ala iOS, as shown here: curious-creature.org/2012/12/11/… ... when i skip the RoundedDrawable conversion, it works fine. Something in the RoundedDrawable code is what is throwing this whole thing off. I'll just need to find another method to round the corners of the imageview. I am using CENTER_CROP now thanks to #kcoppock ! :)