简体   繁体   中英

Why does my Android react native app crash instantly when I try to bridge device listening modules from Java

I have a java module that detects if a magnetic card reader peripheral is attached to an android phone or not. it works fine in the full android version and shows a toast if the peripheral is not connected, this is the working full native java code:

public class MainActivity extends AppCompatActivity {
private SwipeHandler handler;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    run();
}

public void run(){
    SwipeListener listener = new SwipeListener() {

        @Override
        public void onDisconnected(SwipeEvent swipeEvent) {

            Toast someToast = Toast.makeText(getApplicationContext(),"Card is disconnected!", Toast.LENGTH_LONG);
            someToast.show();

        }

        @Override
        public void onConnected(SwipeEvent swipeEvent) {

        }

        @Override
        public void onStarted(SwipeEvent swipeEvent) {

        }

        @Override
        public void onStopped(SwipeEvent swipeEvent) {

        }

        @Override
        public void onReadData(SwipeEvent swipeEvent) {

        }

        @Override
        public void onParseData(SwipeEvent swipeEvent) {

        }

        @Override
        public void onICDetected(SwipeEvent swipeEvent) {

        }
    };

    handler = new SwipeHandler(this);
    handler.addSwipeListener(listener);
    handler.setReadonly(true);
    handler.powerOn();
}

}

Now, after following the module bridging instructions from the react native docs I have written the code below to get this feature into a react native app. The module code:

public class mreaderManager extends ReactContextBaseJavaModule {

    private SwipeHandler handler;

    public mreaderManager(ReactApplicationContext reactContext){

        super(reactContext);

        run();

    }

    //override getName function
    @Override
    public String getName(){
        return "mreaderManager";
    }

    //function body
    @ReactMethod
    public void greetUser(String name, Callback callback){

        String greeting = "Welcome " + name;

        callback.invoke(greeting);

    }

    public void run(){

        //declare swipe listener
        SwipeListener listener = new SwipeListener() {

            @Override
            public void onDisconnected(SwipeEvent swipeEvent) {

                Toast someToast = Toast.makeText(getReactApplicationContext(),"Card is disconnected!", Toast.LENGTH_LONG);
                someToast.show();

            }

            @Override
            public void onConnected(SwipeEvent swipeEvent) {

            }

            @Override
            public void onStarted(SwipeEvent swipeEvent) {

            }

            @Override
            public void onStopped(SwipeEvent swipeEvent) {

            }

            @Override
            public void onReadData(SwipeEvent swipeEvent) {

            }

            @Override
            public void onParseData(SwipeEvent swipeEvent) {

            }

            @Override
            public void onICDetected(SwipeEvent swipeEvent) {

            }
        };

        //instantiate swipe handler
        handler = new SwipeHandler(getReactApplicationContext());
        handler.addSwipeListener(listener);
        handler.setReadonly(true);
        handler.powerOn();

    }

}

and here is the package code:

public class mreaderPackage implements ReactPackage {

    @Override
    public List
            <Class<? extends JavaScriptModule>>
    createJSModules(){
        return Collections.emptyList();
    }

    @Override
    public List
            <ViewManager> createViewManagers(ReactApplicationContext reactContext){
        return Collections.emptyList();
    }

    @Override
    public List
            <NativeModule> createNativeModules(ReactApplicationContext reactContext){
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new mreaderManager(reactContext));

        return modules;
    }

}

The react native app crashes as soon as it opens once I implement this. I noticed it crashes when it instantiates the SwipeHandler that takes context as an argument: handler = new SwipeHandler(getReactApplicationContext()); . What mistake am I making? The app has all the necessary permissions. I would like to mention that when creating the fully native android version, the app was behaving the same way till I stopped using 'Instant Run'.

Crash log from phone(Huawei P8 Lite):

