Hey guys,
I'm currently working on a tutorial for an app of my university.
In order to introduce the app to the user, we want to show him some pictures.
I've decided to use a fragmentStatePagerAdapter in combination with the glide library, because I ran out of memory on previous implementations. Unfortunately my new implementation does not work. At the 14th picture (out of 16) I'm getting an oom-error from the glide library.
02-10 13:15:50.754 I/art (14716): Alloc sticky concurrent mark sweep GC freed 684(80KB) AllocSpace objects, 0(0B) LOS objects, 3% free, 92MB/96MB, paused 1.092ms total 9.371ms
02-10 13:15:50.784 I/art (14716): Clamp target GC heap from 100MB to 96MB
02-10 13:15:50.784 I/art (14716): Alloc partial concurrent mark sweep GC freed 45(2520B) AllocSpace objects, 0(0B) LOS objects, 3% free, 92MB/96MB, paused 1.253ms total 26.522ms
02-10 13:15:50.814 I/art (14716): Clamp target GC heap from 100MB to 96MB
02-10 13:15:50.814 I/art (14716): Alloc concurrent mark sweep GC freed 7(224B) AllocSpace objects, 0(0B) LOS objects, 3% free, 92MB/96MB, paused 767us total 31.447ms
02-10 13:15:50.814 I/art (14716): Forcing collection of SoftReferences for 3MB allocation
02-10 13:15:50.844 I/art (14716): Clamp target GC heap from 100MB to 96MB
02-10 13:15:50.844 I/art (14716): Alloc concurrent mark sweep GC freed 3(96B) AllocSpace objects, 0(0B) LOS objects, 3% free, 92MB/96MB, paused 854us total 27.011ms
02-10 13:15:50.844 E/art (14716): Throwing OutOfMemoryError "Failed to allocate a 3686412 byte allocation with 3183968 free bytes and 3MB until OOM"
02-10 13:15:50.844 E/GlideExecutor(14716): Request threw uncaught throwable
02-10 13:15:50.844 E/GlideExecutor(14716): java.lang.OutOfMemoryError: Failed to allocate a 3686412 byte allocation with 3183968 free bytes and 3MB until OOM
02-10 13:15:50.844 E/GlideExecutor(14716): at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
02-10 13:15:50.844 E/GlideExecutor(14716): at android.graphics.Bitmap.nativeCreate(Native Method)
02-10 13:15:50.844 E/GlideExecutor(14716): at android.graphics.Bitmap.createBitmap(Bitmap.java:939)
02-10 13:15:50.844 E/GlideExecutor(14716): at android.graphics.Bitmap.createBitmap(Bitmap.java:912)
02-10 13:15:50.844 E/GlideExecutor(14716): at android.graphics.Bitmap.createBitmap(Bitmap.java:879)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPool.getDirty(LruBitmapPool.java:140)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.resource.bitmap.Downsampler.setInBitmap(Downsampler.java:573)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.resource.bitmap.Downsampler.decodeFromWrappedStreams(Downsampler.java:273)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.resource.bitmap.Downsampler.decode(Downsampler.java:204)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder.decode(StreamBitmapDecoder.java:60)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder.decode(StreamBitmapDecoder.java:17)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.DecodePath.decodeResourceWithList(DecodePath.java:67)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.DecodePath.decodeResource(DecodePath.java:52)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.DecodePath.decode(DecodePath.java:43)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.LoadPath.loadWithExceptionList(LoadPath.java:56)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.LoadPath.load(LoadPath.java:42)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.DecodeJob.runLoadPath(DecodeJob.java:482)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.DecodeJob.decodeFromFetcher(DecodeJob.java:454)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.DecodeJob.decodeFromData(DecodeJob.java:440)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.DecodeJob.decodeFromRetrievedData(DecodeJob.java:394)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.DecodeJob.onDataFetcherReady(DecodeJob.java:363)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.SourceGenerator.onDataReady(SourceGenerator.java:111)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.onDataReady(MultiModelLoader.java:132)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.data.LocalUriFetcher.loadData(LocalUriFetcher.java:49)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:96)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:61)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:286)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:256)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:226)
02-10 13:15:50.844 E/GlideExecutor(14716): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
02-10 13:15:50.844 E/GlideExecutor(14716): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
02-10 13:15:50.844 E/GlideExecutor(14716): at java.lang.Thread.run(Thread.java:818)
02-10 13:15:50.844 E/GlideExecutor(14716): at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:347)
I can't find my error...
Is it right that glider automatically organizes the memory of it's images? If so, what am I doing wrong?
Here's some code.
1. The activity I start at the first start of the app.
[Activity(Label = "Tutorial", ScreenOrientation = Android.Content.PM.ScreenOrientation.Landscape)]
public class TutorialActivity : FragmentActivity {
private ViewPager pager;
private const int NUMBER_OF_IMAGES = 16;
protected override void OnCreate(Bundle savedInstanceState) {
base.OnCreate(savedInstanceState);
App.Init(this, savedInstanceState);
// Remove notification bar
Window.AddFlags(WindowManagerFlags.Fullscreen);
RequestWindowFeature(WindowFeatures.NoTitle);
// set content view AFTER ABOVE sequence (to avoid crash)
SetContentView(Resource.Layout.ActivityTutorial);
pager = (ViewPager)FindViewById(Resource.Id.pagerTutorial);
pager.Adapter = (new TutorialPagerAdapter(this, SupportFragmentManager));
}
protected override void OnDestroy() {
base.OnDestroy();
}
public override void OnBackPressed() {
if (pager.CurrentItem == 0) {
Finish();
} else {
pager.CurrentItem = (pager.CurrentItem - 1);
}
}
private class TutorialPagerAdapter : FragmentStatePagerAdapter {
private readonly String[] images;
public TutorialPagerAdapter(TutorialActivity parent, global::Android.Support.V4.App.FragmentManager fm) : base(fm) {
images = Enumerable.Range(1, NUMBER_OF_IMAGES)
.Select(i => $"Android_Tut_{GetIndexToken(i)}.png")
.ToArray();
}
private string GetIndexToken(int index) {
if (index < 10) {
Console.WriteLine("Index: " + index + " returned: " + "0" + index.ToString());
return "0" + index.ToString();
} else {
Console.WriteLine("Index: " + index + " returned: " + index.ToString());
return index.ToString();
}
}
public override Android.Support.V4.App.Fragment GetItem(int position) {
FragmentTutorial result = FragmentTutorial.NewInstance(images[position]);
Bundle bundle = new Bundle();
bundle.PutString(FragmentTutorial.IMAGE_FILE_NAME, images[position]);
result.Arguments = (bundle);
return result;
}
public override int Count => images.Length;
}
}
The fragment
public class FragmentTutorial : Android.Support.V4.App.Fragment {
// Define Bundle keys for the image public static string IMAGE_FILE_NAME = "file_name"; public FragmentTutorial() { } // Static factory method that creates and initializes a new tutorial fragment: public static FragmentTutorial NewInstance(String p_fileName) { // Instantiate the fragment class: FragmentTutorial fragment = new FragmentTutorial(); // Pass the image: Bundle args = new Bundle(); args.PutString(IMAGE_FILE_NAME, p_fileName); fragment.Arguments = args; return fragment; } public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Get image: string imgName = Arguments.GetString(IMAGE_FILE_NAME, ""); imgName = imgName.Replace(".jpg", "").Replace(".png", ""); View view = inflater.Inflate(Resource.Layout.FragmentTutorial, container, false); // Locate the ImageView within the fragment's container: ImageView imgView = (ImageView)view.FindViewById(Resource.Id.imageViewTutorial); // Glide Stuff int resourceId = (int)typeof(Resource.Drawable).GetField(imgName).GetValue(null); Glide.With(Activity).Load(resourceId).Into(imgView); return view; } public override void OnDestroyView() { base.OnDestroyView(); }
}
Thanks for enduring my horrible format. Dont know why the code declaration on this post is not working properly.