Read and load images from SDcard asynchronously - fail - android

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().

Related

How to make bitmap loading faster in Android?

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.

Universal Image Loader and BitmapDrawable

We have an image in B64, an we want to use that image as loading image in Universal Image Loader while a better image isn't loaded from an url. So we create a bitmap from that url in b64 and convert it into a BitmapDrawable.
The result is shown fine if I do:
imageView.setImageDrawable(bitmapDrawable)
But, on DisplayImageOptions, if I set that bitmapDrawable as image on loading, the image is never shown. I'm doing the following:
final DisplayImageOptions imageOptions = mDisplayImageOptionsDefaultBuilder.
.showImageOnLoading(bitmapDrawable)
.showImageOnFail(bitmapDrawable)
.showImageForEmptyUri(bitmapDrawable)
.build()
As you can see, I am setting the bitmap drawable not only as image when loading, but as image when fails too (as we don't want that image to change in case of error while loading the better image from an url). The result of that is that the bitmap drawable is never shown. What are we doing wrong?
UPDATE:
After debugging what was happening I've seen that the problem is not the bitmap drawable, it is supported and working fine. The problem was that I am using a default display options builder (mDisplayImageOptionsDefaultBuilder), than at some point did:
final DisplayImageOptions imageOptions = mDisplayImageOptionsDefaultBuilder.
.showImageOnLoading(loadingResource)
.showImageOnFail(errorResource)
.showImageForEmptyUri(errorResource)
.build()
So there's a bug in Universal Image Loader, because now I'm creating a display image options with:
.showImageOnLoading(bitmapDrawable)
Another "solution" is do:
final DisplayImageOptions imageOptions = mDisplayImageOptionsDefaultBuilder.
.showImageOnLoading(0)
.showImageOnLoading(loadingResource)
.showImageOnFail(errorResource)
.showImageForEmptyUri(errorResource)
.build()
But internally it stores that there's a resource stored, so my drawable is not shown but the stored resource instead. Creating a new DisplayImageOptionsBuilder worked for me, but it would be nice that if the showImageOnLoading is set with a drawable, then the old resource was automatically cleared.
Thanks in advance.
UIL only supports the following schemes:
"h t t p://site.com/image.png" // from Web
"file:///mnt/sdcard/image.png" // from SD card
"file:///mnt/sdcard/video.mp4" // from SD card (video thumbnail)
"content://media/external/images/media/13" // from content provider
"content://media/external/video/media/13" // from content provider (video thumbnail)
"assets://image.png" // from assets
"drawable://" + R.drawable.img // from drawables (non-9patch images)
Use these schemes.
Universal Image Loader also provide to use the Background functionality.Please check the below coed for it:-
Here Uri is the path of the folder image OR the URL of the image.
imageLoader.loadImage(YOUR_URL, new SimpleImageLoadingListener() {
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
super.onLoadingComplete(imageUri, view, loadedImage);
layout.setBackgroundDrawable(new BitmapDrawable(loadedImage));
}
});

WebView loading outdated local images. How to update?

I have a WebView that just displays an image from the external SD-card. This works well, however if the image is overwritten with new data, the WebView does not update the image.
This is even more curious because the WebView is created totally new in the onCreate method of the activity. Here is my code:
#Override
public void onCreate(Bundle savedInstanceState)
{
Log.d(TAG, "Creating Viewer");
super.onCreate(savedInstanceState);
Intent intent = getIntent();
Bundle extras = intent.getExtras();
String imagePath = extras.getString("imgFile");
shareImage(Uri.fromFile(new File(imagePath)));
setContentView(R.layout.viewer_test);
WebView viewer = (WebView) findViewById(R.id.imageViewer);
viewer.getSettings().setAllowFileAccess(true);
viewer.getSettings().setBuiltInZoomControls(false);
viewer.getSettings().setLoadWithOverviewMode(true);
viewer.getSettings().setUseWideViewPort(true);
viewer.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
String filename = "file://"+ imagePath;
String html = "<html><head></head><body bgcolor=\"#000000\"><center><img src=\""+ filename + "\"></center></body></html>";
viewer.loadDataWithBaseURL(null, html, "text/html","utf-8", null);
viewer.reload();
}
The image at the path that is saved in imagePath is overwritten by another activity before the path is sent to this activty. The WebView however still shows the old image data.
As you can see I already tried to set the cache mode and I tried to manually reload the WebView, with no luck unfortunately.
I also checked with a file manager and the image on the SD-card is overwritten with new data. I tried to overwrite the file multiple times, but that doesn't work either. Somehow the image data gets cached somewhere or something. How can I avoid this and load the new data every time?
(Obviously creating a new file with a different filename works fine, but I want to replace the old file.)
I'm not too familiar with Webview. but in ordinary websites you can use the querystring to emulate a unique adress, while still loading same image. this is often used on webpages on css files.
example: http://www.webpage.com/image.jpg?cachekey=23456456754
by randomizing the cachekey every time the image loaded, it is treated as a unique image and does not load from cache.
Put a randomized int or string in the end of your filename string
Random r = new Random();
int randInt = r.nextInt(8000000-1000000) + 1000000;
String query = "?cachekey=" + randInt ;
String html = "<html><head></head><body bgcolor=\"#000000\"><center><img src=\""+ filename + query "\"></center></body></html>";
I have not tested this yet. but it's an idea how to solve it.

