From mipmap to drawable - java

I used to have the images of my app in the mipmap folders but I didn't have deferent resolutions ( I had the exactly same image in all 5 folders). In order to save space I moved those images in the drawable folder (except the launcher icons that are the only images that have different resolutions) . But when I open an activity that has some of those images I get the following crash error:
java.lang.OutOfMemoryError: Failed to allocate a
29304012 byte allocation with 16777216 free bytes and
23MB until OOM
at
dalvik.system.VMRuntime.newNonMovableArray(Native
Method)
at
android.graphics.BitmapFactory.nativeDecodeAsset(Native
Method)
at
android.graphics.BitmapFactory.decodeStream(BitmapFac
tory.java:624)
at
android.graphics.BitmapFactory.decodeResourceStream(Bi
tmapFactory.java:457)
at
android.graphics.drawable.Drawable.createFromResource
Stream(Drawable.java:1152)
at
android.content.res.ResourcesImpl.createFromResourceSt
ream(ResourcesImpl.java:1272)
at
android.content.res.ResourcesImpl.loadDrawableForCooki
e(ResourcesImpl.java:743)
at
android.content.res.ResourcesImpl.loadDrawable(Resourc
esImpl.java:585)
at
android.content.res.MiuiResourcesImpl.loadDrawable(Miui
ResourcesImpl.java:308)
at
android.content.res.Resources.loadDrawable(Resources.ja va:872)
at
android.content.res.TypedArray.getDrawable(TypedArray.ja
va:930)
at android.view.View.<init>(View.java:4182)
at android.widget.TextView.<init>(TextView.java:710)
at android.widget.Button.<init>(Button.java:109)
at android.widget.Button.<init>(Button.java:105)
at android.support.v7.widget.AppCompatButton.<init>.
(AppCompatButton.java:70)
at android.support.v7.widget.AppCompatButton.<init>.
(AppCompatButton.java:66)
at
android.support.v7.app.AppCompatViewInflater.createButt
on(AppCompatViewInflater.java:186)
at
android.support.v7.app.AppCompatViewInflater.createVie
w(AppCompatViewInflater.java:109)
at
android.support.v7.app.AppCompatDelegateImplV9.create
View(AppCompatDelegateImplV9.java:1035)
at
android.support.v7.app.AppCompatDelegateImplV9.onCre
ateView(AppCompatDelegateImplV9.java:1092)
at
android.view.LayoutInflater.createViewFromTag(LayoutInfl
ater.java:794)
at
android.view.LayoutInflater.createViewFromTag(LayoutInfl
ater.java:752)
at
android.view.LayoutInflater.rInflate(LayoutInflater.java:883)
at
android.view.LayoutInflater.rInflateChildren(LayoutInflater.j
ava:846)
at
android.view.LayoutInflater.rInflate(LayoutInflater.java:886)
at
android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:846)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:886)
at
android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:846)
at
android.view.LayoutInflater.inflate(LayoutInflater.java:522)
at
android.view.LayoutInflater.inflate(LayoutInflater.java:430)
at
android.view.LayoutInflater.inflate(LayoutInflater.java:377)
at
android.support.v7.app.AppCompatDelegateImplV9.setContentView(AppC
ompatDelegateImplV9.java:287)
at
android.support.v7.app.AppCompatActivity.setContentView(
AppCompatActivity.java:139)
at
com.soon.coming.endturnbutton.themes.onCreate(themes.java:38)
at
android.app.Activity.performCreate(Activity.java:6852)
at
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2700)
at
android.app.ActivityThread.handleLaunchActivity(ActivityT hread.java:2808)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at
android.app.ActivityThread$H.handleMessage(ActivityThre ad.java:1541)
at
android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:165)
at
android.app.ActivityThread.main(ActivityThread.java:6365)
at java.lang.reflect.Method.invoke(Native Method)
at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.r
un(ZygoteInit.java:883)
at
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)

I have faced this issue before, this was because i had a very very large image inside my drawable folder to be loaded (out of memory).
What i did, is to drag all my drawables to this site to generate Android assets and returned them back to my drawables with the new sizes (and resolutions as well like hdpi,....etc).

