Pyjnius传递PythonJavaClass至Java函数出现JNI无效对象错误
Alright, let's break down why you're hitting this JNI error and fix it step by step. The root problem is that your NokeServiceListener instance isn't being properly wrapped as a valid Java proxy object, plus a couple of small but critical mistakes in your method calls and variable handling.
1. Fix the NokeServiceListener Initialization
Your custom listener class inherits from PythonJavaClass, but you're not calling the parent class constructor. This is essential for jnius to properly create the underlying Java proxy object. Update your listener's __init__ method to initialize the parent class and avoid reliance on global variables:
class NokeServiceListener(PythonJavaClass): __javainterfaces__ = ['com.noke.nokemobilelibrary.NokeServiceListener'] __javacontext__ = 'app' def __init__(self, noke_service): super(NokeServiceListener, self).__init__() # Critical: Initialize parent class self.mNokeService = noke_service # Store service instance locally
2. Fix the Mismatched connectToNoke Call
In your onNokeDiscovered method, you're passing self as an extra parameter to connectToNoke, but the Java method only expects a NokeDevice. This mismatched signature will trigger JNI errors:
@java_method('(Lcom/noke/nokemobilelibrary/NokeDevice;)V') def onNokeDiscovered(self,noke): print "Connecting to Noke" # Remove the extra `self` argument here self.mNokeService.connectToNoke(noke)
3. Ensure Service Interactions Run on the UI Thread
The onServiceConnected callback runs on a binder thread, not the main UI thread. jnius requires Java proxy objects to be created on the UI thread to have a valid Android context. Add the run_on_ui_thread decorator to your callback method:
First, make sure you have the import:
from android.runnable import run_on_ui_thread
Then update the onServiceConnected method:
@run_on_ui_thread @java_method('(Landroid/content/ComponentName;Landroid/os/IBinder;)V') def onServiceConnected(self,className, rawBinder): print 'debug1' nokeService = cast('com.noke.nokemobilelibrary.NokeDeviceManagerService$LocalBinder',rawBinder) global mNokeService mNokeService = nokeService.getService() print mNokeService print 'debug2' # Pass the service instance to the listener mNokeServiceListener = NokeServiceListener(mNokeService) print mNokeServiceListener print 'debug2.5' mNokeService.registerNokeListener(mNokeServiceListener) print 'debug3' noke1 = NokeDevice("NOKE3P", "F7:F3:F1:2C:66:25") print 'debug4' mNokeService.addNokeDevice(noke1) print 'debug5' mNokeService.setUploadUrl("https://coreapi-sandbox.appspot.com/upload/") print 'debug6' mNokeService.startScanningForNokeDevices() print "Scanning for devices" if not mNokeService.initialize(): print "Unable to initialize Bluetooth"
4. Verify All Method Signatures Match Exactly
Double-check your @java_method decorators to ensure they perfectly match the Java interface's method signatures. For example:
onBluetoothStatusChangeduses(I)Vwhich correctly matchesvoid onBluetoothStatusChanged(int bluetoothStatus)onErroruses(Lcom/noke/nokemobilelibrary/NokeDevice;ILjava/lang/String;)Vwhich aligns withvoid onError(NokeDevice noke, int error, String message)
Why This Works
- Calling
super().__init__()triggers jnius's logic to create a valid Java proxy object, fixing the "invalid jobject" error. - Removing the extra parameter aligns your method call with the Noke library's expected signature.
- Running on the UI thread ensures the Java proxy has a valid Android context, which is required for interacting with the Noke service.
After making these changes, your listener should be recognized as a valid Java object, and the registerNokeListener call should succeed without the JNI error.
内容的提问来源于stack exchange,提问作者GoBig06

