findViewById generating a RunTime error


#1

hi i am new to android development and java coding, and i am having a problem with the code below. findViewById is generating a run time error (when I remove this code the program seems to work) and the program crashes before it even starts. i was able to work around this in ch. 1 by using a declarative style of coding where i was able to employ a method from the XML file rather than use findViewById for true and false buttons, but i can see this problem is going to be unavoidable.

note: i get the same error when i use findViewById for the true and false buttons, so i have commented them out.

QuizActivity.java:

package com.bignerranch.android.geoquiz;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class QuizActivity extends ActionBarActivity {

//private Button mTrueButton;
//private Button mFalseButton;
private Button mNext;

private TextView mQuestionTextView;

private TrueFalse[] mQuestionBank = new TrueFalse[] {
		new TrueFalse(R.string.question_oceans, true),
		new TrueFalse(R.string.question_mideast, false),
		new TrueFalse(R.string.question_africa, false),
		new TrueFalse(R.string.question_americas, true),
		new TrueFalse(R.string.question_asia, true) 
};

private int mIndex = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_quiz);
    
	//set the question
	mQuestionTextView = (TextView) findViewById(R.id.question_text_view);
            		
	mNext = (Button) findViewById(R.id.next_button);
	mNext.setOnClickListener(new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			mIndex += 1 % mQuestionBank.length;
			updateQuestion();
		}
	});
    
	updateQuestion();

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment())
                .commit();
    }
}

//method for when true button is clicked
public void clickedTrue (View v) {
	Toast.makeText(QuizActivity.this, R.string.incorrect_toast, Toast.LENGTH_SHORT).show();
}

public void clickedFalse (View v ) {
	Toast.makeText(QuizActivity.this, R.string.correct_toast, Toast.LENGTH_SHORT).show();
}

private void updateQuestion () {
	int question = mQuestionBank[mIndex].getQuestion();	//this is the resource ID of the current question
    mQuestionTextView.setText(question);
}

}

fragment_quiz.XML:

<TextView
    android:id="@+id/question_text_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="24dp" />

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:gravity="center" >
    
    <Button 
        android:id="@+id/true_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/true_button"
        android:onClick="clickedTrue" />
    
    <Button
        android:id="@+id/false_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/false_button"
        android:onClick="clickedFalse" />
    
</LinearLayout>

<Button
    android:id="@+id/next_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/next_button" />

TrueFalse.java:

package com.bignerranch.android.geoquiz;

public class TrueFalse {

private int mQuestion;				//holds resource ID
private boolean mTrueQuestion;

public TrueFalse (int question, boolean trueQuestion) {
	mQuestion = question;
	mTrueQuestion = trueQuestion;
}

public int getQuestion() {
	return mQuestion;
}

public void setQuestion(int question) {
	mQuestion = question;
}

public boolean isTrueQuestion() {
	return mTrueQuestion;
}

public void setTrueQuestion(boolean trueQuestion) {
	mTrueQuestion = trueQuestion;
}

}


#2

Looking only at your import statements, your code doesn’t exactly match what’s written in the book. You’d be better served trying to match the book exactly as you learn. This is slightly harder than it used to be because the wizards are generating some extra code that the book didn’t anticipate, but it’s still possible.

You can download the book’s code and compare it line by line to yours to get you started. You should get rid of the placeholder fragment. If I remember correctly from others, I think your xml file might have a different name than the book. You need to fix all those minor differences and then everything will work.


#3

okay so i’ve returned everything exactly to the way the book did it (as far as i can tell). the program is still crashing, below are the codes for the java and xml files, along with the logcat log. any help at all would be appreciated

QuizActivity.java

