Unity3d Android Plugin AsyncTask Static Problem

I am developing an android application on the Unity3d engine. This application should connect to my server on a PC via network sockets. I found some examples of Unity3d plugins for Android. Based on them, I wrote code in C # for Unity3d and Java for Android. I found out that network operations should not be performed in the user interface in an Android application. Therefore, I have to use AsynTask for network requests. I also tried calling non-static methods from C # script, but they did not return any data. Only static calls return data from a java application. Therefore, my AsyncTask class is static. But when I call a static function with the AsyncTask task to receive data over the network, my application crashes. I get errors.Could you help me solve my problems? I see two ways to solve this problem: 1) Change my C # code for Unity3d to get data through non-static method calls. Change all methods to Non-Static in Java code. 2) Change my Java code to work with static methods and static AsyncTask.

My C # script AndroidClientPlugin.cs:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;

public class AndroidClientPlugin : MonoBehaviour {
    private float TEST;

    private AndroidJavaClass cls_UnityPlayer;
    private AndroidJavaObject obj_Activity;
    private AndroidJavaClass cls_CompassActivity;
    // Use this for initialization
    void Start () {

        AndroidJNI.AttachCurrentThread();
        cls_UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        obj_Activity = cls_UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
        cls_CompassActivity = new AndroidJavaClass("com.lab.Android.AndroidClientPlugin");

        cls_CompassActivity.SetStatic<String>("ServerAddressValue", "192.168.1.5");
        cls_CompassActivity.SetStatic<String>("ServerPortValue", "8881");

    }
    void OnGUI() {
        GUI.Label(new Rect(Screen.width / 2 -200, Screen.height / 2, 400,100), "x = " + TEST.ToString());
    }
    void Update()
    {
        if(cls_CompassActivity.CallStatic<bool>("GetData"))
        {
            TEST = cls_CompassActivity.CallStatic<float>("getPosX");
        }
    }
}

My Java script is AndroidClientPlugin.java:

package com.lab.Android;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Looper;
import android.os.StrictMode;
import android.util.Log;
import android.content.Context;
import android.content.Intent;
import android.app.Activity;

public class AndroidClientPlugin  extends UnityPlayerActivity {

    //Server address parameters
    public  static String ServerAddressValue;
    public  static String ServerPortValue;
    //Tracker parameters
    public  static String vServerName;
    public  static String vSensorNumber;

    private  static SensorData vTaskResult;

    public static cTask BackgroundTask;

