开发者

Android: Add Java View to OpenGl View

I have ported my iphone app to android using ndk and cocos2dx. This has worked 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 this is not really working for me. I think I need basic knowledge about have views, activitys, Intent etc works in the Java environment.

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

    }
}

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

Could anyone give me some good advise here?

UPDATE:

Thanks Macarse 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:

Okay I am still working on this issue and just cant get it fixed :( But I have found out something interesting:

So to sum up my problem: My android app has a cocos2dx scene running which works perfect. Then when the user push a button :

myBut = CCM开发者_如何转开发enuItemImage::itemFromNormalImage("some.png", "some.png.png", this, menu_selector(Cocos2dMenuScene::butPushed));

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

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):

Now I also use Admob which is integrated at the Java end. When Admob call my main class( myTest see above ) through some delegate (eg onReceiveAd ) - I have tried to call testSetText() and add my TextView at this point- and everything works fine!

So I think it has someting to do with threading - But I am not a specialist in this area so I could very much need a little help.

Any suggestions?


I have the same issue but I just fixed and realize what happend to the android and cocos2d-x.

Basically, at the android system, only the main thread which create the UI can update the UI itself.

So you need to use the handler and message to inform main thread to update the UI.

And more further, when you call java method by c/c++ functions through JNI.

The static method could be the best choice, and you can grab the JavaVM first and getstaticmethodid by this JavaVM and env.

Hope this will have some help on you.


This is maybe too late, I am not familiar with the NDK, but from the stack trace, I can understand that your problem is trying to add a view from the OpenGL thread (as stated in the log, this is thread 11). You need to run this method in the UI thread, as follows:

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


I found this, and I wanted to make it a little easier for anyone else, since for those coming here you are likely 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 gets executed by 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 deliver the message and invoke a callback on the thread that created the Handler for the callback, which will give you access to that thread's resources. This can also be used for many other things and it is a very fast way to pass messages. It is not limited to UI thread interaction.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