------ SYSTEM LOG (logcat -v threadtime -d *:v) ------ --------- beginning of crash 02-26 17:40:48.669 8024 8024 E AndroidRuntime: FATAL EXCEPTION: main 02-26 17:40:48.669 8024 8024 E AndroidRuntime: Process: com.zynletest, PID: 8024 02-26 17:40:48.669 8024 8024 E AndroidRuntime: java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.HEADSET_PLUG flg=0x40000010 (has extras) } in com.imagpay.bP@5f836e9 02-26 17:40:48.669 8024 8024 E AndroidRuntime: at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:972) 02-26 17:40:48.669 8024 8024 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:743) 02-26 17:40:48.669 8024 8024 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95) 02-26 17:40:48.669 8024 8024 E AndroidRuntime: at android.os.Looper.loop(Looper.java:150) 02-26 17:40:48.669 8024 8024 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5621) 02-26 17:40:48.669 8024 8024 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 02-26 17:40:48.669 8024 8024 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794) 02-26 17:40:48.669 8024 8024 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684) 02-26 17:40:48.669 8024 8024 E AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to read from field 'boolean com.imagpay.bN.i' on a null object reference 02-26 17:40:48.669 8024 8024 E AndroidRuntime: at com.imagpay.SwipeHandler.isReadable(SourceFile:655) 02-26 17:40:48.669 8024 8024 E AndroidRuntime: at com.imagpay.SwipeHandler.powerOff(SourceFile:510) 02-26 17:40:48.669 8024 8024 E AndroidRuntime: at com.imagpay.SwipeHandler.onDisconnected(SourceFile:571) 02-26 17:40:48.669 8024 8024 E AndroidRuntime: at com.imagpay.SwipeHandler.access$0(SourceFile:568) 02-26 17:40:48.669 8024 8024 E AndroidRuntime: at com.imagpay.bP.onReceive(SourceFile:1133) 02-26 17:40:48.669 8024 8024 E AndroidRuntime: at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:962) 02-26 17:40:48.669 8024 8024 E AndroidRuntime: ... 7 more 02-26 17:41:23.274 8348 8348 E AndroidRuntime: FATAL EXCEPTION: main 02-26 17:41:23.274 8348 8348 E AndroidRuntime: Process: com.zynletest, PID: 8348 02-26 17:41:23.274 8348 8348 E AndroidRuntime: java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.HEADSET_PLUG flg=0x40000010 (has extras) } in com.imagpay.bP@ca08f6e 02-26 17:41:23.274 8348 8348 E AndroidRuntime: at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:972) 02-26 17:41:23.274 8348 8348 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:743) 02-26 17:41:23.274 8348 8348 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95) 02-26 17:41:23.274 8348 8348 E AndroidRuntime: at android.os.Looper.loop(Looper.java:150) 02-26 17:41:23.274 8348 8348 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5621) 02-26 17:41:23.274 8348 8348 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 02-26 17:41:23.274 8348 8348 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794) 02-26 17:41:23.274 8348 8348 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684) 02-26 17:41:23.274 8348 8348 E AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to read from field 'boolean com.imagpay.bN.i' on a null object reference 02-26 17:41:23.274 8348 8348 E AndroidRuntime: at com.imagpay.SwipeHandler.isReadable(SourceFile:655) 02-26 17:41:23.274 8348 8348 E AndroidRuntime: at com.imagpay.SwipeHandler.powerOff(SourceFile:510) 02-26 17:41:23.274 8348 8348 E AndroidRuntime: at com.imagpay.SwipeHandler.onDisconnected(SourceFile:571) 02-26 17:41:23.274 8348 8348 E AndroidRuntime: at com.imagpay.SwipeHandler.access$0(SourceFile:568) 02-26 17:41:23.274 8348 8348 E AndroidRuntime: at com.imagpay.bP.onReceive(SourceFile:1133) 02-26 17:41:23.274 8348 8348 E AndroidRuntime: at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:962) 02-26 17:41:23.274 8348 8348 E AndroidRuntime: ... 7 more 02-26 17:42:08.267 8989 8989 E AndroidRuntime: FATAL EXCEPTION: main 02-26 17:42:08.267 8989 8989 E AndroidRuntime: Process: com.zynletest, PID: 8989 02-26 17:42:08.267 8989 8989 E AndroidRuntime: java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.HEADSET_PLUG flg=0x40000010 (has extras) } in com.imagpay.bP@79b169c 02-26 17:42:08.267 8989 8989 E AndroidRuntime: at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:972) 02-26 17:42:08.267 8989 8989 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:743) 02-26 17:42:08.267 8989 8989 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95) 02-26 17:42:08.267 8989 8989 E AndroidRuntime: at android.os.Looper.loop(Looper.java:150) 02-26 17:42:08.267 8989 8989 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5621) 02-26 17:42:08.267 8989 8989 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 02-26 17:42:08.267 8989 8989 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794) 02-26 17:42:08.267 8989 8989 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684) 02-26 17:42:08.267 8989 8989 E AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to read from field 'boolean com.imagpay.bN.i' on a null object reference 02-26 17:42:08.267 8989 8989 E AndroidRuntime: at com.imagpay.SwipeHandler.isReadable(SourceFile:655) 02-26 17:42:08.267 8989 8989 E AndroidRuntime: at com.imagpay.SwipeHandler.powerOff(SourceFile:510) 02-26 17:42:08.267 8989 8989 E AndroidRuntime: at com.imagpay.SwipeHandler.onDisconnected(SourceFile:571) 02-26 17:42:08.267 8989 8989 E AndroidRuntime: at com.imagpay.SwipeHandler.access$0(SourceFile:568) 02-26 17:42:08.267 8989 8989 E AndroidRuntime: at com.imagpay.bP.onReceive(SourceFile:1133) 02-26 17:42:08.267 8989 8989 E AndroidRuntime: at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:962) 02-26 17:42:08.267 8989 8989 E AndroidRuntime: ... 7 more 02-26 17:42:12.375 9074 9074 E AndroidRuntime: FATAL EXCEPTION: main 02-26 17:42:12.375 9074 9074 E AndroidRuntime: Process: com.zynletest, PID: 9074 02-26 17:42:12.375 9074 9074 E AndroidRuntime: java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.HEADSET_PLUG flg=0x40000010 (has extras) } in com.imagpay.bP@79b169c 02-26 17:42:12.375 9074 9074 E AndroidRuntime: at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:972) 02-26 17:42:12.375 9074 9074 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:743) 02-26 17:42:12.375 9074 9074 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95) 02-26 17:42:12.375 9074 9074 E AndroidRuntime: at android.os.Looper.loop(Looper.java:150) 02-26 17:42:12.375 9074 9074 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5621) 02-26 17:42:12.375 9074 9074 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 02-26 17:42:12.375 9074 9074 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794) 02-26 17:42:12.375 9074 9074 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684) 02-26 17:42:12.375 9074 9074 E AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to read from field 'boolean com.imagpay.bN.i' on a null object reference 02-26 17:42:12.375 9074 9074 E AndroidRuntime: at com.imagpay.SwipeHandler.isReadable(SourceFile:655) 02-26 17:42:12.375 9074 9074 E AndroidRuntime: at com.imagpay.SwipeHandler.powerOff(SourceFile:510) 02-26 17:42:12.375 9074 9074 E AndroidRuntime: at com.imagpay.SwipeHandler.onDisconnected(SourceFile:571) 02-26 17:42:12.375 9074 9074 E AndroidRuntime: at com.imagpay.SwipeHandler.access$0(SourceFile:568) 02-26 17:42:12.375 9074 9074 E AndroidRuntime: at com.imagpay.bP.onReceive(SourceFile:1133) 02-26 17:42:12.375 9074 9074 E AndroidRuntime: at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:962) 02-26 17:42:12.375 9074 9074 E AndroidRuntime: ... 7 more 02-26 17:42:40.481 9207 9207 E AndroidRuntime: FATAL EXCEPTION: main 02-26 17:42:40.481 9207 9207 E AndroidRuntime: Process: com.zynletest, PID: 9207 02-26 17:42:40.481 9207 9207 E AndroidRuntime: java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.HEADSET_PLUG flg=0x40000010 (has extras) } in com.imagpay.bP@ca08f6e 02-26 17:42:40.481 9207 9207 E AndroidRuntime: at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:972) 02-26 17:42:40.481 9207 9207 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:743) 02-26 17:42:40.481 9207 9207 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95) 02-26 17:42:40.481 9207 9207 E AndroidRuntime: at android.os.Looper.loop(Looper.java:150) 02-26 17:42:40.481 9207 9207 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5621) 02-26 17:42:40.481 9207 9207 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 02-26 17:42:40.481 9207 9207 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794) 02-26 17:42:40.481 9207 9207 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684) 02-26 17:42:40.481 9207 9207 E AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to read from field 'boolean com.imagpay.bN.i' on a null object reference 02-26 17:42:40.481 9207 9207 E AndroidRuntime: at com.imagpay.SwipeHandler.isReadable(SourceFile:655) 02-26 17:42:40.481 9207 9207 E AndroidRuntime: at com.imagpay.SwipeHandler.powerOff(SourceFile:510) 02-26 17:42:40.481 9207 9207 E AndroidRuntime: at com.imagpay.SwipeHandler.onDisconnected(SourceFile:571) 02-26 17:42:40.481 9207 9207 E AndroidRuntime: at com.imagpay.SwipeHandler.access$0(SourceFile:568) 02-26 17:42:40.481 9207 9207 E AndroidRuntime: at com.imagpay.bP.onReceive(SourceFile:1133) 02-26 17:42:40.481 9207 9207 E AndroidRuntime: at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:962) 02-26 17:42:40.481 9207 9207 E AndroidRuntime: ... 7 more

