Родителският елемент на GLSurfaceView е null, въпреки че е вложен в LinearLayout

Имам персонализиран изглед, наречен GLView, който разширява класа GLSurfaceView. Вътре в този GLView искам да осъществя достъп до другия TextView, който се съдържа в родителско линейно оформление. Когато извикам this.getParent, той връща NULL, така че погледнах и eclipse наистина казва, че mparent е null. някой знае ли защо

Клас на дейност, който извиква 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 файл

<?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>

Вероятно не е необходимо, но ето конструкторите в класа 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);

   }

person Kizik Studios    schedule 24.12.2011    source източник
comment
как се дебъгва, на какво устройство? Полудях, опитвайки се да разбера подобен проблем с opencv на android. Оказа се, че поради някои хардуерни проблеми устройства на Motorola като droid X винаги се сриват... Nexus S обаче беше добре.   -  person peter karasev    schedule 31.12.2011


Отговори (2)


Опитайте първо да разширите оформлението, преди да направите 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 нишката. Само главната/ПИ нишка (тази, която извиква onCreate() във вашата дейност) може да промени потребителския интерфейс. Ако се опитате например да направите ((TextView)view.findViewById(R.id.textView2)).setText("Some text"); в onSurfaceCreated(), това ще доведе до изключение

По-добър начин да направите това би бил да зададете рендеринга от вътрешността на дейността:

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

    }

}

Всичко вътре в метода handleMessage на Handler се поставя на опашка за нишката на UI за изпълни следващия път, когато се завърти. Има други начини за предаване на съобщения между други нишки и нишката на потребителския интерфейс, но това, въпреки че не е веднага очевидно, има най-голям смисъл за не-UI нишки, които правят единични асинхронни актуализации на UI

РЕДАКТИРАНЕ: Handler трябва да бъде деклариран в нишката, в която трябва да се използва (освен ако не правите нещо фънки вижте тук)

person James Coote    schedule 25.12.2011
comment
Благодаря за помощта и съжалявам за дългото чакане. Опитах корекцията по-горе, където единственото нещо, което трябваше да променя, беше да направя рендера в дейността равен на new glrenderer(this, parentView). Имам проблеми обаче, когато се опитвам да направя view.setrenderer(renderer). при отстраняване на грешки казва, че източникът не е намерен. - person Kizik Studios; 30.12.2011
comment
Добре, разбрах, че мога да задам рендера само веднъж, така че коментирах сетрендера, който беше в конструктора на glview. Сега обаче получавам грешка, която възниква, когато манипулаторът е зададен в метода ondraw. срива програмата. - person Kizik Studios; 30.12.2011
comment
А, съжалявам. Всъщност грешах, че Handler винаги се извиква в нишката на потребителския интерфейс. Извиква се от нишката, в която е декларирана. С други думи, декларирайте манипулатор в onCreate() и след това го предайте в конструктора за изобразяване. Актуализирах отговора си - person James Coote; 31.12.2011

В документацията се казва

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

person poitroae    schedule 24.12.2011
comment
Да, знам това, дадох го да го преобразуват. но въпреки това не връща и ViewParent - person Kizik Studios; 24.12.2011