i'm building a file explorer application, and i'm trying to load large amount of images (more then 5000...), i'm trying to use picasso but its still slow so i'm trying to load a Thumbimage with picasso and not the whole image file..
....
ImageItem item = data.get(position);
ImageView imageView = holder.image;
Bitmap ThumbImage = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(item.getImage().getPath()), 100, 100);
Picasso.with (context) .load (ThumbImage ) .into (imageView); /*/ doesnt work.. cant load ThumbImage with Picasso
Picasso.with (context) .load (item.getImage()) .into (imageView); //work, but too slow
i cant figure out how can i load Thumbimage into ImageView with Picasso.. there is any why to do that? another way to load faster my images?
First I would recommend using RecyclerView instead of a GridView, considering it handles a lot of the memory management for you. Instead of having to load all of the images at once (or manage it yourself), it will only load the images that fit on the screen. And you can use a GridLayoutManager to have it appear just as it would in a GridView.
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler);
recyclerView.setLayoutManager(new GridLayoutManager(context, 4);
recyclerView.setAdapter(new MyRecyclerViewAdapter(context, data);
Also, let Picasso handle converting the image for you, this way you do not need to use ThumbnailUtils. Picasso handles image resizing and memory management with the resize() function:
String uri = data.get(position);
Picasso.with(context).load(new File(uri)).resize(100, 100)
.centerCrop().into(imageView)
You can do this in the onBindViewHolder() method of the RecyclerView.Adapter so that each image will only be loaded when the View has to be shown.
I am not sure how you are obtaining the images currently, but if you do not know how to obtain the URI of the image, this should work:
String[] projection = {"*"};
List<String> data = new ArrayList<>();
Cursor cursor = context.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, null);
if(cursor.moveToFirst()) {
do {
data.add(cursor.getString(cursor
.getColumnIndex(MediaStore.Images.Media.DATA)));
} while(cursor.moveToNext());
}
I do not know if this will fix the problem you have with Picasso not loading the images, but if it does not post a stack trace and we can try to figure that out.
Related
I have a code that loads the thumbnail of the image and feeds it to glide. Then glide will load in the holder. but, As I am loading the thumbnail it returns a bitmap. SO, I am passing bitmap to glide. But, this takes nearly 30sec for initial loading. I mean in the gallery there are lots of photos. So, when the gallery is opened it won't show images for 30sec at all. And then it will show the bitmaps.
on the other hand, if I use URI to feed to glide it will load it immediately. But, Images are being loaded in recycler view. So, only some images will be loaded at the time.
After some images are loaded. When we swipe up and see other photos loading speed then obviously bitmap fed images are loaded way faster than URI fed images. But, bitmap takes 30sec of initial loading time.
Is there any way to make this bitmap load faster?
...
while (cursor.moveToNext()) {
Log.d("FetchImages(): ", " Started");
Bitmap thumbBitmap = null;
int _thumpId = cursor.getInt(column_index_data);
Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, _thumpId);
Size thumbSize = new Size(150, 150);
try {
thumbBitmap = getApplicationContext().getContentResolver().loadThumbnail(uri1, thumbSize, null);
} catch (IOException e) {e.printStackTrace();}
ImageModel ImageModel = new ImageModel();
ImageModel.setBitmap(thumbBitmap);
arrayList.add(ImageModel);
}
Log.d("FetchImages(): ", " Ended");
runOnUiThread(() -> {
Adapter Adapter = new Adapter(getApplicationContext(), arrayList, MainActivity.this);
recyclerView.setAdapter(Adapter);
cursor.close();
Log.d("FetchImages(): ", " RecyclerView Adapter attached");
});
...
Glide .with(context) .load(url).apply(new RequestOptions().override(150, 150)) //for resizing .into(imageView);
No need to create bitmap it takes more computation .
Glide is more faster and efficient.
And still if you want to use bitmap then use AsycTask so it wont block main thread and program will not hang.
I want to show a video thumbnail in an ImageView from a video path on storage. Is there a function that takes a video path and returns a bitmap of a thumbnail? I get the video path by this code:
public ArrayList<String> getAllMedia() {
HashSet<String> videoItemHashSet = new HashSet<>();
String[] projection = {MediaStore.Video.VideoColumns.DATA, MediaStore.Video.Media.DISPLAY_NAME};
Cursor cursor = getContext().getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projection, null, null, null);
try {
cursor.moveToFirst();
do {
videoItemHashSet.add((cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA))));
} while(cursor.moveToNext());
cursor.close();
} catch(Exception e) {
e.printStackTrace();
}
ArrayList<String> downloadedList = new ArrayList<>(videoItemHashSet);
return downloadedList;
}
It is the default way to create a thumbnail.
For Mini Kind
Bitmap thumb;
//MINI_KIND, size: 512 x 384 thumbnail
thumb = ThumbnailUtils.createVideoThumbnail(filePath, MediaStore.Video.Thumbnails.MINI_KIND);
img_tumbnail.setImageBitmap(thumb);
For Micro Kind
Bitmap thumb;
//MICRO_KIND, size: 96 x 96 thumbnail
thumb= ThumbnailUtils.createVideoThumbnail(filePath, Thumbnails.MICRO_KIND);
img_tumbnail.setImageBitmap(thumb);
Also, you can use Glide for Url as well as Video path of Device.
Glide.with(context).with(this)
.asBitmap()
.load(videoFilePath) // or URI/path
.into(imgView); //imageview to set thumbnail to
also, you can resize thumbnail by using .override(50,50) with Glide.
Use Glide lib
to show thumbnail from local storage
String filePath = "/storage/emulated/0/Pictures/example_video.mp4";
GlideApp
.with(context)
.asBitmap()
.load(Uri.fromFile(new File(filePath)))
.into(imageViewGifAsBitmap);
You can use ThumbnailUtils to load video thumb in 3 format:
MINI_KIND : Good for media detail view
FULL_SCREEN_KIND : Good for header
MICRO_KIND : Good for recycleView
Ex:
holder.videoThumb.setImageBitmap(ThumbnailUtils.createVideoThumbnail(getItem(position).videoURL, MediaStore.Images.Thumbnails.MICRO_KIND))
The biggest drawback is that ThumbnailUtils operate on UI thread so if you try to use this method in a recycleView then it gone make your app skip frames. Your RecycleView will have laggy scroll and if you have more than 7 items then your app will start throwing ANR.
That means you need to create AsyncTask or Threads which again might lead to memory leaks.
Conclusion; Glide is better in loading video thumbs.
Here DiskCacheStrategy.RESULT is important parameter which worked for me and give a smooth fast scroll in recycle view.
Glide.with(context).load(getItem(position).videoURL)
.asBitmap()
.placeholder(R.drawable.app_icon)
.centerCrop()
.diskCacheStrategy(DiskCacheStrategy.RESULT)
.into(holder.videoThumb)
I have 3rd method to set thumbnail of image/video.
Hope it will help you.
1) ThumbnailUtils --> Effective but Slow
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(thumbPath, MediaStore.Video.Thumbnails.MINI_KIND);
holder.ivThumb.setImageBitmap(thumb);
2) FFmpegMediaMetadataRetriever --> Very Effective but Slow
FFmpegMediaMetadataRetriever retriever = new FFmpegMediaMetadataRetriever();
try {
retriever.setDataSource(thumbPath);
thumb.setImageBitmap(retriever.getFrameAtTime(0));
} catch (Exception ex) {
// Assume this is a corrupt file
}
3) Glide --> Effective and Fast
RequestOptions options = new RequestOptions()
.centerCrop()
.placeholder(android.R.drawable.stat_notify_error)
.error(android.R.drawable.stat_notify_error);
Glide.with(context)
.load(thumPath)
.apply(options)
.into(thumb);
If anyone is looking for a Kotlin version. You can try this extension function.
It is using coil.
/**
* https://github.com/coil-kt/coil/issues/413
*/
fun ImageView.setThumbnail(uri: Uri, frameMillis: Long = 2000) {
val imageLoader = ImageLoader.Builder(context)
.componentRegistry {
add(VideoFrameFileFetcher(context))
add(VideoFrameUriFetcher(context))
}.build()
val request = ImageRequest.Builder(context)
.data(uri)
.videoFrameMillis(frameMillis)
.target(this)
.fetcher(VideoFrameUriFetcher(context))
.build()
findViewTreeLifecycleOwner()?.lifecycleScope?.launch(Dispatchers.Main) {
imageLoader.execute(request)
}
}
In some devices not working for me without FileDescriptorBitmapDecoder
So I used following code with FileDescriptorBitmapDecoder
public static void loadLocalVideoThumbanail(Context context, String path, final ImageView imageView) {
try {
if (path == null || path.isEmpty())
return;
BitmapPool bitmapPool = Glide.get(context).getBitmapPool();
int microSecond = 1000000;// 1st second as an example
VideoBitmapDecoder videoBitmapDecoder = new VideoBitmapDecoder(microSecond);
FileDescriptorBitmapDecoder fileDescriptorBitmapDecoder = new FileDescriptorBitmapDecoder(videoBitmapDecoder, bitmapPool, DecodeFormat.PREFER_ARGB_8888);
Glide.with(context).load(path).asBitmap().thumbnail(0.6f)
.diskCacheStrategy(DiskCacheStrategy.RESULT)
.dontAnimate()
.videoDecoder(fileDescriptorBitmapDecoder)
.override(200,200)
.into(imageView);
} catch (Exception e) {
MyLog.e(TAG, "LoadImage: ", e);
}
}
I want create image gallery with RecyclerView where use images from phone. I didn't find any RecyclerView adapter which fill image with File type. Is it possible?
For basic functionality of RecyclerView adapters: http://guides.codepath.com/android/Using-the-RecyclerView
In your onBindViewHolder, you can get your image like this:
String path = Environment.getExternalStorageDirectory() + "/myImage.jpg";
Bitmap bitmap = BitmapFactory.decodeFile(path);
(more info on getting images from external storage)
and use it with an ImageView or something similar.
It's works
#Override
public void onBindViewHolder(RecyclerViewHolders holder, int position) {
holder.countryName.setText("Img");
Bitmap bitmap = BitmapFactory.decodeFile(newList.get(position));
holder.countryPhoto.setImageBitmap(bitmap);
}
I have many images that I want to preload and use later on. I want to make it so that I can load an image, hide it, and then load it again whenever I want.
https://github.com/bumptech/glide/wiki/Loading-and-Caching-on-Background-Threads#into
I have tried following this, but it doesn't work.
Here is my code:
private void loadImage() throws ExecutionException, InterruptedException {
FutureTarget<File> future = Glide.with(this)
.load(R.drawable.image1)
.downloadOnly(500, 500);
File cacheFile = future.get();
Bitmap myBitmap = Glide.with(this)
.load(cacheFile)
.asBitmap()
.centerCrop()
.into(500, 500)
.get();
Glide.with(this).load(myBitmap).into(image_name);
}
I tried using Picasso because I read that this can easily be done in it, but the images take really long to load in Picasso.
I'd like to load image which is on SDCARD in folder to imageView of my cell in listView. I've tried different solutions but each of them fails. When I load images normally as it is in every base tutorial everything works. I've observed that, my application slows down when it has to load many images. Images are taken from photo camera of device. I'd like to load each of them asynchronously to avoid UI slow reaction. I've tried to use Thread, Asynctask but each of them throws error: "Only the oryginal thread that created a view hierarchy can touch its views". How to load images to avoid speed problems? SDImageLoader is a class which is possible to get from GITHUB. What I've tried is a standard code but is slows:
In a getView method in ListAdapter:
File imageFile = new File(Options.PATH_TO_FOLDER_PHOTOS_OF_APP + "test.png");
String imageFileString = Options.PATH_TO_FOLDER_PHOTOS_OF_APP + "test.png";
// "test.png" is a test file. Each cell will have different name of file to load.
if(imageFile.exists())
{
Bitmap myBitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath());
image.setImageBitmap(myBitmap);
// final SDImageLoader loader = new SDImageLoader(context);
// new SDImageLoader().load(imageFileString, image);
//UrlImageViewHelper.setUrlDrawable(image, url);
}
else
{
final SDImageLoader loader = new SDImageLoader();
Resources resources = context.getResources();
int resurceId;
resurceId = resources.getIdentifier("bad", "drawable",context.getPackageName());
loader.load(imageFileString, image);
image.setImageResource(resurceId);
}
Have you tried to refresh your project after adding an external library to your project? It doesn't matter with the fragment. You send exact context to the List Adapter - which should be fragment.this.getActivity().