Android: добавление представления Java в представление OpenGl

Я перенес свое приложение для iPhone на Android, используя ndk и cocos2dx. Это работает как шарм, и я думаю, что cocos2dx очень крут!

Теперь я хотел бы добавить несколько представлений Java к моему основному представлению opengl в среде Java. И это не совсем работает для меня. Я думаю, что мне нужны базовые знания о представлениях, действиях, намерениях и т. Д., Работающих в среде Java.

Чтобы быть конкретным, мне нужно добавить TextView (java) в мое представление opengl во время выполнения. Я пробовал следующее, но он падает, когда я вызываю функцию void testSetText().

public class myTest extends Cocos2dxActivity{
    private static final String TAG = "MY_TEST";

    private FrameLayout mainFrame; 
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        Log.e(TAG, "onCreate");

        String packageName = getApplication().getPackageName();
        super.setPackageName(packageName);

        mainFrame = new FrameLayout(this);

        mGLView = new Cocos2dxGLSurfaceView(this);

        mainFrame.addView(mGLView);

        RelativeLayout base = new RelativeLayout(this);
        base.addView(mainFrame);
        setContentView(base);

    }

    private GLSurfaceView mGLView;

    static {
        System.loadLibrary("cocos2d");
        System.loadLibrary("cocosdenshion");
        System.loadLibrary("game");
    }

     @Override
     protected void onPause() {         
         super.onPause();
         Log.i("TAG"," onPause");         
         mGLView.onPause();

     }

     @Override
     protected void onResume() {         
         super.onResume();
         Log.i("TAG"," onResume");         
         mGLView.onResume();
     }

    @Override
    protected void onStart() {
        // TODO Auto-generated method stub                
        super.onStart();
        Log.e(TAG, "onStart");

    }

    @Override
    protected void onStop() {
        // TODO Auto-generated method stub        
        super.onStop();        
        Log.e(TAG, "onStop");
    }

    public void testSetText(){
        Log.e(TAG, "testSetText");    

        TextView textView = new TextView(this);         
        textView.setText("Hello, Android");

        LinearLayout testLayout = new LinearLayout(this);

        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);        
        lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        testLayout.addView(textView ,lp);
        mainFrame.addView(testLayout);

    }
}

И если вместо этого я попытаюсь запустить другую активность или вызвать setContentView(R.layout.test_screen) в function public void testSetText(), моя игра также вылетит.

Может ли кто-нибудь дать мне хороший совет здесь?

ОБНОВЛЕНИЕ:
Спасибо, Макарс, вот трассировка стека:

08-16 15:19:52.121: INFO/TAG(8352):  canITalktoPIT 
08-16 15:19:52.121: ERROR/MY_APP(8352): test call PIT 2
08-16 15:19:52.203: WARN/dalvikvm(8352): threadid=11: thread exiting with uncaught exception (group=0x40015560)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352): FATAL EXCEPTION: GLThread 10
08-16 15:19:52.214: ERROR/AndroidRuntime(8352): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at android.view.ViewRoot.checkThread(ViewRoot.java:2932)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at android.view.ViewRoot.requestLayout(ViewRoot.java:629)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at android.view.View.requestLayout(View.java:8267)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at android.view.View.requestLayout(View.java:8267)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at android.view.View.requestLayout(View.java:8267)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:257)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at android.view.View.requestLayout(View.java:8267)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at android.view.ViewGroup.addView(ViewGroup.java:1869)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at android.view.ViewGroup.addView(ViewGroup.java:1851)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at dk.comp.testApp.testAppB.calling(testAppB.java:289)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at dk.comp.testApp.SigletonJohn.canITalktoPIT(SigletonJohn.java:43)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at org.cocos2dx.lib.testAppJavaCppComunication.pitTestJNI(testAppJavaCppComunication.java:47)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at org.cocos2dx.lib.Cocos2dxActivity.pitTestJNI(Cocos2dxActivity.java:177)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at org.cocos2dx.lib.Cocos2dxRenderer.nativeTouchesEnd(Native Method)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at org.cocos2dx.lib.Cocos2dxRenderer.handleActionUp(Cocos2dxRenderer.java:49)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at org.cocos2dx.lib.Cocos2dxGLSurfaceView$9.run(Cocos2dxGLSurfaceView.java:288)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1326)
08-16 15:19:52.214: ERROR/AndroidRuntime(8352):     at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1118)
08-16 15:19:52.238: WARN/ActivityManager(116):   Force finishing activity dk.comp.testApp/.testAppB
08-16 15:19:52.242: INFO/SOUND(8352):  PAUSE 
08-16 15:19:52.246: INFO/TAG(8352):  onPause