UPDATE:

After pondering the situation some more, I notice that the imagpay library is using the headphone plug to do it's thing and that the HEADSET_PLUG intent is "sticky". This means HEADSET_PLUG intents can hang around in the system and be received by an application as soon as it registers a receiver. This might explain why these events are generating errors if they turn up while the SwipeHander is still constructing itself. So a possible approach to solve this (assuming the above analysis is right) is to read off the existing intents before creating the new SwipeHandler. Here is an example that might work (taken from here ):

    ...
    // Register a receiver for a little while.
    IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
    myReceiver = new IgnorantIntentReceiver();
    registerReceiver(myReceiver, filter);
    // Give it a moment to deliver the intents.
    Thread.sleep(300);
    unregisterReceiver(myReceiver);

    //instantiate swipe handler
    handler = new SwipeHandler(getReactApplicationContext());
    handler.addSwipeListener(listener);
    handler.setReadonly(true);
    handler.powerOn();

}

private class IgnorantIntentReceiver extends BroadcastReceiver {
@Override public void onReceive(Context context, Intent intent) {
    if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
        int state = intent.getIntExtra("state", -1);
        switch (state) {
        case 0:
            Log.d(TAG, "Headset is unplugged");
            break;
        case 1:
            Log.d(TAG, "Headset is plugged");
            break;
        default:
            Log.d(TAG, "I have no idea what the headset state is");
        }
    }
}
}

NOTE: I think the creation, registering and unregistering should perhaps be moved to the onStart() and onStop() lifecycle methods of the Activity. See here .


From the logcat, the error is being caused by receiving a NullPointerException in your SwipeHandler class. You have not posted the code for the SwipeHandler class, so I cannot diagnose further. The issue is happening here:

com.imagpay.SwipeHandler.isReadable(SourceFile:655)

It is trying to work out the state from a null object within the isReadable method.

It could be that the imagpay library was developed to be used in an Android application and not specifically a React Native application. In this case, the problem may stem from the way you are creating the SwipeHandler in each case. There are 2 places in the code above where you initialize a SwipeHandler, one of them is for the React Native version:

handler = new SwipeHandler(getReactApplicationContext());

Perhaps you could try to give it a reference to the actual Android application context. Something like:

 handler = new SwipeHandler(getReactApplicationContext().getBaseContext());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM