ShowCaseView 内存不足错误

ShowCaseView Out of Memory Error

我在使用 Galaxy S 系列时遇到一些问题,展示视图在任何其他设备上都可以正常工作,但我在 Galaxy S 设备上遇到以下错误。

java.lang.OutOfMemoryError: Failed to allocate a 5760012 byte allocation with 3573238 free bytes and 3MB until OOM at dalvik.system.VMRuntime.newNonMovableArray(VMRuntime.java) at android.graphics.BitmapFactory.nativeDecodeAsset(BitmapFactory.java)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:726)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:547)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:1014)
at android.content.res.Resources.loadDrawableForCookie(Resources.java:3747)
at android.content.res.Resources.loadDrawable(Resources.java:3620) at android.content.res.Resources.getDrawable(Resources.java:1852) at android.support.v4.content.res.ResourcesCompatApi21.getDrawable(ResourcesCompatApi21.java)
at android.support.v4.content.res.ResourcesCompat.getDrawable(ResourcesCompat.java)
at com.github.amlcurran.showcaseview.StandardShowcaseDrawer.(StandardShowcaseDrawer.java)
at com.github.amlcurran.showcaseview.ShowcaseView.(ShowcaseView.java)
at com.github.amlcurran.showcaseview.ShowcaseView.(ShowcaseView.java)
at com.github.amlcurran.showcaseview.ShowcaseView$Builder.(ShowcaseView.java)
at com.github.amlcurran.showcaseview.ShowcaseView$Builder.(ShowcaseView.java)
at br.com.mygas.myapplication.MainActivity.showcase(MainActivity.java)
at br.com.mygas.myapplication.MainActivity.access0(MainActivity.java)
at br.com.mygas.myapplication.MainActivity.onShowcaseViewDidHide(MainActivity.java)
at com.github.amlcurran.showcaseview.ShowcaseView.onAnimationEnd(ShowcaseView.java)
at com.github.amlcurran.showcaseview.AnimatorAnimationFactory.onAnimationEnd(AnimatorAnimationFactory.java)
at android.animation.ValueAnimator.endAnimation(ValueAnimator.java:1089)
at android.animation.ValueAnimator$AnimationHandler.doAnimationFrame(ValueAnimator.java:666)
at android.animation.ValueAnimator$AnimationHandler.run(ValueAnimator.java:682)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:777)
at android.view.Choreographer.doCallbacks(Choreographer.java:590) at
android.view.Choreographer.doFrame(Choreographer.java:559) at
android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:763)
at android.os.Handler.handleCallback(Handler.java:739) at
android.os.Handler.dispatchMessage(Handler.java:95) at
android.os.Looper.loop(Looper.java:145) at
android.app.ActivityThread.main(ActivityThread.java:5942) at
java.lang.reflect.Method.invoke(Method.java) at
java.lang.reflect.Method.invoke(Method.java:372) at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)

这是产生上述错误的实现代码:

private void showcase() {
        if (SaveSharedPreference.isMainActivity(this)) {
            switch (counter) {
                case 0:
                    new ShowcaseView.Builder(this)
                            .withMaterialShowcase()
                            .setContentTitle("Esta é a tela inicial:")
                            .setStyle(R.style.CustomShowcaseThemeNext)
                            .setShowcaseEventListener(new SimpleShowcaseEventListener() {
                                @Override
                                public void onShowcaseViewDidHide(ShowcaseView showcaseView) {
                                    counter++;
                                    showcase();
                                }
                            })
                            .build();
                    break;

                case 1:
                    new ShowcaseView.Builder(this)
                            .setContentTitle("Selecione o tipo de combustível:")
                            .setTarget(new ViewTarget(R.id.spinner, this))
                            .setShowcaseDrawer(new CustomShowcaseView(this, findViewById(R.id.spinner).getWidth(), findViewById(R.id.spinner).getHeight()))
                            .setShowcaseEventListener(new SimpleShowcaseEventListener() {
                                @Override
                                public void onShowcaseViewDidHide(ShowcaseView showcaseView) {
                                    counter++;
                                    showcase();
                                }
                            })
                            .build();
                    break;

                case 2:
                    new ShowcaseView.Builder(this)
                            .withMaterialShowcase()
                            .setTarget(new ViewTarget(R.id.fab2, this))
                            .setContentTitle("Clique neste botão para procurar combustível ao redor:")
                            .setStyle(R.style.CustomShowcaseThemeNext)
                            .setShowcaseEventListener(new SimpleShowcaseEventListener() {
                                @Override
                                public void onShowcaseViewDidHide(ShowcaseView showcaseView) {
                                    counter++;
                                    showcase();
                                }
                            })
                            .build();
                    break;

                case 3:
                    new ShowcaseView.Builder(this)
                            .withMaterialShowcase()
                            .setTarget(new ViewTarget(R.id.fab2, this))
                            .setContentTitle("Lembre-se:")
                            .setContentText("É necessário estar com o GPS ligado")
                            .setStyle(R.style.CustomShowcaseTheme2)
                            .setShowcaseEventListener(new SimpleShowcaseEventListener() {
                                @Override
                                public void onShowcaseViewDidHide(ShowcaseView showcaseView) {
                                    counter++;
                                    showcase();
                                }
                            })
                            .build();
                    SaveSharedPreference.mainActivityFirst(this);
                    break;
            }
        }
    }

我不知道错误是从哪里来的,所以正在寻找任何建议。

OutOfMemoryError 是 android 中最常见的问题,尤其是在处理位图时。当由于内存不足 space 而无法分配对象时,Java 虚拟机 (JVM) 会抛出此错误,而且垃圾收集器无法释放一些 space.

磁盘上文件的大小不一定与内存中文件的大小一致。文件很可能是压缩的,解码时不会压缩。您需要在计算中考虑到这一点。

how to load bitmaps efficiently?
可以参考这篇文章 How to load large bitmaps efficiently?

虽然使用不是一个好主意android:largeHeap="true"这里是google的摘录来解释它,

However, the ability to request a large heap is intended only for a small set of apps that can justify the need to consume more RAM (such as a large photo editing app). Never request a large heap simply because you've run out of memory and you need a quick fix—you should use it only when you know exactly where all your memory is being allocated and why it must be retained. Yet, even when you're confident your app can justify the large heap, you should avoid requesting it to whatever extent possible. Using the extra memory will increasingly be to the detriment of the overall user experience because garbage collection will take longer and system performance may be slower when task switching or performing other common operations.

这是完整的 link 文档 https://developer.android.com/training/articles/memory.html

但是,您可以尝试在 andriod 清单文件和 运行 中进行设置。

问题已解决,更改方法 hide from ShowcaseView.java 来自:

@Override
    public void hide() {
        // If the type is set to one-shot, store that it has shot
        shotStateStore.storeShot();
        mEventListener.onShowcaseViewHide(this);
        fadeOutShowcase();
    }

为此:

@Override
    public void hide() {
        // If the type is set to one-shot, store that it has shot
        clearBitmap();
        shotStateStore.storeShot();
        mEventListener.onShowcaseViewHide(this);
        fadeOutShowcase();
    }