This means you are out of memory. What you can do to save space is move the images back into the mipmap folder but you only need it in one of them. You do not need to put it in all five. It is not the best practice, but it would work.

use this link to create appropriate resolution images(hdp,xdp, xxdp) and then put these images in related drawable resource directory
https://romannurik.github.io/AndroidAssetStudio/

Related

Android Java unable to find resource ID

On some devices there is no problem but on some such exception appears when opening src of ImageView.
The stack trace looks like this:
java.lang.RuntimeException: Unable to start activity
ComponentInfo{pl.jawegiel.endlessblow/pl.jawegiel.endlessblow.activities.MainActivity}:
android.view.InflateException: Binary XML file line #11: Binary XML file line #11: Error inflating class
ImageView at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2666) at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2727) at android.app.ActivityThread.-
wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1478) at
android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at
android.app.ActivityThread.main(ActivityThread.java:6121) at java.lang.reflect.Method.invoke(Native
Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889) at
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779) Caused by: android.view.InflateException:
Binary XML file line #11: Binary XML file line #11: Error inflating class ImageView Caused by:
android.view.InflateException: Binary XML file line #11: Error inflating class ImageView Caused by:
android.content.res.Resources$NotFoundException: Drawable (missing name) with resource ID #0x7f0800cd
Caused by: android.content.res.Resources$NotFoundException: Unable to find resource ID #0x7f0800cd at
android.content.res.ResourcesImpl.getResourceName(ResourcesImpl.java:228) at
android.content.res.ResourcesImpl.loadDrawableForCookie(ResourcesImpl.java:687) at
android.content.res.ResourcesImpl.loadDrawable(ResourcesImpl.java:571) at
android.content.res.Resources.loadDrawable(Resources.java:858) at
android.content.res.TypedArray.getDrawable(TypedArray.java:928) at android.widget.ImageView.
(ImageView.java:162) at android.widget.ImageView.(ImageView.java:150) at
androidx.appcompat.widget.AppCompatImageView.(AppCompatImageView.java:74) at
androidx.appcompat.widget.AppCompatImageView.(AppCompatImageView.java:69) at
androidx.appcompat.app.AppCompatViewInflater.createImageView(AppCompatViewInflater.java:199) at
androidx.appcompat.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:119) at
androidx.appcompat.app.AppCompatDelegateImpl.createView(AppCompatDelegateImpl.java:1551) at
androidx.appcompat.app.AppCompatDelegateImpl.onCreateView(AppCompatDelegateImpl.java:1602) at
android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:769) at
android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727) at
android.view.LayoutInflater.rInflate(LayoutInflater.java:858) at
android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821) at
android.view.LayoutInflater.inflate(LayoutInflater.java:518) at
android.view.LayoutInflater.inflate(LayoutInflater.java:426) at
android.view.LayoutInflater.inflate(LayoutInflater.java:377) at
androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:696) at
androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:170) at
pl.jawegiel.endlessblow.activities.MainActivity.onCreate(MainActivity.java:50) at
android.app.Activity.performCreate(Activity.java:6682) at
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2619) at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2727) at android.app.ActivityThread.-
wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1478) at
android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at
android.app.ActivityThread.main(ActivityThread.java:6121) at java.lang.reflect.Method.invoke(Native
Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889) at
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
MainActivity.java:50 looks like this:
setContentView(R.layout.activity_main);
ImageView that causes problem looks like this:
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/splash2"
android:scaleType="fitXY"
android:adjustViewBounds="true"
android:contentDescription="TODO" />
this splash2.png is located in res\drawable, res\drawable-hdpi, res\drawable-mdpi, res\drawable-xhdpi, res\drawable-xxhdpi and res\drawable-xxxhdpi so I guess in correct folders. So how to solve that?
Thank you in advance!
You may be able to solve this problem with a more generalistic approach:
Try using scalable vector graphics (SVG) instead of .PNG-images. VectorDrawable is more flexible if you need to match different screen resolutions.
PNGs can be transformed into scalable vector graphics with Inkscape or online PNG converter (https://convertio.co/de/png-svg/)
After that you can create a new VectorDrawable by loading the SVG. VectorDrawables can be assigned with app:srcCompat="#drawable/ic_VectorDrawableName"
Documentation:
A VectorDrawable is a vector graphic defined in an XML file as a set
of points, lines, and curves along with its associated color
information. The major advantage of using a vector drawable is image
scalability. It can be scaled without loss of display quality, which
means the same file is resized for different screen densities without
loss of image quality. This results in smaller APK files and less
developer maintenance. You can also use vector images for animation by
using multiple XML files instead of multiple images for each display
resolution.
VectorDrawable also requires much less RAM than .PNG.
You may find the cause of your errors in this thread:
Resources$NotFoundException drawable-xhdpi from drawable resource

Android - I am having problems with adding more than 8 imageviews to RelativeLayout

enter ?
I need to add 24 images to RelativeLayout and I first tried it with XML,
which just shut down the app after I added 8th ImageView.
So I tried with coding like above, and it shows me that message.
It says OutOfMemory, failed to allocate ___ to a memory with 6mb OOM and I don't really know what it means but I am guessing image files are too large?
It caused error like that when I just tried with XML too.
enter image description here
but the entire set of images are less than 100kb though.
How can I deal with this issue?
looks like you have drawables in drawable folder. So if you have really large-density screen, it scales. You should create scaled images for all dpi's or init images manually:
Options options = new Options();
options.inScaled = false;
bitmapImage = BitmapFactory.decodeResource(context.getResources(),
R.drawable.imageName, options);
imageview.setImageBitmap(bitmapImage);
or
InputStream is = this.getResources().openRawResource(imageId);
Bitmap originalBitmap = BitmapFactory.decodeStream(is);
imageview.setImageBitmap(originalBitmap);
Use Picssso library (http://square.github.io/picasso/). It has fit() method that is very useful for loading many images. Example:
Picssso.with(context).load(R.drawable.yourimage).fit().into(yourImageView);

Out Of Memory Error When loading more images in Glide

Edited:
In my application, I am loading more than 300 images in home page. I used glide to load images. I'm getting Out of Memory Error.
I have used large heap true in manifest :
android:largeHeap="true"
Glide Version:
compile 'com.github.bumptech.glide:glide:3.7.0'
Device/Android Version:
Nexus Device 6.0 version
Every images I'm getting from Json would be 800kb to 1mb.
activity_layout:
<RelativeLayout
android:id="#+id/home_layout_bottom"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/home_layout_top_recycler"
android:layout_margin="5dp">
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_list_tab_home_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:scrollbars="vertical"
android:visibility="visible" />
<TextView
android:id="#+id/no_user_posts_item_tv_recycler"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/rv_list_tab_home_recycler"
android:layout_marginTop="80dp"
android:layout_centerHorizontal="true"
android:text="#string/txt_no_posts_available"
android:textColor="#color/txt_common_black"
android:textSize="#dimen/txt_size" />
</RelativeLayout>
adapter code:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
final HomePostItems rowItem = getItem(position);
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.lv_adapter_post_items_layout, null);
holder = new ViewHolder();
holder.ivPostedImage = (ImageView) convertView.findViewById(R.id.iv_posted_img);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
..................
Glide.with(context).load(rowItem.getPosteduserpostimage())
.placeholder(R.drawable.golive_load_image).error(R.drawable.golive_cancel_image)
.override(600, 200)
.into(holder.ivPostedImage);
adapter_layout.xml:
<RelativeLayout
android:id="#+id/rl_lv_user_post_adapter_img_holder_home"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginLeft="1dp"
android:layout_marginRight="1dp"
android:layout_below="#+id/tv_user_posted_msg_post_items_home" >
<ImageView
android:id="#+id/iv_posted_img_home"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:scaleType="fitXY"
android:background="#ffffff"
android:contentDescription="#string/cont_desc"/>
</RelativeLayout>
Logcat:
Request threw uncaught throwable
java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: Failed to allocate a 6365196 byte allocation with 865912 free bytes and 845KB until OOM
at java.util.concurrent.FutureTask.report(FutureTask.java:94)
at java.util.concurrent.FutureTask.get(FutureTask.java:164)
at com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor.afterExecute(FifoPriorityThreadPoolExecutor.java:96)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1121)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
at com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor$DefaultThreadFactory$1.run(FifoPriorityThreadPoolExecutor.java:118)
Caused by: java.lang.OutOfMemoryError: Failed to allocate a 6365196 byte allocation with 865912 free bytes and 845KB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:635)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:611)
at com.bumptech.glide.load.resource.bitmap.Downsampler.decodeStream(Downsampler.java:329)
at com.bumptech.glide.load.resource.bitmap.Downsampler.downsampleWithSize(Downsampler.java:220)
at com.bumptech.glide.load.resource.bitmap.Downsampler.decode(Downsampler.java:153)
at com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder.decode(StreamBitmapDecoder.java:50)
at com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder.decode(StreamBitmapDecoder.java:19)
at com.bumptech.glide.load.resource.bitmap.ImageVideoBitmapDecoder.decode(ImageVideoBitmapDecoder.java:39)
at com.bumptech.glide.load.resource.bitmap.ImageVideoBitmapDecoder.decode(ImageVideoBitmapDecoder.java:20)
at com.bumptech.glide.load.resource.gifbitmap.GifBitmapWrapperResourceDecoder.decodeBitmapWrapper(GifBitmapWrapperResourceDecoder.java:121)
at com.bumptech.glide.load.resource.gifbitmap.GifBitmapWrapperResourceDecoder.decodeStream(GifBitmapWrapperResourceDecoder.java:94)
at com.bumptech.glide.load.resource.gifbitmap.GifBitmapWrapperResourceDecoder.decode(GifBitmapWrapperResourceDecoder.java:71)
at com.bumptech.glide.load.resource.gifbitmap.GifBitmapWrapperResourceDecoder.decode(GifBitmapWrapperResourceDecoder.java:61)
at com.bumptech.glide.load.resource.gifbitmap.GifBitmapWrapperResourceDecoder.decode(GifBitmapWrapperResourceDecoder.java:22)
at com.bumptech.glide.load.engine.DecodeJob.decodeFromSourceData(DecodeJob.java:190)
at com.bumptech.glide.load.engine.DecodeJob.decodeSource(DecodeJob.java:177)
at com.bumptech.glide.load.engine.DecodeJob.decodeFromSource(DecodeJob.java:128)
at com.bumptech.glide.load.engine.EngineRunnable.decodeFromSource(EngineRunnable.java:122)
at com.bumptech.glide.load.engine.EngineRunnable.decode(EngineRunnable.java:101)
at com.bumptech.glide.load.engine.EngineRunnable.run(EngineRunnable.java:58)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
at com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor$DefaultThreadFactory$1.run(FifoPriorityThreadPoolExecutor.java:118)
I don't know how to fix this OOM issue. Please share your suggestion, if you have already familiar with this issue.
I solved this issue by removing nested scroll view placed above
recyclerview. Why OutOfMemory error occurred means, when loading more
than 200 images in home page, it is loading all 200 images because of using
nested scroll view above recyclerview.
So I can't check the logcat image view width and height one by one in
adapter.
After removed nested scroll view fixed out of memory error.because it
will load only 3 images displayed in device when coming to home
activity.
Also check
this, how to use scroll instead of nested scroll view.
This is not an exact solution to your problem, but you need to keep these things in mind while loading images in a list using Glide.
The main threatening part of your problem is the image size. The image you're getting is almost 1mb each! Which is in fact too large for displaying them into a list having 300+ items. So if you're doing the server side too, its always recommended to have the images in several different sizes.
For example, in case of showing a friend list along with their profile pictures, I would suggest you get the whole list first from the server. Then fetch all of the profile images and store them locally. Then populate the ListView. And the most important part is while uploading a profile picture of an user to the server, after uploading it, the server needs to keep several sizes of it e.g. low, mid and high res version. So that while serving the profile picture urls for the ListView the server might provide the images with low res as they'll be used most likely for thumbnails.
Using RecyclerView instead of ListView is a good call too. But it won't solve the problem you've here when you're in a low-end device.
OMM has nothing to do with you can solve programatically. You need to resize your image to a lower res version.
You can check for the Glide's caching mechanism too. I would suggest you use the caching strategy so that every time you don't have to load the image from server.
Good luck.
Using Glide doesn't guarantee no Out of Memory errors, you need to use several small steps to reduce the probability to not get OOM's.
Step 1: Understand the caching mechanism in Glide
Step 2: I prefer to load thumbnails into recyclerview
Glide
.with( context )
.load( UsageExampleGifAndVideos.gifUrl )
.thumbnail( 0.1f )
.into( imageView2 );
Remember to always request small size image if bigger or HD images are
not required.
Make sure the ImageView has match_parent or fixed dp as dimensions
wrap_content makes Glide load full resolution Bitmaps.
.placeholder() shows an image instead of empty space while loading large bitmap
.thumbnail(float) loads a downsampled version fast while the bigger image is loading in the background
Also look around the Glide issues, maybe you find something helpful.
Use recyclerView instead of ListView. It reusable single item for rendering items. I am using glide with recyclerView where i am loading wallpapers with 100+ items.
In ListView every time you are creating view, if you have 100+ view and it will create 100+ views where as in recyclerview it creates how many visible items are there in screen +2.
The reason is while scrolling, glide keep doing image process even related views removes from list. Add this code in your listview's onScrollStateChanged.
if (view.getContext() != null) {
switch (scrollState) {
case SCROLL_STATE_IDLE:
Glide.with(view.getContext()).resumeRequests();
break;
case SCROLL_STATE_TOUCH_SCROLL:
case SCROLL_STATE_FLING:
Glide.with(view.getContext()).pauseRequests();
break;
}
}
I faced the similar problem . I am sharing the way I solved it . Create a folder named drawable-nodpi put your golive_load_image and golive_cancel_im‌​age file into that folder , and remove those two image file from other place like drawable-ldpi,drawable-hdpi etc (if you have there ) . And add skipMemoryCache( true )
Glide.with(context).load(rowItem.getPosteduserpostimage())
.skipMemoryCache( true )
.placeholder(R.drawable.golive_load_image).error(R.drawable.golive_cancel_image)
.override(600, 200)
.into(holder.ivPostedImage);
your images should not be too large ( if they are, use .thumbnail(...f) )
use .skipMemoryCache(true) if you are not force to keep images in cache
you can use .diskCacheStrategy(DiskCacheStrategy.NONE) to deactivate the disk cache
In order to prevent Out of Memory error one can just make precautions to make sure that it will not occurs. So the answer of this question is actually a bunch of suggestions one can suggest. So do I.
As suggested by #Reaz Murshed I am also recommending to have the images in several different sizes. Apart from this I would like to add few more things that might help you analyze this issue and solve it.
As far as I remember OOM was always a usage error, largeHeap will just delay it; or if it's a large load then maybe it's not possible. So I am suggesting you to follow this link to diagnose for memory leaks.
Stack traces of OutOfMemoryErrors don't help at all for diagnosing
them. It just tells you it's broken and something filled up the
memory. This filling happens much before the actual exception was
thrown. This also implies that usually whatever throws the OOM is not
actually the culprit. The only exception to this is when the amount of
wannabe allocated memory is simply too big, for example: an array to
be allocated is bigger than the maximum memory, then you know that
some calculation went really wrong, like a 32000x32000#4 image would
take around 4GB of memory.
If you can reproduce: get a heap dump and analyze your app's usage.
Normal OOM diagnostic steps:
Reproduce exception
(wait till you see it in LogCat)
Take a heap dump(To analyze memory leaks)
Analyze it for big objects and leaks
In above shared link there is few another links regarding how to take heap dump? and issues that are identical with this one.
So I suggest you to analyze for memory leaks and take necessary steps to prevent OOM.
Hope this will help you.
Probably a different approach can be taken to resolve this.
To achieve this you can use a different ImageAdapter with
Glide.with(mActivity).loadFromMediaStore(_imageInfo.getmUri())
this does not crash being using MediaStoreThumbFetcher
To have more control over the load do the following using Glide v4
// usage:
Glide.with(mActivity).load(_imageInfo)....
// in GlideModule.registerComponents
registry.prepend(ImageInfo.class, ImageInfo.class, new UnitModelLoader.Factory<ImageInfo>());
registry.prepend(ImageInfo.class, Bitmap.class, new ImageInfoBitmapDecoder(context));
class ImageInfoBitmapDecoder implements ResourceDecoder<ImageInfo, Bitmap> {
private final ContentResolver contentResolver;
private final BitmapPool pool;
public ImageInfoBitmapDecoder(Context context) {
this.contentResolver = context.getContentResolver();
this.pool = Glide.get(context).getBitmapPool();
}
#Override public boolean handles(ImageInfo source, Options options) { return true; }
#Override public #Nullable Resource<Bitmap> decode(ImageInfo source, int width, int height, Options options) {
Bitmap thumb = Thumbnails.getThumbnail(contentResolver, source.getmId(), Thumbnails.MINI_KIND, null);
return BitmapResource.obtain(thumb, pool);
}
}
Using following API's we can figure out free memory left out and size of the bitmap
You can check available memory and bitmap details (if needed) as a pre-check
Check the amount of free memory left
public static final float BYTES_IN_MB = 1024.0f * 1024.0f;
public static float megabytesFree() {
final Runtime rt = Runtime.getRuntime();
final float bytesUsed = rt.totalMemory();
final float mbUsed = bytesUsed/BYTES_IN_MB;
final float mbFree = megabytesAvailable() - mbUsed;
return mbFree;
}
public static float megabytesAvailable() {
final Runtime rt = Runtime.getRuntime();
final float bytesAvailable = rt.maxMemory();
return bytesAvailable/BYTES_IN_MB;
}
Check how big is the bitmap we want to load
private void readBitmapInfo() {
final Resources res = getActivity().getResources();
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, R.drawable.brasil, options);
final float imageHeight = options.outHeight;
final float imageWidth = options.outWidth;
final String imageMimeType = options.outMimeType;
Log.d(TAG, "w,h, type:"+imageWidth+", "+imageHeight+", "+imageMimeType);
Log.d(TAG, "estimated memory required in MB: "+imageWidth * imageHeight * BYTES_PER_PX/MemUtils.BYTES_IN_MB);
}
For more details go through Java methods to check memory and bitmap and github discussion
I faced the same issue and solved it by adding android:largeHeap="true" in the application tag of my manifest file like below.
<manifest>
...
<application
.....
android:largeHeap="true"
....
>
....
</application>
</manifest>
NB: this should be your last option, as using largeHeap:true is not recommended for solving simple OOM problems.

