I have problem with shadow of ActionBar it doesn't show when i add this : android:hardwareAccelerated="false" in my AndroidManifest.xml but when i delete this line it show shadow well and show other problem in my Activity which has Recycleview with items of images(small size images) it be very slow when i scroll the Recycleview, but when add android:hardwareAccelerated="false" scrolling be normal.
Please anyone could help me with this?
According to google documentation
Beginning in Android 3.0 (API level 11), the Android 2D rendering pipeline supports hardware acceleration, meaning that all drawing operations that are performed on a View's canvas use the GPU. Because of the increased resources required to enable hardware acceleration, your app will consume more RAM.
So i guess writing android:hardwareAccelerated="false" stops the app from making use of the GPU, hence reducing GPU rendered effects like shadows.
A couple of things that you can do is
Add the android:hardwareAccelerated="false" for the specific activity where you want to load heavy images. Click here to check that.
Try and reduce the size of the images that you are loading. This can be done using the following two functions as documented in the developer documentation for android. Click here for the complete documentation.
Function 1
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
Function 2
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
Set Image in ImageView
mImageView.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
Also refer this link for a another reference about Image Resizing.
Related
I got some OutOfMemory crashes when switching image in ImageSwitcher, it's very rare but it happens sometimes (never to me, otherway I would be able to debug it haha).
I only have 5 images (PNG) and each of them has something between 10-60kb, so to be honest I am quite surprised. Here is code:
frameImages = new int[]{R.drawable.f_0, R.drawable.f_1, R.drawable.f_2, R.drawable.f_3, R.drawable.f_4};
...
public void switchImage() {
int frame = getFrame();
int image = frameImages[frame];
// imageSwitcher.startAnimation(getAnimation());
if (frame == 0)
startYAxisRotation(imageSwitcher, 400);
imageSwitcher.setImageResource(image); //CRASHES HERE
}
Am I doing something wrong?
Stacktrace:
java.lang.OutOfMemoryError:
at android.graphics.BitmapFactory.nativeDecodeAsset(BitmapFactory.java:0)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:677)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:507)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:872)
at android.content.res.Resources.loadDrawable(Resources.java:3022)
at android.content.res.Resources.getDrawable(Resources.java:1586)
at android.widget.ImageView.resolveUri(ImageView.java:648)
at android.widget.ImageView.setImageResource(ImageView.java:377)
at android.widget.ImageSwitcher.setImageResource(ImageSwitcher.java:41)
at com.myapp.MainActivity$5.switchImage(MainActivity.java:143)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5293)
at java.lang.reflect.Method.invokeNative(Method.java:0)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
at dalvik.system.NativeStart.main(NativeStart.java:0)
With the below code, you can be able to reduce the resolution of the Bitmap prior to loading it in the ImageSwitcher.
public void switchImages(){
//Create a Bitmap with the resolution based on the view size.
//getWidth and getHeight will not work until the layout as finished,
//if you need to show an image when the Activity is created you need
//to follow this link: https://stackoverflow.com/a/6569243/2910520
Bitmap smallBitmap = decodeSampledBitmapFromResource(getResources(), yourDrawableId,
imageSwitcher.getWidth(), imageSwitcher.getHeight())
//use a drawable, because you can create it from a custom Bitmap
BitmapDrawable drawable = new BitmapDrawable(getResources(), smallBitmap);
imageSwitcher.setImageDrawable(drawable);
}
These two methods below were copied from developer site here
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
unfortunately if None of the Above works, then Add this to your Manifest file. Inside application tag
<application
android:largeHeap="true"
for details
Strange out of memory issue while loading an image to a Bitmap object
Add android:largeHeap="true"
in your Manifest file.
hope solve your issue.
So, solution was to decrease resolution of images (I did manual resizing in photoshop). From 620x1080 to 800x460 and everything works fine.
Conclusion: Image size it's not that important - image resolution is.
PS: MatPag should also be teoretically correct, it's practically same what I did - except he is doing that in code, I did it manually in photoshop by myself. But I think doing that manually is better IMHO.
I have bigs problems with the decodeSampleBitmap code and the final size of my images. I have my drawables in nodpi drawables folder for not multiply the same drawable in diferents folders with diferents sizes, and i resize after aply my decodeSampleBitmap.
I have this code for load a bitmap:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
The code i can get at the documentation. Ok i think this is for load images more eficiently but i have memory problems. I try explain this problem.
1-I want load a png, 2037x1440 pixels, 12.6kb.
2-I aply my code and load a png with 2037x1440 pixels and 11,73 MB. I dont undurstand what i'm doing wrong. Why android multiply for 1000 the size of my drawables?
10-12 12:06:07.842 12405-12822/com.viridesoft.kiseichuu V/control4: width=2037 height=1440 size=11733120
Edit: if i load the drawable with BitmapFactory.decodeResource the size is the same, 11733120.
The old question should be changed. I understand i cant reduce more my image size and i continue with the same problem.
I load a lot of images for create a dinamical background and charge all the characters(my player and zombies), in total until 111 bitmaps of 25%px x 10%px of the screen size and until 30 bitmaps of the 100% screen size. I load all this bitmaps in a loader activity and save for the later use in the game. I have a good quality of images and a drawable-nodpi folder with a lot of images for the best android resolution i see. My game run fluid in some devices (bq aquaris, nexus 5, etc) but is continually cleaning the memory and run slow in others (some tablets, some mid-range devices, etc )
The new question is:
How i can load eficiently a lot of images for a fluid game experiencie?
Getting OOM big time in my game UI (I'm only targeting kitkat and above)
I noticed that if I use a android:src="#drawable/empty_screen_game_setup" in XML, leaving and entering the activity always has the same memory usage.
If I DON'T set src in XML, but rather use the following google code, leaving and entering the activity makes the memory usage climb like crazy. This is a test app with no other code because I'm trying to understand the OOM. So much conflicting info out there!!
Is it better to just use src in XML memory-wise? I was hoping to use one set of ressources in no-dpi and scale them to size with bitmapfactory given the screen size but I guess that's not best :(
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
And in onCreate:
glass = (ImageView) findViewById(R.id.imageViewGlass);
glass.setImageBitmap( decodeSampledBitmapFromResource(getResources(), R.drawable.empty_screen_game_setup, 500, 300) );
I have a set of image files stored in internal storage, each file size is about 750 KB. I need to create a 360 degrees animation like with this images, so, I load each image in a list, while I'm doing this process an out of memory exception appears.
I have been reading about bitmap processing on Android, but in this case is not about resize bitmap dimensions, the dimensions are OK (600, 450) because its a tablet application, is about image quality I think.
Is there a way to reduce the memory each bitmap takes?.
It is not possible without reducing image dimensions.
All images with the same dimensions require same amount of RAM, regardless it size on disk and compression. Graphics adapter don't understand different image types and compression and it needs only uncompressed raw array of pixels. And it size is constant
For example
size = width * height * 4; // for RGBA_8888
size = width * height * 2; // for RGB_565
So you should reduce image dimensions or use caching on the disk and remove bitmaps from the RAM that are currently invisible and reload from disk when needed.
There is a great resource on how to do this here:
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
Basically you need to load a bitmap at a different resolution using these two functions:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
Then set the image as follows:
imageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(),
R.drawable.my_image_resource,
imageView.getWidth(),
imageView.getHeight()));
Hope that helps!
I'm working on an android app, and in resources folder I have an image which is 8000x400px resolution. It is a .png that I'm using at my Sprite class to simulate the movement of an animal.
I display the portion of the png using drawBitmap() in my SurfaceView class.
Sprite class, SurfaceView and all the elements work perfect, but when working with that large images it doesnt display anything.
To fix this problem I would like to know.
What is the limit of maximum resolution of a Bitmap allowed in
Android?
How could I display in onDraw() a Sprite with that size?
Concerning the displaying / loading of Bitmaps:
You need to load the Bitmap properly and adjust the size of the Bitmap to your needs. In most cases, it makes no sense to load a Bitmap with higher resolution than the screen of the device supports.
Furthermore, this practice is very important to avoid OutOfMemoryErrors when working with Bitmaps that large.
As an example, a Bitmap with the size of 8000 x 4000 uses more than 100 Megabytes of RAM (in 32 Bit color), which is an enormous amount for a mobile device and much more than even high end devices are capable of handling.
This is how to load a Bitmap properly:
public abstract class BitmapResLoader {
public static Bitmap decodeBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
private static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
}
Example usage in code:
Bitmap b = BitmapResLoader.decodeBitmapFromResource(getResources(),
R.drawable.mybitmap, 500, 500);
Taken from the Google Android Developer guidelines here:
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
Concerning the maximum Bitmap size:
The maximum Bitmap size limit depends on the unterlying OpenGL implementation. When using OpenGL, this can be tested via (source: Android : Maximum allowed width & height of bitmap):
int[] maxSize = new int[1];
gl.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxSize, 0);
e.g. for the Galaxy S2, it is 2048x2048.