masked-view icon indicating copy to clipboard operation
masked-view copied to clipboard

[bug/crash] MaskedView makes application crash on Android

Open DanielMarkiel opened this issue 4 years ago • 16 comments

Hi,

I'm experiencing an app crash on Android devices when using MaskedView. It occurs when leaving the screen (react navigation) with rendered MaskedView component and started happening after upgrading to RN 0.64.0.

Deps: "@react-native-masked-view/masked-view": "0.2.3", "react-native": "0.64.0",

P.s. iOS is working fine.

Logcat fragment:

021-04-13 12:31:49.611 15339-15339/[app] E/unknown:ReactNative: Exception thrown when executing ReactViewGroup.dispatchDraw method on ReactViewGroup[2999]
    java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.setVisibility(int)' on a null object reference
        at org.reactnative.maskedview.RNCMaskedView.updateBitmapMask(RNCMaskedView.java:81)
        at org.reactnative.maskedview.RNCMaskedView.dispatchDraw(RNCMaskedView.java:35)
        at android.view.View.buildDrawingCacheImpl(View.java:20689)
        at android.view.View.buildDrawingCache(View.java:20555)
        at android.view.View.draw(View.java:21145)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4388)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4173)
        at com.facebook.react.views.view.ReactViewGroup.dispatchDraw(ReactViewGroup.java:710)

DanielMarkiel avatar Apr 13 '21 10:04 DanielMarkiel

@DanielMarkiel

can you share example code to recreate this behavior?

Thanks

k-ibr avatar Apr 22 '21 12:04 k-ibr

@k-ibr

Sure, here's the link to the repo (created with npx react-native init MyApp --template react-native-template-typescript) -> https://github.com/DanielMarkiel/reprex-masked-view-android-error/commit/0a198c020fa1ae030a474318dfc5476096ee9ba3

In short. The error occurs if we define custom headerLeft and we render MaskedView component on the screen which uses it, e.g.


        <Stack.Screen
          name="MaskedView"
          component={MaskedViewScreen}
          options={({navigation}) => ({
            // Usage of custom 'headerLeft' breaks the app if MaskedView is rendered on the screen
            headerLeft: () => (
              <Button onPress={() => navigation.goBack()} title="Back" />
            ),
          })}
        />

DanielMarkiel avatar Apr 25 '21 07:04 DanielMarkiel

@DanielMarkiel I looked into this and it seems like MaskedView is trying to "modify" elements that no longer exist due to RN removing them from memory (by switching screens). So a quick fix for this is to check for null object on the view inside RNCMaskedView.java. You can try this by replacing the following functions by this code.

private void updateBitmapMask() {
    if (this.mBitmapMask != null) {
      this.mBitmapMask.recycle();
    }

    View maskView = getChildAt(0);
    if (maskView != null) {
      maskView.setVisibility(View.VISIBLE);
      this.mBitmapMask = getBitmapFromView(maskView);
      maskView.setVisibility(View.INVISIBLE);
    } else{
      this.mBitmapMask = null;
    }
  }
public void onDescendantInvalidated(View child, View target) {
    super.onDescendantInvalidated(child, target);

    if (!mBitmapMaskInvalidated) {
      View maskView = getChildAt(0);
      if (maskView != null) {
        if (maskView.equals(child)) {
          mBitmapMaskInvalidated = true;
        }
      }
    }
  }

this solves the crashing, but perhaps someone from the MaskedView team could look further into it because I am not 100% sure this is a clean solution. Could someone more experienced also look into this? @Naturalclar @FonDorn

k-ibr avatar Apr 26 '21 09:04 k-ibr

@k-ibr i've created the same patch as you did. But the issue now is, that the mask is not applied during navigation back to previous screen 🤔

Don't know how to resolve this issue.

friedolinfoerder avatar Apr 27 '21 14:04 friedolinfoerder

@friedolinfoerder thanks for also looking into it, def need someone more experienced with Android to have a look at this, at least we know whats going wrong. I’ll look deeper into it as well and will share my thoughts here.