Populate Android Gallery from image file paths?

I have some images that are saved to a directory on the Android device when the application starts--I would like to be able to display these images in a Gallery, but so far I haven't been able to do it.
I was following the sample Gallery code here, but it uses drawable resource IDs instead of file paths. I found this solution that is similar to what I'm looking for, except it uses ImageView instead of Gallery.
So the code using ImageView would look something like this:
File imgFile = new File(“/data/data/com.myproject.example/files/someImage.png”);
if(imgFile.exists()){
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
ImageView myImage = (ImageView) findViewById(R.id.imageviewTest);
myImage.setImageBitmap(myBitmap);
}
The above code works, but I'm not sure how to do it with a Gallery. I have been searching for answers and trying different things, but I'm v new to Android development and I feel like I'm in a bit over my head.
Any help is appreciated. Thank you in advance.
Basically I think you just need to put your two examples together.
Use the HelloGallery example as a start, however you want to change the code inside the getView() method of the ImageAdapter to call setImageBitmap() on the ImageView instead of setImageResource().
You will need an array/collection of file paths of images you want to load.
What you need to do is something like this:
public ImageAdapter(Context c, int itemId) {
context = c;
imgArr = GlobalStore.getItem(itemId).getPhotos();
TypedArray attr = context.obtainStyledAttributes(R.styleable.HelloGallery);
mGalleryItemBackground = attr.getResourceId(R.styleable.HelloGallery_android_galleryItemBackground, 0);
attr.recycle();
}
as you can see this is basically a copy from Gallery tutorial. In the constructor imgArr variable is loaded with an array of JPG file names. These were for example read from a database.
Then in the getView function you have something like this...
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = new ImageView(context);
String tmpStr = appContext.getFilesDir() + File.separator + "photos" + File.separator + imgArr.get(position);
Bitmap bitmap = BitmapFactory.decodeFile(tmpStr);
imageView.setImageBitmap(bitmap);
imageView.setLayoutParams(new Gallery.LayoutParams(350, 300));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setBackgroundResource(mGalleryItemBackground);
return imageView;
}
As you can see getFilesDir() gets your applications data location where it stores files, then let's imagine all photos are in "photos" directory, you build a path and attach a file name from the imgArr array. Since this is called for every photo you just use the passed position variable.
If you don't have an array of photos then maybe the way is to build it by reading the directory where you store photos, load all of the filenames in an array and then do this.
Then you do the rest on the gallery side as in the gallery tutorial.

Android Fedor's Lazy Load pass image to other activity

I m using Fedor's lazy Loader Adapter for showing images on a list view.
I want to pass the image(already downloaded) of the row which is clicked to new activity. I dont want to re download the image again.
How can this be done ?
Ref : Lazy load of images in ListView
Fedor's Code (from what i've read) uses a File Cache aswell as a Memory Cache to Cache the downloaded files...
So Simply use
FileCache fileCache = new FileCache(context);
File bmp = fileCache.getFile(url);
//convert the File object to a Bitmap object using BitmapFactory (see decodeFile() method in ImageLoader)
and
MemoryCache memCache = new MemoryCache(context);
Bitmap bmp = memCache.get(url)
Note : If both return null, then you'll have to download it again.

Categories

Resources