MediaMetadata.getString java.lang.RuntimeException: Could not read bitmap from parcel blob

Call MediaMetadata.getString, have below crash in report, but not always repro:
java.lang.RuntimeException: Could not read bitmap from parcel blob.
at android.graphics.Bitmap.nativeCreateFromParcel(Native Method)
at android.graphics.Bitmap.access$000(Bitmap.java:32)
at android.graphics.Bitmap$1.createFromParcel(Bitmap.java:1477)
at android.graphics.Bitmap$1.createFromParcel(Bitmap.java:1469)
at android.os.Parcel.readParcelable(Parcel.java:2246)
at android.os.Parcel.readValue(Parcel.java:2146)
at android.os.Parcel.readArrayMapInternal(Parcel.java:2479)
at android.os.BaseBundle.unparcel(BaseBundle.java:221)
at android.os.BaseBundle.getCharSequence(BaseBundle.java:953)
at android.os.Bundle.getCharSequence(Bundle.java:716)
at android.media.MediaMetadata.getText(MediaMetadata.java:334)
at android.media.MediaMetadata.getString(MediaMetadata.java:347)
The code is as blow, the MediaMetadata meta is from the controller of api MediaSessionManager.OnActiveSessionsChangedListener, it should be created by third-part music app.
meta.getString(MediaMetadata.METADATA_KEY_ALBUM_ARTIST);
meta.getString(MediaMetadata.METADATA_KEY_ARTIST);
meta.getString(MediaMetadata.METADATA_KEY_AUTHOR);
meta.getBitmap(MediaMetadata.METADATA_KEY_ART);
meta.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
meta.getString(MediaMetadata.METADATA_KEY_ALBUM);
meta.getString(MediaMetadata.METADATA_KEY_TITLE);
Why the getString will parse the bitmap? is it possible the memory is out when this happen?
I think this happens when you put big bitmaps into the MediaMetaData object with .putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, icon). This bitmap is used on the MediaDescription and thus it should be pretty small as it's serialized. It's actually deserialized every time you call getString on the meta data.
So, the solution to this issue would be to only use small bitmaps for METADATA_KEY_DISPLAY_ICON or not use it at all if possible.

