Start a new topic

sendJsonObject and setJSONObjectReceivedCallback

Hello team wikitude,

I am having a problem with the sendJsonObject method.
Using the flutter plugin, version of sdk is 8.7.

All I am doing right now is calling the sendJsonObject like this when I am clicking something:

 

AR.platform.sendJSONObject({
            action: "back"
        });

 

That breaks the app immediately with the following error message:

 FATAL EXCEPTION: JsWorker
Process: com.example.playground_wikitude, PID: 7851
java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread. Current thread: JsWorker
       at io.flutter.embedding.engine.FlutterJNI.ensureRunningOnMainThread(FlutterJNI.java:794)
       at io.flutter.embedding.engine.FlutterJNI.dispatchPlatformMessage(FlutterJNI.java:684)
       at io.flutter.embedding.engine.dart.DartMessenger.send(DartMessenger.java:80)
       at io.flutter.embedding.engine.dart.DartExecutor.send(DartExecutor.java:189)
       at io.flutter.view.FlutterNativeView.send(FlutterNativeView.java:155)
       at io.flutter.plugin.common.MethodChannel.invokeMethod(MethodChannel.java:98)
       at io.flutter.plugin.common.MethodChannel.invokeMethod(MethodChannel.java:84)
       at com.wikitude.wikitude_plugin.ArchitectWidget.onJSONObjectReceived(ArchitectWidget.java:324)
       at com.wikitude.architect.CallbackHandler.forwardJSONObject(SourceFile:317)
       at com.wikitude.architect.PlatformBridge.callAsyncImplInternal(Native Method)
       at com.wikitude.architect.PlatformBridge.callAsyncImpl(SourceFile:134)
       at com.wikitude.architect.PlatformBridge$a.a(SourceFile:66)
       at com.wikitude.architect.PlatformBridge$a.run(SourceFile:40)
Activity com.example.playground_wikitude.MainActivity has leaked IntentReceiver com.wikitude.architect.ArchitectView$NetworkStateReceiver@9284686 that
o unregisterReceiver()?
android.app.IntentReceiverLeaked: Activity com.example.playground_wikitude.MainActivity has leaked IntentReceiver com.wikitude.architect.ArchitectView
red here. Are you missing a call to unregisterReceiver()?
       at android.app.LoadedApk$ReceiverDispatcher.<init>(LoadedApk.java:1351)
       at android.app.LoadedApk.getReceiverDispatcher(LoadedApk.java:1132)
       at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1421)
       at android.app.ContextImpl.registerReceiver(ContextImpl.java:1394)
       at android.app.ContextImpl.registerReceiver(ContextImpl.java:1382)
       at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:609)
       at com.wikitude.architect.ArchitectView.h(SourceFile:596)
       at com.wikitude.architect.ArchitectView.onPostCreate(SourceFile:579)
       at com.wikitude.wikitude_plugin.ArchitectWidget.onMethodCall(ArchitectWidget.java:157)
       at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:222)
       at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:96)
       at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:643)
       at android.os.MessageQueue.nativePollOnce(Native Method)
       at android.os.MessageQueue.next(MessageQueue.java:325)
       at android.os.Looper.loop(Looper.java:142)
       at android.app.ActivityThread.main(ActivityThread.java:6543)
       at java.lang.reflect.Method.invoke(Native Method)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

 

What I want to achieve is, when the user clicks on let's say a point of interest, to send a JSON object to flutter, which then does some stuff with it...


Thanks in advance!


Great Matthew!

thank you very much!


Solved it. In ArchitectWidget.java:


import android.os.Handler;

import android.os.Looper;


@Override

    public void onJSONObjectReceived(final JSONObject jsonObject) {

        

final Handler handler = new Handler(Looper.getMainLooper());

handler.post(new Runnable() {

@Override

public void run() {

channel.invokeMethod("jsonObjectReceived", jsonObject.toString());

}

});

    }


2 people like this

I'm getting this issue too.

I've the same problem on Android, I set the callback in onArchitectWidgetCreated function 

Future<void> onArchitectWidgetCreated() async {
    this.architectWidget
        .load("samples/01_ImageTracking_1_ImageOnTarget/index.html", () {
      print("ar works");
    }, (string) {
      print(string);
    });
    this.architectWidget.setJSONObjectReceivedCallback((jsonObjectReceived) {
      print(jsonObjectReceived.toString());
      
    });
    this.architectWidget.resume();

  }

 The error is always 

 

java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread. Current thread: JsWorker
E/AndroidRuntime(15716): 	at io.flutter.embedding.engine.FlutterJNI.ensureRunningOnMainThread(FlutterJNI.java:794)

 

I think the problem is related to incorrect thread management in the flutter plugin Android implementation.

The problem is probably similar to the one in this post https://github.com/flutter/flutter/issues/34993

Being able to communicate with the rest of the flutter application is essential for the development of a non-demo app.

I hope that those who developed it will find the solution


1 person likes this

 Hello,

I have found the implementation in Flutter that you provided, where the

 Future<void> onJSONObjectReceived(Map<String, dynamic> jsonObject) async

 

 is marked as async.

That once again results in the exception I posted initially.

Would you check this behaviour?

Thanks!


1 person likes this

... so it seems my actual problem lies in implementing the setJSONObjectReceivedCallback(). It causes the app to break, without it I am just told that I should

Use architectView.addArchitectJavaScriptInterfaceListener to receive the data.

 

... which is what I want to do with this:

this.architectWidget.setJSONObjectReceivedCallback(pleaseWork);

 

Fast forward 10 minutes.


Apparently I put the setJSONObjectReceivedCallback() in a async method, causing it to break the app.

However, now I am setting it in the initState().

I am still told:

forwardJSONObject: There are no ArchitectJavaScriptInterfaceListener set.
Use architectView.addArchitectJavaScriptInterfaceListener to receive the data.

 

Can you give me an example of a correct implementation of that?


Thanks ind advance!

Oh, and I have tried the samples, they kinda work, I just couldn't find the missing piece.

Login or Signup to post a comment