package com.bignerranch.android.geoquiz;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class QuizActivity extends ActionBarActivity {
	
	private Button mTrueButton;
	private Button mFalseButton;
	private Button mNext;
	
	private TextView mQuestionTextView;
	
	private TrueFalse[] mQuestionBank = new TrueFalse[] {
			new TrueFalse(R.string.question_oceans, true),
			new TrueFalse(R.string.question_mideast, false),
			new TrueFalse(R.string.question_africa, false),
			new TrueFalse(R.string.question_americas, true),
			new TrueFalse(R.string.question_asia, true) 
	};
	
	private int mIndex = 0;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_quiz);
        
		//set the question
		mQuestionTextView = (TextView) findViewById(R.id.question_text_view);
       
       //referencing true button to its id
       mTrueButton = (Button)findViewById(R.id.true_button);
                
       //setting a listener for true button
       mTrueButton.setOnClickListener(new OnClickListener() {		
			@Override
			public void onClick(View v) {	
				Toast.makeText(QuizActivity.this, R.string.incorrect_toast, Toast.LENGTH_SHORT).show();
			}
		});
        
        //referencing false button to its id
        mFalseButton = (Button) findViewById(R.id.false_button);
        
        //setting a listener for false button
        mFalseButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Toast.makeText(QuizActivity.this, R.string.correct_toast, Toast.LENGTH_SHORT).show();
			}
		});
        		
		mNext = (Button) findViewById(R.id.next_button);
		mNext.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				mIndex += 1 % mQuestionBank.length;
				updateQuestion();
			}
		});
        
		updateQuestion();

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.quiz, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
    
    private void updateQuestion () {
    	int question = mQuestionBank[mIndex].getQuestion();	//this is the resource ID of the current question
        mQuestionTextView.setText(question);
    }
   
}

fragment_quiz.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/question_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="24dp" />
    
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center" >
        
        <Button 
            android:id="@+id/true_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/true_button" />
        
        <Button
            android:id="@+id/false_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/false_button" />
        
    </LinearLayout>
    
    <Button
        android:id="@+id/next_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/next_button" />

</LinearLayout>

Logcat:
04-16 15:51:02.030: W/ApplicationPackageManager(5551): getCSCPackageItemText()
04-16 15:51:02.090: D/AndroidRuntime(5551): Shutting down VM
04-16 15:51:02.090: W/dalvikvm(5551): threadid=1: thread exiting with uncaught exception (group=0x418a6da0)
04-16 15:51:02.100: E/AndroidRuntime(5551): FATAL EXCEPTION: main
04-16 15:51:02.100: E/AndroidRuntime(5551): Process: com.bignerranch.android.geoquiz, PID: 5551
04-16 15:51:02.100: E/AndroidRuntime(5551): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.bignerranch.android.geoquiz/com.bignerranch.android.geoquiz.QuizActivity}: java.lang.NullPointerException
04-16 15:51:02.100: E/AndroidRuntime(5551): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2305)
04-16 15:51:02.100: E/AndroidRuntime(5551): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2363)
04-16 15:51:02.100: E/AndroidRuntime(5551): at android.app.ActivityThread.access$900(ActivityThread.java:161)
04-16 15:51:02.100: E/AndroidRuntime(5551): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1265)
04-16 15:51:02.100: E/AndroidRuntime(5551): at android.os.Handler.dispatchMessage(Handler.java:102)
04-16 15:51:02.100: E/AndroidRuntime(5551): at android.os.Looper.loop(Looper.java:157)
04-16 15:51:02.100: E/AndroidRuntime(5551): at android.app.ActivityThread.main(ActivityThread.java:5356)
04-16 15:51:02.100: E/AndroidRuntime(5551): at java.lang.reflect.Method.invokeNative(Native Method)
04-16 15:51:02.100: E/AndroidRuntime(5551): at java.lang.reflect.Method.invoke(Method.java:515)
04-16 15:51:02.100: E/AndroidRuntime(5551): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
04-16 15:51:02.100: E/AndroidRuntime(5551): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
04-16 15:51:02.100: E/AndroidRuntime(5551): at dalvik.system.NativeStart.main(Native Method)
04-16 15:51:02.100: E/AndroidRuntime(5551): Caused by: java.lang.NullPointerException
04-16 15:51:02.100: E/AndroidRuntime(5551): at com.bignerranch.android.geoquiz.QuizActivity.onCreate(QuizActivity.java:43)
04-16 15:51:02.100: E/AndroidRuntime(5551): at android.app.Activity.performCreate(Activity.java:5426)
04-16 15:51:02.100: E/AndroidRuntime(5551): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
04-16 15:51:02.100: E/AndroidRuntime(5551): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2269)
04-16 15:51:02.100: E/AndroidRuntime(5551): … 11 more
04-16 15:51:04.592: I/Process(5551): Sending signal. PID: 5551 SIG: 9


