So I am displaying video files from specific folder when the folder is selected but in the video list I am showing file name with the video thumbnail and that's where the problem starts i am using this way to get the thumb
Bitmap bmThumbnail = ThumbnailUtils.
extractThumbnail(ThumbnailUtils.createVideoThumbnail(info.getFilename(),
MediaStore.Video.Thumbnails.MINI_KIND), 60, 60);
if(bmThumbnail != null) {
imageView.setImageBitmap(bmThumbnail);}
and even if I don't set the bitmap or not the process is taking way too much time to open the new fragment whereas just displaying the name is smooth if I call the following bitmap it takes around 6-7 sec to display the list. The following thing are happening in the adapter as I test the app in adapter then recycler view
so I would like to know what is the best way to do it .
For using image loader i need the url which is not there as i am getting the album art using the file url but it will not produce the album art url directly.
Dealing with images and videos like that takes time. Particularly when dealing with a large group of them. It's unlikely you can speed up the operation but you can make it so your application doesn't have to wait for it by sending it to the background. I recommend Kotlin coroutines if you are up for converting to Kotlin. Otherwise I recommend making a thumbnail work manager
public class VideoThumbnailWorker extends Worker {
}
Related
What is my Problem (KISS)?
After showing the 3rd Image in Detail my App crashes cause OutOfMemory
Background information about my App:
I made an offline Supermarket. All products are shown in a ListView.
All Images I use are stored as String (Uri from every Image) in a sqlite Database by SugarORM.
The ListView element got a ArrayAdapter where the Information for each Item in the ListView is set.
Like this:
ImageView imageView = (ImageView) rowView.findViewById(R.id.productimage);
Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
imageView.setImageURI(productList.get(position).getPictureUri());
handler.removeCallbacks(this);
}
});
My Intention was, to load the Images in the Background to Click on it, even before the Image is loaded (But it did'nt work for me :/ The Image is Shown, but I cant click on any other View Element while Loading the Image).
The "getPictureUri" gets the URI from the Picture that the Admin has choosen for the product with the following Code:
Intent pickPhoto = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickPhoto,1);
AndroidManifest.xml
android:hardwareAccelerated="false"
android:largeHeap="true"
I extend only from "AppCompatActivity" (Needed for Toolbar). Meaning of this: I don't use "Activity" even once.
Could anyone give me a good advice, how to clear the cached Images (I think this might be the Problem) and besides, maybe one of you got the Time to help me with my "Image Async Loading while you are able to move freely in your app" Problem.
Using setImageUri() is rather intensive on memory, especially when trying to load large bitmaps from a local resource. Instead, use tried and true solutions like Picasso or Glide for any/all image loading tasks. The libraries will work offline, can definitely load images from URIs pointing to a local resource and would most likely solve all your memory issues with image loading.
I am trying to make a recyclerview with gifs. Everything shows perfectly but fresco do not cache gifs. After scroll recycler down and scroll up again, gifs are loading once again. I supposed they should be cached and loaded a bit quicker. Previously I used ION library. Loading was quicker and did not have cache problem. I had to change lib because, it has some problem with gif decoding, described here. Current solution looks like that:
//for default initial in application class
Fresco.initialize(this);
//I have also tried to change DiskCacheConfig and ImagePipelineConfig params.
//Without any positive result
//for recyclerview on onBindViewHolder
GenericDraweeHierarchy hierarchy = holder.draweeView.getHierarchy();
Uri uri = Uri.parse(path);
hierarchy.setPlaceholderImage(R.drawable.img_bg);
Logger.e(check(uri) + " " + uri.toString());
DraweeController controller = Fresco.newDraweeControllerBuilder().setUri(uri)
.setAutoPlayAnimations(true).build();
holder.draweeView.setController(controller);
//for method which show cached uri images in imagepipeline
public static boolean check(Uri uri) {
ImagePipeline imagePipeline = Fresco.getImagePipeline();
return imagePipeline.isInBitmapMemoryCache(uri);
}
//... all the time log shows "false + gif url"
I have not seen any information about not caching animated images. There is information about not supported image postprocessing for animations, but it's everything about that. How to correctly cache gifs?
edit:
It looks like fresco cache animations, because below method return true for reloaded gifs.
public static boolean isImageDownloaded(Uri loadUri) {
if (loadUri == null) {
return false;
}
CacheKey cacheKey = DefaultCacheKeyFactory.getInstance()
.getEncodedCacheKey(ImageRequest.fromUri(loadUri));
return ImagePipelineFactory.getInstance().getMainDiskStorageCache().hasKey(cacheKey)
|| ImagePipelineFactory.getInstance().getSmallImageDiskStorageCache()
.hasKey(cacheKey);
}
Just to make things a bit more clear, Fresco has 3 levels of cache:
DiskCache - Keeps image files in their original format. (To be
precise, if on an Android version that doesn't fully support webp
images, they may be transcoded to other format before storing.)
EncodedMemoryCache - In-memory cache of images in their original encoded format. (Image is kept as a byte-array of the original bytes
as they are stored on disk + some additional metadata.)
BitmapMemoryCache - In-memory cache consisting mostly of Android Bitmaps. Bitmaps are decoded images and each pixel occupies 32bits
which is significantly more than what it takes when encoded.
The trade-off is obviously space vs time. Available memory is limited and if the image is not in the bitmap cache, it will have to be decoded again. Furthermore, if it is not in the encoded memory cache either, it will have to be read from the disk which also can be slow.
Now back to the animated images. This is a known limitation. Animated images are not cached in their decoded form because that would exhaust the bitmap cache (just multiply the num_frames * width * height * 32bpp) and a single animated image can possibly evict every other image in the cache. Instead they are decoded on demand and only a couple of frames that are about to be displayed next are kept in a short-lived cache.
We have some plans to improve animations, although I cannot provide any time estimates.
I was facing the same issue, it appears that Fresco is correctly caching the gif images, but in fact it's taking time to decode and play the animation each time you scroll through the RecyclerView or any other view you're using.
However if you use a gif image without animation, the gif image doesn't "reload" when scrolling through the view.
Since I have control over the images displayed inside my app. I am creating 2 versions of the gif images on my server, the first without animation to display inside the RecyclerView/ListView and the other to display inside the "Media viewer" activity, when the user clicks on an item in the list.
Fresco, they mainly focused low size gifs. I tried with low size gifs in recycleview, caching working perfectly. If you use high resolution gifs, they need high memory consumption for decode and caching. may be surpass heap size. so they are decoded on demand, and only a couple of frames (those about to be displayed) get cached.
It is possible to configure fresco to display the first frame as soon as it is available (without decode whole frame) and cache the static first frame easily.
ImageDecodeOptionsBuilder b = new ImageDecodeOptionsBuilder();
b.setForceStaticImage(true);
ImageDecodeOptions imageDecodeOptions=new ImageDecodeOptions(b);
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(animatedGifUri).setImageDecodeOptions(imageDecodeOptions).setLocalThumbnailPreviewsEnabled(true).build();
orI have an app that is consistently downloading large images from a parse back-end. In android you can download the images as streams using their URI's and set a specific dimension size to the bitmap that I want to download. Usually this is done using the BitmapFactory libraries and allows me to download a bitmap that's of a scaled down size, saving my app from long loading times. Is there an equivalency to this method on the IOS platform? This is what I am currently doing, but when I download 15 full sized images I get a large amount of load time:
//where photoQuery is a Parse.com database query that returns the photo as the first object
PFObject *photoObject = [photoQuery getFirstObject];
PFFile *photoFile = (PFFile *)[photoObject objectForKey:#"fullSizedImage"];
UIImage *fullImage = [UIImage imageWithData:photoFile.getData];
Does IOS support something similar to BitmapFactory or this common android design pattern?
PFFile has a method called – getDataInBackgroundWithBlock:. Which can be used like this:
[photoFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if(!error) {
[imageView setImage:[UIImage imageWithData:data];
}
}
Or you can use another method called - getDataStreamInBackgroundWithBlock:. It is similar as the one above. The difference is the first parameter of the block is a NSInputStream
PFImageView should help you load these images a synchronously. You may try thumbnailing images using Cloud Code.
I'm trying to implement a gallery and I have a GridView that displays all the images (thumbnail) in the camera folder. To get the thumbnails, I basically get their IDs using:
final String[] PROJECTION =
new String[] {MediaStore.Images.Media._ID};
Cursor pictureCursor = getActivity().getContentResolver().query(Images.Media.EXTERNAL_CONTENT_URI,
PROJECTION, null, null, MediaStore.Images.Media._ID);
ArrayList<Integer> ids = new ArrayList<Integer>();
int idIndex = pictureCursor.getColumnIndex(MediaStore.Images.Media._ID);
while (pictureCursor.moveToNext()) {
ids.add(pictureCursor.getInt(idIndex));
}
And to read the thumbnails, I'm using
Bitmap bitmap = MediaStore.Images.Thumbnails.getThumbnail(content_resolver, ids.get(position), MediaStore.Images.Thumbnails.MICRO_KIND, null);
on an AsyncTask as specified in http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
But as I'm comparing the load times between my app vs. Android's native gallery app, I'm seeing that the gallery app loads thumbnails MUCH faster than my app, all the while having better image quality than my Thumbnails.MICRO_KIND. Is there a faster way to load thumbnails than to use MediaStore.Images.Thumbnails.getThumbnail() function? because obviously the gallery app loads thumbnails much faster.
NOTE: this is when the app is initially opened, before cache comes into play. After my cache stores images, then load time is near instant. So, not a cache problem.
EDIT:
I thought I should clarify. It's not that my UI is getting locked or my app is slow, since I'm already using an AsyncTask to read my images off the UI thread. What I'm asking is if the function MediaStore.Images.Thumbnails.getThumbnail() is the fastest way to load thumbnails already stored on the phone?
Use Universal Image Loader it takes care of your issues which most likely stems from you loading the wrong sizes and/or not caching the results.
I'm working on a project that needs to use a large image as a map. The image is about 95MB and has a resolution of 12100 x 8000 pixels.
I don't need the whole image at once, I just need a detail of 1000 x 1000 Pixel (it's not always the same detail, just grabbing the same part is not a solution I can use). So I can't just sample it down with the BitmapOptions.
I looked around and found the idea to create a FileInputStream (the image is on the SD-Card) and then I can just load the detail with decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts). That way I wouldn't load the whole thing into the memory. I tried it, but it's just crashing when I try to load the image. Here's my code:
FileInputStream stream = null;
try {
stream = new FileInputStream(path);
} catch(Exception e) {
Log.e("inputstream",e.toString());
}
Rect rect = new Rect(a,b,c,d);
return BitmapFactory.decodeStream(stream, rect, null);
When I try to load the image, the activity closes and LogCat tells me java.lang.outOfMemoryError. Why does it crash? I thought with the stream it should work on the image "on-the-fly", but the only explication I have for the Error is the it trys to load the hole image into the memory. Does anybody have an idea how I can load the detail out of the image, or why this idea doesn't work?
It crashed because all these 95M are sucked into memory for processing. This call will not ignore parts of the stream - it will put the whole thing to memory and then try to manipulate it. The only solution you can have is to have some sort of server side code that does the same sort of manipulation or if you don't want to do it on server - provide thumbnails of your large image. And I would strongly advise against pulling whole 95M at any time anyways
Does BitmapRegionDecoder not help (I realise its level 10)?