GLSurfaceView 父级为 null,即使它嵌套在 LinearLayout 中

Posted

技术标签:

【中文标题】GLSurfaceView 父级为 null,即使它嵌套在 LinearLayout 中【英文标题】:GLSurfaceView parent is null even though it is nested in a LinearLayout 【发布时间】:2011-12-24 02:25:03 【问题描述】:

我有一个名为 GLView 的自定义视图,它扩展了 GLSurfaceView 类。在这个 GLView 内部,我想访问包含在父线性布局中的另一个 TextView。当我调用 this.getParent 时,它返回 NULL,所以我看了看,eclipse 确实说 mparent 为 null。有人知道为什么吗?

调用视图的Activity类

package org.kizik.WLTBO;



import android.app.Activity;
import android.os.Bundle;




import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;


public class WholettheballoutActivity extends Activity 
   GLView view;



   @Override
   public void onCreate(Bundle savedInstanceState) 
      super.onCreate(savedInstanceState);
      setContentView(R.layout.score);
      view = (GLView) findViewById(R.id.mySurfaceView);


   // You can use a FrameLayout to hold the surface view
      /*FrameLayout frameLayout = new FrameLayout(this);
      frameLayout.addView(view);

      // Then create a layout to hold everything, for example a RelativeLayout
      RelativeLayout relativeLayout= new RelativeLayout(this);
      relativeLayout.addView(frameLayout);
      relativeLayout.addView(score);
      setContentView(relativeLayout);*/
   

   @Override
   protected void onPause() 
       super.onPause();
       view.onPause();
   

   @Override
   protected void onResume() 
       super.onResume();
       view.onResume();
   

XML 文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_
    android:layout_
    android:id="@+id/parent" >


    <TextView android:id="@+id/textView2"
        android:text = "Points 12345 Time:"
        android:gravity="center_horizontal"

        android:textSize="22sp"

        android:layout_
        android:layout_/>


    <org.kizik.WLTBO.GLView
        android:id="@+id/mySurfaceView"
        android:layout_
        android:layout_
        android:layout_weight="1"/>        

</LinearLayout>

可能不需要,但这里是 GLView 类中的构造函数

public GLView(Context context) 
      super(context);
      // Uncomment this to turn on error-checking and logging
      //setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
      renderer = new GLRenderer(context, view);
      setRenderer(renderer);
   

   public GLView(Context context, AttributeSet attrs)

       super(context,attrs);
       view = this.getParent();

       renderer = new GLRenderer(context, view);
       setRenderer(renderer);

   

【问题讨论】:

你在什么设备上调试得如何?我疯狂地试图找出与 android 上的 opencv 类似的问题。原来,由于一些硬件问题,像 droid X 这样的摩托罗拉设备总是会崩溃……不过 Nexus S 很好。 【参考方案1】:

尝试在活动中进行setContentView() 之前先扩展布局。然后您可以检查默认布局行为是否将 GLSurfaceView 附加到 LinearLayout:

View parentView = getLayoutInflater().inflate(R.layout.main,null,false);
view = (GlView)parentView.findViewById(R.id.mySurfaceView);
if(view.getParent()==null || !view.getParent() instanceof View )
    // throw new Exception("GLView had no parent or wrong parent");
 else 
    setContentView(parentView);


您实际上无法从onDraw()onSurfaceChanged()onSurfaceCreated() 方法内部更改渲染器中的父视图(线性布局)或任何其他视图,因为它们都由 GL 线程调用。只有主/UI 线程(在您的活动中调用 onCreate() 的线程)可以更改 UI。例如,如果您尝试在onSurfaceCreated() 中执行((TextView)view.findViewById(R.id.textView2)).setText("Some text");,则会导致异常

更好的方法是在活动内部设置渲染器:

public class WholettheballoutActivity extends Activity 


    GLView view;
    GLRenderer renderer;



    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.score);
        view = (GLView) findViewById(R.id.mySurfaceView);
        LinearLayout parentView = findViewById(R.id.parent);

        // Handler declaration goes in UI thread
        Handler handle = new Handler(new Handler.Callback()

            @Override
            public boolean handleMessage(Message msg)
                // message is handled by the UI thread

                TextView tv = WholettheballoutActivity .this.findViewById(R.id.textView2);

                tv.setText("You Rock!");

                return true;

            


        );

        renderer = new GLRenderer(context, parent, handler);
        view.setRenderer(renderer);

    


然后在渲染器中:

public class GLRenderer implements GLSurfaceView.Renderer

    View parent;
    Context context;
    Handler handler;

    public GLRenderer(Context context, View parent, Handler handler)
        this.context = context;
        this.parent = parent;
        this.handler = handler;

    

    public void onDraw(GL10 gl)

        // drawing etc


        handler.sendEmptyMessage(0);

    


Handler 的 handleMessage 方法中的任何内容都会排队等待 UI 线程在下一次循环时执行。有other ways to pass messages between other threads and the UI thread,但这个虽然不是很明显,但对于对 UI 进行单一异步更新的非 UI 线程最有意义

编辑:必须在要使用的线程中声明处理程序(除非你正在做一些时髦的see here)

【讨论】:

感谢您的帮助,很抱歉让您久等了。我已经尝试了上面的修复,我唯一需要更改的是使活动中的渲染器等于新的 glrenderer(this,parentView)。但是,当我尝试执行 view.setrenderer(renderer) 时,我遇到了问题。调试时说找不到源。 好的,我发现我只能设置一次渲染器,所以我注释掉了 glview 构造函数中的 setrenderer。但是,现在,在 ondraw 方法中设置处理程序时出现错误。它使程序崩溃。 啊,对不起。实际上我错了 Handler 总是在 UI 线程中被调用。它是从声明它的线程调用的。换句话说,在onCreate() 中声明一个处理程序,然后将其传递给渲染器构造函数。我更新了我的答案【参考方案2】:

文档说

Gets the parent of this view. Note that the parent is a ViewParent and not necessarily a View.

【讨论】:

是的,我知道,我已经把它排版了。但即便如此它也不返回 ViewParent

以上是关于GLSurfaceView 父级为 null,即使它嵌套在 LinearLayout 中的主要内容,如果未能解决你的问题,请参考以下文章

在父级为表单的子报表中滚动

升级到 Qt 5.15 后,ListView 委托中的父级为空

仅在 Safari 中 - 位置:固定子级在父级为位置时被切断:固定且溢出:隐藏

<div style="width:100%">是啥意思?

定位的属性以及margin的简写。

子视图有父级的阴影,即使有背景