#4

Your code has differences from the book code. I didn’t look at it line by line, but here’s one example.

Mine:

@Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; }

Yours:

[code] @Override
public boolean onCreateOptionsMenu(Menu menu) {

    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.quiz, menu);
    return true;
}[/code]

So at the very least, you need quiz.xml instead of main.xml.

You are also extending ActionBarActivity instead of Activity.

99% isn’t good enough. You need to be at 100% to get it working. Copy the code from the book into a new project and see if it will build. That’s the right first step for anybody having trouble getting started. If it builds and runs, the problem is in your source. If it doesn’t, the problem is in your build environment. Chances are it’s in your source. Once the downloaded code is working, start copying your own source on top if it until you find the offending file. Then diff that file with the book file to find the error. Repeat as necessary.

We’ve all gone through some frustration. Android development isn’t easy. At one point I started to feel lost and reread the book from page 1. I also refer to a different Android book, stackoverflow, and the official docs as needed. It’s still hard, but it’s starting to sink in.


#5

Good catch on the Activity instead of ActionBarActivity. Although, even in the solutions code, they use activity_quiz.xml instead of main.xml, because that is the name of the file to which they are referring. My file happens to be called quiz.xml. I have no file called main.xml.

Copying and pasting the code from solutions seems not even to be launching, could this be a problem with the build environment, as you mentioned? Do you have any suggestions on how to correct this? Sorry for the one million questions, just so confused!


#6

After spending hours on this same problem, I think I have some sort of a solution. Since android updated, there is now a fragment_activity.xml along with the main activity.xml that the book describes. To alter TextView, you have to use the method inside the Placeholderfragment class, which extends fragment, inside the main java file. Don’t use the first class that extends ActionBarActivity.

The Placeholder class is a static class so you have to declare your variable inside the onCreateView method, unlike the way the book describes, which is before the onCreate method. After doing that, I was able to use setText(int x) and my app finally stopped crashing.

So many hours on this lost. found the answer at stackoverflow:

stackoverflow.com/questions/3697 … rce-closes

i don’t know if there is a better way, but i’m using this for now. i’m a newbie to this.

hopefully, if any coders see this, they can explain how the code from the Big Nerd Ranch Guide for android programming can be updated.

thank you!
rob


#7

one other change. you have to add “rootView” in the declaration inside the Placeholder class:

TextView mYourStuff = (TextView)rootView.findViewById(R.id.your_text);

then it should roll like whatever…


#8

ashlin,
Double-check that you are indeed using activity_quiz.xml

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_quiz);
You may be seeing the error because activity_quiz.xml is empty

Your post from 16 April implies you are editing and attempting to use fragment_quiz.xml instead

Alternatively, if you are indeed using a layout file called quiz.xml, you need to use that in your setContentView() call

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.quiz);


#9

thanks to both robrob808 and skregas!

skregas - i am using activity_quiz for the setContentView, thanks for the heads up!

robrob808 - your advice was incredibly helpful and did work! i am still working to correct one problem that resulted. i cannot seem to use the method Toast.makeText in a static method (checkAnswer must be a static method since it is used in a static class right?), as it does not like the context argument “this”. I have tried replacing that with a number of other arguments like:

