I am creating an app where I change the background image every time a new quote gets displayed.
I am using ImageView and those pictures are all jpg-files. They are stored in the mipmap folder under xxhdpi, because the images are too big for the drawable folder.
However when I am setting the new ImageView using:
background.setBackgroundResource(backgrounds.get(counter));
the new picture will be displayed, but it has a delay of half a second. Thats not really cool and I just want to set the new pictues smoothly.
I dont think its useful to post the whole code. The most important parts:
The references are stored in an ArrayList like this:
ArrayList<Integer> backgrounds;
Right after onCreate() I am filling the list like this:
backgrounds = new ArrayList<>();
backgrounds.add((Integer) R.mipmap.background1);
backgrounds.add((Integer) R.mipmap.background2);
backgrounds.add((Integer) R.mipmap.background3);
backgrounds.add((Integer) R.mipmap.background4);
The pictures have a size between 100KB and 7MB.
Can anyone tell me why the loading is slow and how to improve it? Also, is it right to put those in the xxhdpi folder under mipmap?
Thanks for every answer!
There are some valid comments under your question, but I'll add mine as an answer :)
Decreasing image sizes are crucial - using JPG instead of PNG and decreasing resolution will save you some time and device battery.
Try placing those images under the drawable-nodpi folder - this will save you from unneeded image scaling. I presume that you only have one instance of the background in your app.
There is not too much you can do to improve the background setting speed, especially when the images are already baked inside your APK.
It is working properly now. The images were way too big and I reduced the size of them from 2-3MB to ~25KB. They still look good and load properly.
Related
I implemented a RecyclerView in one of my Activities.
I use a customized RecyclerView adapter to load data from a SQLite Database (using Room and LiveData-structure) and display it in the view.
All of the rows have a large ImageView where I want to show a Drawable (just a .png). To do that I first tried to use the approach written on the official Android Developers site but it did not work well for me.
Therefore I am trying to use Glide as a library recommended by Google.
I have 16 drawables in my project. They all have a scaling between 800x800 and 1920x1080 pixels.
In my adapter I load the data from my database and based on the drawable id, the image as well (so there is no image data stored in the database; I did this previously).
Unfortunately my App cannot handle that amount of image cache which leads to an OutOfMemoryError exception. That's why I used
android:largeHeap = "true"
in my Android Manifest.
I know this is not a good solution and I also know that there has to be a way to use less memory for such a small amount of pictures.
In Glide I use
GlideApp
.load(R.drawable.my_drawable)
.fitcenter()
.into(myImageView);
But unfortunately the image does not get shrinked or smaller. I thought that Glide can scale the image based on the size of the ImageView, screen size and so on.
What am I doing wrong? Is there a better way to use less memory without fixed scaling so that my pictures not become ugly?
EDIT:
I first stored my images in the basic "drawable" folder in my project structure (copy and paste).
My second approach was the gimp-android-xdpi addon which exports images or icons for any android density (mdpi, hdpi, xhdpi etc.). But this did not help either.
call override(horizontalSize, verticalSize).
This will resize the image before displaying it in the ImageView.
So my app needs to have a maximum of 50 images on the screen at the same time in a FrameView, they need to be placed on top of a base image. If I put these images into drawable, the app crashes after a few images are placed with an OutOfMemoryError. But it works when I put the images in mipmap for some reason without crashing. So I placed them all into the mipmap folders. The images are VERY small too, the largest among them is 2.2 KB and the smallest is 398 bytes. The app works as intended, but performance is horrible after you place a few images onto the screen. The first few images will load quickly, but as you continue to place images onto the screen it gets progressively slower to the point where it may take multiple seconds to place the image onto the screen. I'm just using an ArrayList to put all the Drawables in, and then another ArrayList to put all the ImageViews and I load them into the view within my onTouchListener. Here's an idea. The index is used to decide which image is to be inserted:
drawableOverlays.set(index, getResources().getDrawable(R.mipmap.exampleImage, null));
imageOverlays.get(index).setImageDrawable(drawableOverlays.get(index));
frame.addView(imageOverlays.get(index));
I've also tried using Glide and Picasso and those loaded in even slower. Am I approaching this wrong? Is there a more efficient way to accomplish this?
The best way is create a RecyclerView with ImageViews as items, and then load the images with Glide or Picasso, any of those libraries will give you the best performance
I am working on a very simple app that shows one jpg, which is scrollable on vertical axis.
I would like this image to be very large(20000x1000 px), however, when I try to run the app on my device, it says that "bitmap too large to be uploaded into a texture".
Is there a way to display the image of such size in an android app?
If not, would it be possible to divide the image into segments, and after I scrolled to the bottom
of one segment, I would proceed to another?
To quote the answer for your question here:
All rendering is based on OpenGL, so no you can't go over this limit.
Note that this would take a huge amount of memory. With such big
images, if you want to zoom in out, and in a mobile environement with
heavy memory constraints, you should setup a system similar to what
you see in google maps for example. With the image split in several
pieces, and several definitions.
You could split the images into let's say 128x128 chunks. Add them to an array, and loop the array to create and fill an ImageView with the image that is currently served.
some pseudocode would be: (excuse me, I've been programming a PHP application the past few days)
Private BitMap[] imageArray = {your bitmaps from internal or external storage};
For(BitMap bm in imageArray) {
// create a new image view here, use the correct layout params or use a parrent grid view.
imageView.setBitMap(bm)
}
now once again, I am 0% sure about that pseudo code, but it should help you along.
I need some help,
I am creating an app, and want it to run faster I mean when the app is started first it shows a blank white screen for o 1-2 seconds and then loads images. I have a layout background image, and 4 imageviews which are clickable and take you to the next activity. I read somewhere i should use threads to load images and it will load them on a separate thread faster, but i have some problem using it.
So here are the problems and android studio explanations:
Thread thread=new Thread(
public void run(){
ImageView tipka=(ImageView)findViewById(R.id.tipkaproba);
tipka.setImageResource(R.drawable.instructions);
LinearLayout asd=(LinearLayout)findViewById(R.id.layoutproba);
asd.setBackgroundResource(R.drawable.backfround123);
}
).start();
Now the android studio says:
After
"Thread(" )expected
Before
"public void run(){"
; expected
On ").start();"
Invalid method declaration; return type required, Missing method body, or declare abstract.
Now i would like to know:
Does this speed up loading images, ( if not how to do it then)
How to fix my errors.
Thanks anyway !
Do all images fit in the screen?! If users need to scroll to view other images why load all of them at once? Use a grid view with adapter to load the image. In this way when the app start only images on the screen will be loaded and then when the user scrolls other images show up!
another thing you can do is to have 2 version of each image. one low quality with small size that loads first and one for high quality image. that will load latter. You can also calculate the base color for each image (use open source code or do it manually). then set the background image of iamgeview to this color. So when the image finally loads on the screen. The difference is not as dramatic as it was before.
If you want to use thread try AsyncTask first. Using AsyncTask is simpler than defining thread yourself.
Try to decrease the size of your images! If you be able to do this. it works better than any other trick! It's mobile, you don't have to show supper high quality images. users don't even notice most of the time
You probably took care of this but it worth mentioning that you need to provide different images for different screen densities and it's critical for performance as well as quality.
I'm creating somekind of 2D image editor in Android and I have the big problem of big files don't fit in memory.
I need to zoom in/out the image put some shapes and then save it.
My question is:
How can I load the image and save it without getting out of memory?
I've been reading about bitmapregiondecode and the sample technic but there's must be another solution. How can I save the image if I always use regiondecode?
The images need good detail quality because it's architectural images... and the lines must be well defined.
I'm new to this, help me please.
Note two things while dealing with images:
tempBitmap = Bitmap.createBitmap(bit);
clone the bitmap which you are using for zoom and other operations but wont use the original because it looses its clarity when you save;
when done with bitmap give
bit.recycle();
to release the memory space