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 委托中的父级为空