k-ibr avatar Apr 27 '21 14:04 k-ibr

But the issue now is, that the mask is not applied during navigation back to previous screen 🤔

@friedolinfoerder are you using react-native-screens? Probably this project needs same fix like here: https://github.com/react-native-svg/react-native-svg/pull/1542/files

ku8ar avatar Jun 08 '21 21:06 ku8ar

Yes indeed, I use react-native-screens. @ku8ar Thanks for your help, but unfortunately the suggested fix does not change the wrong behavior (mask not applied during back navigation) 😕

friedolinfoerder avatar Jun 10 '21 11:06 friedolinfoerder

I created PR. Thanks @k-ibr for this solution.

khorark avatar Jun 28 '21 12:06 khorark

The fix has been released here: https://github.com/react-native-masked-view/masked-view/releases/tag/v0.2.5

khorark avatar Jun 29 '21 10:06 khorark

that is great thanks a lot for the fix @khorark

k-ibr avatar Jun 29 '21 11:06 k-ibr

image

RN 64 react-navigation 5 react-native-screens "@react-native-masked-view/masked-view": "^0.2.6",

then I press to current Bottom Tab to go to top stack, app crashed on android

my temporary decision

private void updateBitmapMask() { View maskView = getChildAt(0); if (maskView != null) { if (this.mBitmapMask != null) { this.mBitmapMask.recycle(); } maskView.setVisibility(View.VISIBLE); this.mBitmapMask = getBitmapFromView(maskView); maskView.setVisibility(View.INVISIBLE); } }

m4tkv avatar Jul 22 '21 13:07 m4tkv

@k-ibr Thanks for the fix. I have another problem related to this issue Now when I go back from a screen, the MaskedView shows children for a short time (instead of masked view, or nothing)

https://user-images.githubusercontent.com/23259418/147493919-0971a1e1-1170-419b-94f8-d0ec2b44d101.mov

SiSa68 avatar Dec 27 '21 17:12 SiSa68

@k-ibr Thanks for the fix. I have another problem related to this issue Now when I go back from a screen, the MaskedView shows children for a short time (instead of masked view, or nothing)

Screen.Recording.1400-10-06.at.20.50.20.mov

Did you have solution for this? I have the same issue.

highjump0615 avatar May 07 '22 21:05 highjump0615

@highjump0615 @k-ibr Were either of you able to solve this? Thanks!

LucasClaude avatar Jun 01 '22 16:06 LucasClaude

@highjump0615 @k-ibr Were either of you able to solve this? Thanks!

Hey Lucas,

No unfortunately haven't solved or to be honest continued investigating this any longer. We aren't having any of these issued within our project.

P.S. I also recommend looking at RN SKIA, it is a much nicer approach to masks.

goodluck!

k-ibr avatar Jun 01 '22 16:06 k-ibr

@k-ibr Thanks for the fix. I have another problem related to this issue Now when I go back from a screen, the MaskedView shows children for a short time (instead of masked view, or nothing)

Screen.Recording.1400-10-06.at.20.50.20.mov

I had the same problem and solved it this way:

private View prevMaskView = null;
...
private void updateBitmapMask() {
  if (this.mBitmapMask != null) {
    this.mBitmapMask.recycle();
  }

  View maskView = getChildAt(0);
  if (maskView != null) {
    prevMaskView = maskView;
    maskView.setVisibility(View.VISIBLE);
    this.mBitmapMask = getBitmapFromView(maskView);
    maskView.setVisibility(View.INVISIBLE);
  } else {
    prevMaskView.setVisibility(View.VISIBLE);
    this.mBitmapMask = getBitmapFromView(prevMaskView);
    prevMaskView.setVisibility(View.INVISIBLE);
  }
}

maciejbadura avatar Jul 21 '22 14:07 maciejbadura

should close issue if it's fixed

iway1 avatar Nov 08 '23 22:11 iway1