Android:将Java视图添加到OpenGl视图

4
我使用NDK和Cocos2dx将我的iPhone应用程序移植到了Android平台。这个过程非常顺利,我认为Cocos2dx非常酷!
现在我想在Java环境中的主OpenGL视图中添加一些Java视图。但是这对我来说并不容易。我认为我需要基本了解Java环境中视图、活动、意图等的工作原理。
更具体地说,我需要在运行时向我的OpenGL视图添加一个TextView(Java)。我尝试了以下方法,但当我调用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);

    }
}

如果我尝试运行另一个活动或在public void testSetText()函数中调用setContentView(R.layout.test_screen),我的游戏也会崩溃。

有人能给我一些好的建议吗?

更新:
感谢Macarse 以下是堆栈跟踪:

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

我通过JNI调用Java环境,并请求添加某种视图(例如 TextView )(请参见 testSetText())。此时,我的应用程序崩溃了 - 带有crashlog:

WARN / dalvikvm(8352):threadid = 11:线程退出,未捕获 异常(group = 0x40015560)08-16 15:19:52.214: ERROR / AndroidRuntime(8352):致命异常:GLThread 10 08-16 15:19:52.214:ERROR / AndroidRuntime(8352):

现在我还使用Admob,在Java端集成了它。当Admob通过一些委托(例如onReceiveAd)调用我的主类(myTest见上文)时 - 我尝试调用 testSetText()并在此时添加我的 TextView - 一切正常!

所以我认为这与线程有关。但我不是这个领域的专家,所以我非常需要一些帮助。

有什么建议吗?


请添加堆栈跟踪。 - mibollma
嘿,兄弟,你能分享一下这个问题的代码吗?我也遇到了同样的问题,我也想要同样的东西。这将是非常有帮助的!!! - user1169079
我也在尝试集成admob,但不知道如何在场景中访问我的广告视图?希望你能帮我解决这个问题。 - user1169079
3个回答

0

我发现了这个,想让它对其他人更容易一些,因为来到这里的人很可能正在寻找一个快速完整的答案,详细说明过程。这里有一个示例实现。

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线程上调用一个回调函数,这将使您能够访问该线程的资源。这也可以用于许多其他事情,它是一种非常快速的传递消息的方式。它不仅限于UI线程的交互。

0
这可能有点晚了,我不太熟悉NDK,但从堆栈跟踪中可以看出,您的问题是尝试从OpenGL线程中添加视图(如日志中所述,这是线程11)。 您需要在UI线程中运行此方法,如下所示:
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

我有同样的问题,但是我已经解决了并且意识到了发生在安卓和cocos2d-x上的问题。

基本上,在安卓系统中,只有创建UI的主线程才能更新UI本身。

所以你需要使用处理程序(handler)和消息(message)来通知主线程更新UI。

进一步说,当你通过JNI调用C/C++函数来调用Java方法时,

静态方法可能是最好的选择,你可以首先获取JavaVM,然后通过这个JavaVM和env获取staticmethodid。

希望这对你有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接