user153275
user153275

Reputation:

findViewById in a subclassed SurfaceView throwing RuntimeException

This code works fine if I move the findViewById call in to the Activity. Any hints as to why it doesn't work from inside the LearningView class? I've tried moving the TextView inside the com.example.LearningView tag but no joy. I'd prefer to get the TextView from within the SurfaceView subclass as I feel it's more logical to treat the TV as a "child" of the SV.

This is a contrived example I wrote to figure out the problem in a larger application, but the gist of it is the same, and the stack trace is basically the same.

For what it is worth, the findViewById call is returning null, which obviously threw NullPointerExceptions in some attempts to fix this.

As you can probably gather from my attempts I'm flying blind on this one.

Learning.java:

package com.example.Learning;

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

public class Learning extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

LearningView.java:

package com.example.Learning;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.TextView;

public class LearningView extends SurfaceView implements SurfaceHolder.Callback {
    public LearningView(Context context, AttributeSet atts) {
        super(context, atts);
        getHolder().addCallback(this);      
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        TextView t = (TextView) findViewById(R.id.contents);
        t.setText("testing");
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    }
}

main.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <com.example.Learning.LearningView
        android:id="@+id/learningview" android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
    <TextView android:id="@+id/contents" android:layout_gravity="bottom|left"
        android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:textColor="#ffffffff" />
</FrameLayout>

Stack trace:

Thread [<3> main] (Suspended (exception RuntimeException))  
    ActivityThread.performLaunchActivity(ActivityThread$ActivityRecord, Intent) line: 2454  
    ActivityThread.handleLaunchActivity(ActivityThread$ActivityRecord, Intent) line: 2470   
    ActivityThread.access$2200(ActivityThread, ActivityThread$ActivityRecord, Intent) line: 119 
    ActivityThread$H.handleMessage(Message) line: 1821  
    ActivityThread$H(Handler).dispatchMessage(Message) line: 99 
    Looper.loop() line: 123 
    ActivityThread.main(String[]) line: 4310    
    Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]  
    Method.invoke(Object, Object...) line: 521  
    ZygoteInit$MethodAndArgsCaller.run() line: 860  
    ZygoteInit.main(String[]) line: 618 
    NativeStart.main(String[]) line: not available [native method]  

Upvotes: 1

Views: 7170

Answers (3)

Romain Guy
Romain Guy

Reputation: 98501

You are crashing because your TextView is null after findViewById(). The TextView is not a child of the SurfaceView, therefore calling findViewById() with the SurfaceView as the starting point will not find it.

Upvotes: 2

Gilson
Gilson

Reputation: 1838

I was having the same problem and the answer provided by Loke resolved my issue. I don't know if casting is a good clean way to program for android sdk. here is what my code ended up like:

my activity had:

setContentView(R.layout.game);

my game.xml:

<TextView  
    android:text="@string/text_foul_counter_1"  
    android:layout_height="wrap_content"  
    android:background="#fff"  
    android:gravity="center"  
    android:textColor="#000"  
    android:id="@+id/TextViewFoulCounter1"  
    android:layout_width="wrap_content"  
    android:layout_below="@+id/TextViewFoul1" 
    android:padding="2dp"></TextView>

and calling finViewById from within my class: public class PlayerView extends Activity implements OnClickListener, OnLongClickListener {...}

without casting I used to get a null pointer exception. below is the code line that works now.

foulsTextViewTeam1 = (TextView) ((Activity) context).findViewById(R.id.TextViewFoulCounter1);

Upvotes: 1

Loke
Loke

Reputation: 21

You can cast the context as an Activity and find the view as follows:

(TextView) ((Activity) context).findViewById(R.id.contents);

Now it won't be null.

Upvotes: 2

Related Questions