5

Unity3d エンジンで Android 用のアプリケーションを開発しています。このアプリケーションは、ネットワーク ソケット経由で PC 上のサーバーに接続する必要があります。Android 用の Unity3d プラグインの例をいくつか見つけました。それらに基づいて、Unity3d 用の c# と Android 用の Java でいくつかのコードを作成しました。Android アプリケーションの UI スレッドでネットワーク操作を実行してはならないことがわかりました。そのため、ネットワーク リクエストには AsynTask を使用する必要があります。また、C# スクリプトから非静的メソッドを呼び出そうとしましたが、データが返されません。静的呼び出しのみが Java アプリケーションからデータを返します。したがって、私の AsyncTask クラスは静的です。しかし、ネットワーク経由でデータを取得するために AsyncTask ジョブで静的関数を呼び出すと、アプリケーションがクラッシュします。エラーが発生します。問題を解決するのを手伝ってくれませんか? この問題を解決するには、次の 2 つの方法があります。1) Unity3d の c# コードを変更して、非静的メソッド呼び出しを介してデータを取得します。Java コードですべてのメソッドを非静的に変更します。2) 静的メソッドと静的 AsyncTask で動作するように Java コードを変更します。

私のC#スクリプト 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");
        }
    }
}

私の Java スクリプト 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;
    }   
}

デバッグ メッセージ:

    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
4

1 に答える 1

2

まず、Update 関数で Android コードを呼び出すのはなぜですか? フレームごとに呼び出されるため。

おそらく、ネイティブ コードが実行されていることを示すフラグを設定し、それを 2 回呼び出さないでください。

あなたの問題については、私が知る限り、AsyncTask の作成とタスクの実行は UI スレッド内で呼び出す必要があります。問題は次のとおりです。

  1. UnityAndroidClientPlugin.GetDataのメソッド内で静的メソッドを呼び出します。Update私の知る限り、それは Android の UI スレッドと同じスレッドではありません。つまり、Unity の独自のスレッド内で呼び出して、次のようにします。
  2. Unity3d のスレッド内で AsyncTask を作成して実行するため、エラーになります。

私の解決策は次のとおりです(試すことができます):

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

}
于 2013-10-04T08:21:44.497 に答える