IBM-Watson Asynchronous requests fail

233 Views Asked by At

i am implementing Watson Assistant v2 asynchronous request (with no thread, as it is not required). but i end up with crash for making network call on main thread. which means this call is not called asynchronous on android.

"android.os.NetworkOnMainThreadException" - This exception is thrown when an application attempts to perform a networking operation on its main thread

code:-

  public void sendMessage(String message){
        Log.d("TAG","message :"+message+", session id:"+sessionId);
        MessageInput input = new MessageInput.Builder()
                .messageType("text")
                .text(message)
                .build();
        MessageOptions options = new MessageOptions.Builder(assistanID, sessionId)
                .input(input)
                .build();
        assistant.message(options).enqueue(new ServiceCallback<MessageResponse>() {
            @Override
            public void onResponse(MessageResponse response) {
                System.out.println(response);
                Gson gson = new Gson();

                GsonWatson gsonparse = gson.fromJson(String.valueOf(response), GsonWatson.class);
                mainActivity.messageRecievedFromAssistant(gsonparse.getOutput().getGeneric().get(0).getText());
            }
            @Override
            public void onFailure(Exception e) {

            }
        });
    }





 android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1513)
        at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:117)
        at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:105)
        at java.net.InetAddress.getAllByName(InetAddress.java:1154)
        at okhttp3.Dns$1.lookup(Dns.java:40)
        at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:185)
        at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.java:149)
        at okhttp3.internal.connection.RouteSelector.next(RouteSelector.java:84)
        at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:214)
        at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
        at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
        at okhttp3.RealCall.execute(RealCall.java:77)
        at com.ibm.watson.developer_cloud.service.security.IamTokenManager.callIamApi(IamTokenManager.java:187)
        at com.ibm.watson.developer_cloud.service.security.IamTokenManager.requestToken(IamTokenManager.java:108)
        at com.ibm.watson.developer_cloud.service.security.IamTokenManager.getToken(IamTokenManager.java:78)
        at com.ibm.watson.developer_cloud.service.WatsonService.setAuthentication(WatsonService.java:375)
        at com.ibm.watson.developer_cloud.service.WatsonService.createCall(WatsonService.java:206)
        at com.ibm.watson.developer_cloud.service.WatsonService.createServiceCall(WatsonService.java:240)
        at com.ibm.watson.developer_cloud.assistant.v2.Assistant.message(Assistant.java:151)
        at com.XXX.IBMwatson.sendMessage(IBMwatson.java:78)
        at com.XXX.ibmwatson.MainActivity$onCreate$1.onClick(MainActivity.kt:39)
        at android.view.View.performClick(View.java:6597)
        at android.view.View.performClickInternal(View.java:6574)
        at android.view.View.access$3100(View.java:778)
        at android.view.View$PerformClick.run(View.java:25885)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
  • did some digging in source code of Watson service. one of call which is made in background is run on main thread

class: XXX\files-2.1\com.ibm.watson.developer_cloud\core\6.13.2\673b89ba561c095131da91c327c99800f12b6d9f\core-6.13.2-sources.jar!\com\ibm\watson\developer_cloud\service\security\IamTokenManager.java

method: callIamApi:187

line:187:- okhttp3.Response response = call.execute();

this call is made on main thread.

1

There are 1 best solutions below

0
Logan Patiño On

This is currently a bug in the Java SDK where, as you pointed out, the call to authenticate through IAM is still made on the main thread. This bug is currently documented here.

In the meantime, as a workaround, you can explicitly wrap the call in a new thread. One way to do this is with an AsyncTask. Below is an example:

private class MessageTask extends AsyncTask<String, Void, String> {
  @Override
  protected String doInBackground(String... params) {
    MessageInput input = new MessageInput.Builder()
      .messageType("text")
      .text(params[0])
      .build();
    MessageOptions options = new MessageOptions.Builder(assistantId, sessionId)
      .input(input)
      .build();
    assistant.message(options).enqueue(new ServiceCallback<MessageResponse>() {
      @Override
      public void onResponse(MessageResponse response) {
        Log.d("Response: ", response.toString());
      }
      @Override
      public void onFailure(Exception e) {}
    });
    return "sent message successfully";
  }
}

where you just call it like this:

new MessageTask().execute("This is an example message");