Toast.makeText(QuizActivity.this, messageId, Toast.LENGTH_SHORT).show();
Toast.makeText(getBaseContext(), messageId, Toast.LENGTH_SHORT).show();
Toast.makeText(getApplicationContext(), messageId, Toast.LENGTH_SHORT).show();

this is the code for what my checkAnswer method looks like:

private static void checkAnswer(boolean userPressedTrue) {
    	
    	boolean answerIsTrue = mQuestionBank[mIndex].isTrueQuestion();
    	int messageId = 0;
    	
    	if (userPressedTrue == answerIsTrue) messageId = R.string.correct_toast;
    	else {messageId = R.string.incorrect_toast;}
    	
    	Toast.makeText(QuizActivity.this, messageId, Toast.LENGTH_SHORT).show();
    }

i dunno if anyone knows why this is happening, but any input would be helpful. once i have the correct code up and running, i will post it in case anyone else needs to see it. thanks again for the help!


#10

Here are my declarations:

They aren’t static.


#11

unfortunately if you are putting the code for your buttons and text view in the class entitled PlaceholderFragment (which is static), instead of onCreate as in the book (this is due to reasons above given by robrob808) you can only use static methods any object inside this class. Therefore, my declaration for checkAnswer has to be static in order for this method to work on any object inside PlaceholderFragment.

I’ve also tried moving checkAnswer into the PlaceholderFragment class to avoid making it static, but then you get errors for using the Toast.makeText method.


#12

Alright, so this is the final functional code for PlaceholderFragment class in QuizActivity.java. Because you can’t use Toast.makeText within a static method, you can’t have a checkAnswer method and you must write out the code for that within each setOnClickListener (at least as far as I can tell).

    public static class PlaceholderFragment extends Fragment {

		public PlaceholderFragment() {
		}
		
		private Button mTrueButton;
		private Button mFalseButton;
		private Button mNext;
		
		private TextView mQuestionTextView;
		
		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container,
				Bundle savedInstanceState) {
			
			View rootView = inflater.inflate(R.layout.fragment_quiz, container,
					false);

			//set the question
			mQuestionTextView = (TextView) rootView.findViewById(R.id.question_text_view);
			
			//referencing true button to its id
	        mTrueButton = (Button)rootView.findViewById(R.id.true_button);
	        
	      //setting a listener for true button
		    mTrueButton.setOnClickListener(new View.OnClickListener() {		
				@Override
				public void onClick(View v) {	
					
					boolean answerIsTrue = mQuestionBank[mIndex].isTrueQuestion();
			    	int messageId = 0;
					if (answerIsTrue == true) messageId = R.string.correct_toast;
			    	else {messageId = R.string.incorrect_toast;}
			    	Toast.makeText(getActivity(), messageId, Toast.LENGTH_SHORT).show();
				}
			});                
		      
		    //referencing false button to its id
		    mFalseButton = (Button) rootView.findViewById(R.id.false_button);
		        
		    //setting a listener for false button
		    mFalseButton.setOnClickListener(new View.OnClickListener() {
				@Override
				public void onClick(View v) {
					boolean answerIsTrue = mQuestionBank[mIndex].isTrueQuestion();
			    	int messageId = 0;
					if (answerIsTrue == false) messageId = R.string.correct_toast;
			    	else {messageId = R.string.incorrect_toast;}
			    	Toast.makeText(getActivity(), messageId, Toast.LENGTH_SHORT).show();
				}
			});
		        		
			mNext = (Button) rootView.findViewById(R.id.next_button);
			mNext.setOnClickListener(new View.OnClickListener() {
				@Override
				public void onClick(View v) {
					mIndex = (mIndex + 1) % mQBLength;
					updateQuestion(mQuestionTextView);
				}
			});
		        
			updateQuestion(mQuestionTextView);
			
			return rootView;
		}
	}