Font asset not found helvetica.ttf on lollipop

For some reason on lollipop, I'm getting this error and since lollipop is so new I can't find out why anywhere and I have no idea how to figure it out. Thanks in advance Logcat error:
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.bent.MissionaryTracker/com.bent.MissionaryTracker.MainActivity}:
java.lang.RuntimeException: Font asset not found helvetica.ttf
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2298)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
at android.app.ActivityThread.access$800(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: java.lang.RuntimeException: Font asset not found helvetica.ttf
at android.graphics.Typeface.createFromAsset(Typeface.java:190)
at com.bent.MissionaryTracker.MainActivity.onCreate(MainActivity.java:57)
at android.app.Activity.performCreate(Activity.java:5933)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
... 10 more
EDIT: HERE IS THE CODE THAT THROWS THE ERROR
title = (TextView) findViewById(R.id.title);
Typeface font = Typeface.createFromAsset(getAssets(), "helvetica.ttf");
title.setTypeface(font);
I have helvetica.ttf in my assets folder in my project folders.
EDIT:
This app works on all devices up until 5.0 so for some reason 5.0 is not recognizing the file in my assets folder.
I tried to post a screenshot of it in my assets folder but I don't have enough reputation to post images.
If you are working on Android Studio make sure your asset folder is under main and not res
This worked for me
Now it's better to use for custom fonts this approach
Store fonts in res/font
To get typeface use :
Typeface typeface = ResourcesCompat.getFont(context, R.font.myfont);
I had this problem too before I realized I didn't put "fonts/" before the .otf file
Typeface font = Typeface.createFromAsset(getAssets(),"fonts/TTMastersDEMOBlack.ttf");
This worked for me. In my case it didn't work because I created assets folder in res and not in main.
If changing the directory doesn't work it could be due to a problem already fixed by the Android team but didn't make it in time for 5.0. It's all explained here:
https://code.google.com/p/android-developer-preview/issues/detail?id=608&thanks=608&ts=1404735239
The workaround (at least it was for me) is to fix the font files with TTX as mentioned in the linked issue.
Getting TTX to work can be a bit of a hassle if you have no python expertise so I ended up downloading Adobe's AFDKO that includes TTX. You have to run 'ttx yourfontfile.ttf' that'll turn yourfile to .ttx and then run it again 'ttx yourfontfile.ttx' to get a new .ttf that works with 5.0.
Clean the project, it helped me on android 6.0
Just place a assets folder inside main directory.
After do this:
Typeface typeface=Typeface.createFromAsset(getAssets(),"OpenSans-Light.ttf");
textView.setTypeface(typeface);
I faced this issue before. I deleted x.ttf and then undid the deletion, tried to run with no lock. So my fix was just to delete it and downloaded the font again and pasted it to fonts/ folder and every thing worked fine.
Ok Guys,
I ran into the same problem. First of all I made my font loading logic crash proof:
/**
* Init method. This method must be called before any other call in this class.
*/
public static void init () {
fontPlain = createFont( "helvetica.ttf" , Typeface.NORMAL );
fontBold = createFont( "helveticab.ttf", Typeface.BOLD );
}
/**
* Load font from assets font folder.
*/
public static Typeface createFont (String font, int style) {
Typeface typeface;
try {
AssetManager assets = Kit.getAppContext().getAssets();
typeface = Typeface.createFromAsset( assets, "fonts" + File.separator + font );
}
catch (RuntimeException e) {
// createFromAsset() will throw a RuntimeException in case of error.
Log.e( Constants.TAG, "Unable to create font: " + font, e );
typeface = Typeface.defaultFromStyle( style );
}
return typeface;
}
And then I also downloaded another font from this project in git:
https://github.com/dimanchec3/Tutoriapps-Android/blob/master/assets/Helvetica.ttf
I realized that my old font was 56KB and this new font is 84KB. I guess I had an older version of the font.
Please make sure you have the proper license before using this font.

Categories