jackpocket/android-scratchoff

It lags or even hangs sometimes. Due to memory issue.

Closed this issue · 9 comments

I am using the library for scratch and win functionality in my app. The whole screen is the scratchable layout. and there is another layout behind the scratchable linear layout which will be decided on the possibility of user wins or loses. But sometimes i found out that sometimes it does not even call the method setScratchValueChangedListener or the setCompletionCallback. Do you have any solution? Please help.

The XML layout is as follows.

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".fragment.ScratchFragment"> 

    <include
        android:id="@+id/toolbar_layout"
        layout="@layout/toolbar_text_logo" />

        <RelativeLayout
            android:id="@+id/scratch_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <RelativeLayout
                android:id="@+id/scratch_view_behind"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_centerInParent="true">

                <include
                    android:id="@+id/sorry_layout"
                    layout="@layout/activity_sorry"
                    android:visibility="gone"
                    />

                <include
                    android:id="@+id/winner_layout"
                    layout="@layout/activity_winner"
                    android:visibility="gone"/>

            </RelativeLayout>

            <com.jackpocket.scratchoff.views.ScratchableLinearLayout
                android:id="@+id/scratch_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_centerInParent="true">

                <ImageView
                    android:id="@+id/img_scratach_shape"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_gravity="center"
                    android:gravity="center"
                    android:scaleType="fitXY"
                    android:src="@drawable/scratch_1" />
            </com.jackpocket.scratchoff.views.ScratchableLinearLayout>
        </RelativeLayout>

</FrameLayout>

And before setting the scratch controller We are setting the behind layout which will be revealed. the code for that is as follows:

private void setBackgroundLayout() {
        shouldWin = someWinnerLogic();

        if (shouldWin) {
            winnerLayout.setVisibility(View.VISIBLE);
            sorryLayout.setVisibility(View.GONE);
        } else {
            sorryLayout.setVisibility(View.VISIBLE);
            winnerLayout.setVisibility(View.GONE);
        }
}

The code for setting the scratch controller is as follows:

private void setScratchController() {
        controller = new ScratchoffController(this);
        controller.setThresholdPercent(0.80d)
                .setTouchRadiusDip(this, 33)
                .setFadeOnClear(true)
                .setClearOnThresholdReached(true)

                .setScratchValueChangedListener(percentChanged -> {
                    // Do something on scratch percent value changed
                    if (percentChanged * 100 > 5) {
                        mediaPlayerScratch.start();
                        if (!isMarkAsScratch) {
                            isMarkAsScratch = true;
                            markAsCompleteScratch();
                        }
                    }
                })
                .setCompletionCallback(() -> {
                    Log.e("on", "completion callback");
//and my code for some ui actions on completeing scratching(reaching threshold)
                })
                .attach(scratchableLinearLayout, behindScratchView);
    }

Hi there, I'm sorry to hear you're having trouble and maybe I can help clear some things up. First, which version of the library are you using?

As for the memory issues, can you describe what you're seeing in more detail or provide any logs? Have you tried running the sample application (which is also an almost-fullscreen scratchoff) to see if you're also experiencing the same issues? You could then try adding pieces of your layout individually to see where the bottleneck begins.

Hi, @mattsilber thanks for replying.
I am using version 1.3.0.

An in my logs I am seeing following logs.

There's an exception:

java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
        at android.graphics.Bitmap.createBitmap(Bitmap.java:742)
03-14 10:39:24.861 20799-21045/com.veridocscratch.android W/System.err:     at com.jackpocket.scratchoff.a.d.f(ThresholdProcessor.java:86)
        at com.jackpocket.scratchoff.a.d.a(ThresholdProcessor.java:74)
        at com.jackpocket.scratchoff.a.b.run(Processor.java:20)
        at java.lang.Thread.run(Thread.java:764)

There are also GC related logs

Background concurrent copying GC freed 68(63KB) AllocSpace objects, 6(21MB) LOS objects, 68% free, 8MB/26MB, paused 327us total 101.705ms

and many more like this (almost similar like the above sentence)

And No, I have not tried running the sample app. From where can I found the sample app?

And As I said it is lagging can be seen in the attached gif.
Scratch   win

There's an exception:

That NPE is generally safe to ignore, assuming you're calling ScratchoffController.onResume() in your Activity's onResume method. The call to ScratchoffController.reset() will create the processors, which then get initially started via onResume (but aren't quite ready yet since the drawing area is not available). The processors are then correctly restarted once the layout event has been triggered.

No, I have not tried running the sample app. From where can I found the sample app?

My mistake, it's called scratchoff-test in the root of this repository. If you clone the repo, you could slowly add components from your layout code into there to see where your problem actually originates.

Also... what's going on in this block? If you try commenting it out are you still experiencing the jank? The ScratchValueChangedListener is run on the UI Thread. It's also worth noting, that it will not be triggered after the scratch threshold has been reached.

                   if (percentChanged * 100 > 5) {
                        mediaPlayerScratch.start();
                        if (!isMarkAsScratch) {
                            isMarkAsScratch = true;
                            markAsCompleteScratch();
                        }
                    }

Due to large bitmap, it was lagging behind, So I just resized that bitmap. Now it is not lagging anymore. But I am still facing an issue sometimes that is: sometimes the completion call back is not at all called.

what's going on in this block?

I am just counting that user has scratched one more time. (like a counter) that all calculation is covered in the method markAsCompleteScratch(); and playing the sound of scratching.

But I am still facing an issue sometimes that is: sometimes the completion call back is not at all called.

Is it also not clearing the scratchable area? Or is it clearing the area, but not triggering your callback?

and playing the sound of scratching

I would just be careful how much you're doing in there at a time as it's run on the UI thread and can be called many times per second.

Is it also not clearing the scratchable area? Or is it clearing the area, but not triggering your callback?

It is clearing the area but not triggering the callback.

It is clearing the area but not triggering the callback.

Then it sounds like the ScratchoffController is working properly, but might be losing the reference to your supplied Runnable. Are you positive you're never setting it to null, or that there are no code paths that could lead to you not adding the completion callback on Activity state changes?

Could you try having your Activity implement the Runnable interface and set it as the completion callback?

Ok Thank you @mattsilber. I will try my activity to implement runnable and set as completion callback as you said and let you know if I am still facing the trouble or not.

@mattsilber I am still facing the issue. in some of the devices or in some random cases, the callback is not triggered.