2012-09-11 12 views
5

Estoy desarrollando una aplicación para Android en el motor Unity3d. Esta aplicación debe conectarse a mi servidor en la PC a través de conectores de red. Encontré algunos ejemplos de complementos de Unity3d para Android. Basándome en ellos, he escrito un código en C# para Unity3d y en Java para Android. Descubrí que las operaciones de red no deben ejecutarse en UI-thread en la aplicación de Android. Así que tengo que usar AsynTask para las solicitudes de red. También intenté llamar a métodos no estáticos desde el script C# pero no devuelven ningún dato. Solo las llamadas estáticas devuelven datos de la aplicación Java. Entonces mi clase AsyncTask es estática. Pero cuando llamo a la función estática con el trabajo AsyncTask para obtener datos a través de la red, mi aplicación se cuelga. Recibo errores ¿Podrías ayudarme a solucionar mis problemas? Veo dos maneras de solucionar este problema: 1) Cambiar mi código C# para Unity3d para obtener datos a través de llamadas al método no estático. Cambie todos los métodos a No estático en el código de Java. 2) Cambiar mi código Java para trabajar con métodos estáticos y AsyncTask estático.Unity3d complemento de Android estático AsyncTask número

Mi C# AndroidClientPlugin.cs de script:

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"); 
     } 
    } 
} 

Mi Java Script 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; 
    } 
} 

mensajes de depuración:

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 

Respuesta

1

En primer lugar, ¿por qué se llama Android código en la función Actualizar? Como se llamará cada cuadro.

Quizás deba poner un indicador que indique que el código nativo se está ejecutando, y no lo haya llamado dos veces.

Y sobre su problema, hasta donde yo sé, la creación de AsyncTask y la ejecución de tareas deben ser llamadas dentro de la UI-Thread. Los problemas son:

  1. usted llama método estático AndroidClientPlugin.GetData dentro del método Update en la Unidad. Por lo que yo sé, ese no es el mismo hilo con el UI-Thread of android. Así que lo llamó dentro del propio subproceso de Unity, y:
  2. Crea y ejecuta AsyncTask dentro del subproceso de Unity3d, por lo que será un error.

Mi solución es (se puede probar):

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;  
     } 
    }); 

} 
Cuestiones relacionadas