ОБНОВЛЕНИЕ #2:
Хорошо, я все еще работаю над этой проблемой и просто не могу ее исправить :( Но я обнаружил кое-что интересное:

Итак, чтобы подвести итог моей проблемы: в моем приложении для Android работает сцена cocos2dx, которая работает отлично. Затем, когда пользователь нажимает кнопку:

myBut = CCMenuItemImage::itemFromNormalImage("some.png", "some.png.png", this, menu_selector(Cocos2dMenuScene::butPushed));

Я вызываю среду Java через JNI и прошу добавить какое-то представление (например, TextView) (см. testSetText()). В этот момент мое приложение вылетает - с крашлогом:

ПРЕДУПРЕЖДЕНИЕ/dalvikvm(8352): threadid=11: поток завершается с необработанным исключением (группа=0x40015560) 08-16 15:19:52.214: ОШИБКА/AndroidRuntime(8352): НЕИСПРАВНОЕ ИСКЛЮЧЕНИЕ: GLThread 10 08-16 15:19:52.214 : ОШИБКА/AndroidRuntime (8352):

Теперь я также использую Admob, который интегрирован в конец Java. Когда Admob вызывает мой основной класс (myTest, см. выше) через какого-то делегата (например, onReceiveAd) — я пытался вызвать testSetText() и добавить свой TextView в этот момент — и все работает нормально!

Так что я думаю, что это как-то связано с многопоточностью. Но я не специалист в этой области, поэтому мне очень нужна небольшая помощь.

Какие-либо предложения?


person tomas    schedule 13.08.2011    source источник
comment
Добавьте трассировку стека, пожалуйста.   -  person mibollma    schedule 14.08.2011
comment
Эй, братан, можешь поделиться своим кодом для этого. Я тоже застрял в той же проблеме, я тоже хочу то же самое. Было бы здорово помочь!!!   -  person user1169079    schedule 05.07.2012
comment
Я также пытаюсь интегрировать admob, но не могу понять, как мне получить доступ к моему объявлению в сценах ?? Я надеюсь, что вы можете помочь мне с тем же   -  person user1169079    schedule 05.07.2012


Ответы (3)


У меня такая же проблема, но я только что исправил и понял, что случилось с андроидом и cocos2d-x.

По сути, в системе Android только основной поток, создающий пользовательский интерфейс, может обновлять сам пользовательский интерфейс.

Поэтому вам нужно использовать обработчик и сообщение, чтобы сообщить основному потоку об обновлении пользовательского интерфейса.

И еще, когда вы вызываете java-метод функциями c/c++ через JNI.

Статический метод может быть лучшим выбором, и вы можете сначала захватить JavaVM и получить статический метод с помощью этой JavaVM и env.

Надеюсь, это поможет вам.

person user865007    schedule 02.11.2011

Возможно, это уже слишком поздно, я не знаком с NDK, но из трассировки стека я могу понять, что ваша проблема заключается в попытке добавить представление из потока OpenGL (как указано в журнале, это поток 11). Вам нужно запустить этот метод в потоке пользовательского интерфейса следующим образом:

public void testSetText(){
    runOnUiThread(new Runnable() {

        @Override
        public void run() {
           Log.e(TAG, "testSetText");    

           TextView textView = new TextView(this);         
           textView.setText("Hello, Android");

           LinearLayout testLayout = new LinearLayout(this);

           RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);        
           lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
           testLayout.addView(textView ,lp);
           mainFrame.addView(testLayout);
        }
    });
}
person Sergio R. Lumley    schedule 18.12.2013

Я нашел это, и я хотел сделать это немного проще для всех, так как для тех, кто приходит сюда, вы, вероятно, ищете быстрый полный ответ, подробно описывающий процесс. Вот пример реализации.

import android.os.Handler;
import android.os.Message;
import android.os.Bundle;

Этот код выполняется вашим основным потоком:

// In main thread
Handler handler = new Handler(new Handler.Callback() {
    public boolean handleMessage(Message message) {
        Bundle bundle = message.getData();
        switch (bundle.getInt("type")) {
             case 0:
                String txt = bundle.getString("text");
                my_text_view.setText(txt);
                break;
        }
        return true;
    }
});

Этот код выполняется другим потоком, желающим поговорить с основным потоком:

// In other thread.
Message msg = handler_variable_passed_to_thread.obtainMessage();
Bundle bundle = new Bundle();
bundle.putInt("type", 0);
bundle.putString("text", "hello world!");

Система доставит сообщение и вызовет обратный вызов в потоке, который создал Handler для обратного вызова, что даст вам доступ к ресурсам этого потока. Это также можно использовать для многих других целей, и это очень быстрый способ передачи сообщений. Это не ограничивается взаимодействием потоков пользовательского интерфейса.

person Community    schedule 06.05.2015