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

发布于 2024-12-22 17:39:36 字数 2728 浏览 5 评论 0 原文

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

调用视图

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_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/parent" >


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

        android:textSize="22sp"

        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>


    <org.kizik.WLTBO.GLView
        android:id="@+id/mySurfaceView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"/>        

</LinearLayout>

Activity 类可能不需要,但这里是 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);

   }

I have a custom view called GLView that extends the GLSurfaceView class. Inside of this GLView I want to access the other TextView that is contained in a parent Linear Layout. When I call this.getParent it returns NULL, so I looked and eclipse indeed says that mparent is null. does anyone know why?

Activity class that calls the View

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 File

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


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

        android:textSize="22sp"

        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>


    <org.kizik.WLTBO.GLView
        android:id="@+id/mySurfaceView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"/>        

</LinearLayout>

Probably not needed but here are the constructors within the GLView class

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

   }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

如此安好 2024-12-29 17:39:36

在 Activity 中执行 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 线程(在 Activity 中调用 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 排队等待 UI 线程在下次循环时执行。还有其他方法可以在其他线程和UI线程之间传递消息,但这虽然不是立即显而易见的,但对于对 UI 进行单个异步更新的非 UI 线程来说最有意义

编辑:必须在要使用它的线程中声明处理程序(除非您正在做一些时髦的事情参见此处

Try expanding the layout first before you do setContentView() in activity. You can then check whether the default layout behavior is attaching the GLSurfaceView to the 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);
}

You can't actually change the parent view (the linear layout) or any other views in your renderer from inside the onDraw(), onSurfaceChanged() or onSurfaceCreated() methods as they are all called by the GL thread. Only the main/UI thread (the one that calls onCreate() in your activity) can change the UI. If you tried for example to do ((TextView)view.findViewById(R.id.textView2)).setText("Some text"); in onSurfaceCreated(), it would cause an exception

A better way to do this would be to set the renderer from inside the activity:

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

    }

}

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

    }

}

Anything inside the handleMessage method of a Handler gets queued for the UI thread to execute next time it loops round. There are other ways to pass messages between other threads and the UI thread, but this one although not immediately obvious, makes most sense for non-UI threads making single asynchronous updates to the UI

EDIT: Handler has to be declared in the thread it is to be used in (unless you're doing something funky see here)

小巷里的女流氓 2024-12-29 17:39:36

文档说

获取此视图的父级。请注意,父级是 ViewParent, 不一定是 View。

The documentation says

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文