Android: adding Java View to OpenGl View

I ported my iphone application to android using ndk and cocos2dx. It works like a charm, and I think cocos2dx is very cool!

Now I would like to add some Java views to my main opengl view in the Java environment. And it does not work for me. I think I need basic knowledge of how Java has views, actions, intent, etc.

To be specific, I need to add a TextView (java) to my opengl view at runtime. I tried the following, but it will work when I call the void function 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); } } 

And if instead I try to run another action - or call setContentView(R.layout.test_screen) in function public void testSetText() , my game will also function public void testSetText() .

Can anyone give me some good advice?

UPDATE:
Thanks to Macara, here is the stack trace:

 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 



UPDATE # 2:
Ok, I'm still working on this problem and just can't fix it :( But I found out something interesting:

So, to summarize my problem: In my Android application there is a scene with the cocos2dx effect that works fine. Then, when the user clicks the button:

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

I call the Java environment through the JNI and request to add some kind of view (e.g. TextView ) (see testSetText() ). At this point, my application crashes - with crashlog:

WARN / dalvikvm (8352): threadid = 11: thread exiting with a non-display 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):

Now I also use Admob, which is integrated at the end of Java. When Admob calls my main class (myTest see above) through some delegate (for example, onReceiveAd) - I tried calling testSetText() and adding my TextView at that moment - and everything works fine!

So, I think this is due to threads - but I'm not an expert in this area, so I really need a little help.

Any suggestions?

+4
source share
3 answers

I have the same problem, but I just fixed it and realized what was going on with Android and cocos2d-x.

In principle, in the android system, only the main thread creating the user interface can update the interface itself.

Therefore, you need to use a handler and a message to tell the main thread to update the interface.

And what's more, when you call the java method using c / C ++ functions via JNI.

A static method may be a better choice, and you can first grab JavaVM and getstaticmethodid using this JavaVM and env.

Hope this helps you.

0
source

Maybe it's too late, I'm not familiar with the NDK, but from the stack trace, I understand that your problem is trying to add a view from the OpenGL thread (as indicated in the log, this is thread 11). You need to run this method in the user interface thread, as shown below:

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

I found this, and I wanted to make it a little easier for everyone, because for those who come here, you are probably looking for a quick, complete answer that details the process. Here is an example implementation.

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

This code runs on your main thread:

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

This code is executed by another thread wishing to talk to the main thread:

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

The system will send a message and call a callback in the thread that Handler created for the callback, which will give you access to these thread resources. It can also be used for many other things, and it is a very fast way to send messages. This is not limited to the interaction of UI streams.

0
source

All Articles