    @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        //set thread strict mode off
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);

        vTaskResult = new SensorData(); 
        ServerAddressValue = "192.168.1.5";
        ServerPortValue = "8881";
        vServerName = "Tracker0";
        vSensorNumber = "0";       
        BackgroundTask = new cTask();        
    }

    @Override
    protected void onResume()
    {
        super.onResume();
    }

    @Override
    protected void onStop()
    {
        super.onStop();
    }

    public static boolean GetData()
    {    
        cTaskResult taskResult = new cTaskResult();
        taskResult = BackgroundTask.DoAsyncTask(ServerAddressValue, ServerPortValue, vServerName, vSensorNumber);
        vTaskResult = taskResult.ResultData;
        return taskResult.DataIsReady;
    }


    public static class cTaskResult
    {
        public boolean DataIsReady;
        public SensorData ResultData;
        public cTaskResult()
        {
            DataIsReady = false;
            ResultData = new SensorData();  
        }   
    }

    public static class cTask
    {       
        public cTask()
        {               
        }
        public cTaskResult DoAsyncTask(String serverAddress, String serverPort, String trackerName, String trackerSensorNumber)
        {
            cTaskResult Result = new cTaskResult();     
            GetDataTask Task;
            Task = new GetDataTask();       
            Task.execute(serverAddress, serverPort, trackerName, trackerSensorNumber, Result);          
            try {
                Result = Task.get(1, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (TimeoutException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return Result;          
        }

        public static class GetDataTask extends AsyncTask<Object, Void, cTaskResult> 
        {
            @Override
            protected void onPreExecute() {
              super.onPreExecute();
            }

            @Override
            protected cTaskResult doInBackground(Object... params) {
                cTaskResult TMPData = new cTaskResult();
                //doing network requests
                //TMPData.DataIsReady = NetClient.getInstance().GetData((String)params[0], (String)params[1], (String)params[2],  Integer.valueOf((String)params[3]), TMPData.ResultData);
                //TMPData is a result of network operations
                TMPData.DataIsReady = true;
                TMPData.ResultData = new SensorData();

                return TMPData;
            }

            @Override
            protected void onPostExecute(cTaskResult result) {
              super.onPostExecute(result);
            }
          }
    }

    public static float getPosX()
    {
        return vTaskResult.posX;
    }   
}

Debug messages:

    09-11 12:56:05.514: E/CMarlinMediator(137): Error : MarlinMediator Failed to get TrustedTime
09-11 12:56:05.594: E/CMarlinMediator(137): Error : MarlinMediator Failed to get TrustedTime
09-11 12:56:12.184: E/Adreno200-EGL(7590): <qeglDrvAPI_eglGetConfigAttrib:484>: EGL_BAD_ATTRIBUTE
09-11 12:56:12.184: E/Adreno200-EGL(7590): <qeglDrvAPI_eglGetConfigAttrib:484>: EGL_BAD_ATTRIBUTE
09-11 12:56:12.184: E/Adreno200-EGL(7590): <qeglDrvAPI_eglGetConfigAttrib:484>: EGL_BAD_ATTRIBUTE
09-11 12:56:14.304: E/AndroidRuntime(7590): FATAL EXCEPTION: GLThread 741
09-11 12:56:14.304: E/AndroidRuntime(7590): java.lang.ExceptionInInitializerError
09-11 12:56:14.304: E/AndroidRuntime(7590):     at com.lab.Android.AndroidClientPlugin$cTask.DoAsyncTask(AndroidClientPlugin.java:128)
09-11 12:56:14.304: E/AndroidRuntime(7590):     at com.lab.Android.AndroidClientPlugin.GetData(AndroidClientPlugin.java:79)
09-11 12:56:14.304: E/AndroidRuntime(7590):     at com.unity3d.player.UnityPlayer.nativeRender(Native Method)
09-11 12:56:14.304: E/AndroidRuntime(7590):     at com.unity3d.player.UnityPlayer.onDrawFrame(Unknown Source)
09-11 12:56:14.304: E/AndroidRuntime(7590):     at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1462)
09-11 12:56:14.304: E/AndroidRuntime(7590):     at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1216)
09-11 12:56:14.304: E/AndroidRuntime(7590): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
09-11 12:56:14.304: E/AndroidRuntime(7590):     at android.os.Handler.<init>(Handler.java:121)
09-11 12:56:14.304: E/AndroidRuntime(7590):     at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:607)
09-11 12:56:14.304: E/AndroidRuntime(7590):     at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:607)
09-11 12:56:14.304: E/AndroidRuntime(7590):     at android.os.AsyncTask.<clinit>(AsyncTask.java:190)
09-11 12:56:14.304: E/AndroidRuntime(7590):     ... 6 more
09-11 12:56:15.194: E/CMarlinMediator(137): Error : MarlinMediator Failed to get TrustedTime
09-11 12:56:15.234: E/CMarlinMediator(137): Error : MarlinMediator Failed to get TrustedTime
+5
source share
1 answer

First of all, why are you calling the Android code in the update function? Since it will be called every frame.

Maybe you should put some flag that indicates that your own code is running, and did not call it twice.

And about your problem, as far as I know, creating AsyncTask and starting a task should be called in UI-Thread. Problems:

  • You are invoking a static method AndroidClientPlugin.GetDatain a method Updatein Unity. As far as I know, this is not the same thread with the UI-Thread of android. So you named it in your own Unity thread and:
  • You create and run AsyncTask in a Unity3d stream, so this will be an error.

( ):

public static void GetData()
{    
    //this will be called on UIThread of Android
    com.unity3d.player.UnityPlayer.currentActivity.runOnUiThread(new Runnable(){
        public void run(){
            cTaskResult taskResult = new cTaskResult();
            taskResult = BackgroundTask.DoAsyncTask(ServerAddressValue, ServerPortValue, vServerName, vSensorNumber);
            vTaskResult = taskResult.ResultData;
                com.unity3d.player.UnityPlayer.currentActivity.SendMessage("YourGameObjectName", "YourMethodName", taskResult.DataIsReady);
            //return taskResult.DataIsReady;    
        }
    });

}
+1

All Articles