I cannot for the life of me figure out why I'm getting a NullPointerException.
When a user clicks on a particular image, a dialog window is supposed to pop-up and display a larger version of said image:
private OnClickListener coverListener = new OnClickListener()
{
public void onClick(View v)
{
showDialog(DIALOG_COVER);
}
};
DIALOG_COVER is set to = 0.
The associated onCreateDialog looks like this:
protected Dialog onCreateDialog(int id) {
Dialog dialog;
switch(id)
{
case DIALOG_COVER:
dialog = new Dialog(mContext);
dialog.setContentView(R.layout.cover_dialog);
dialog.setTitle(book.getTitle());
ImageView coverLarge = (ImageView)findViewById(R.id.coverLarge);
coverLarge.setImageBitmap(book.getCover());
break;
default:
dialog = null;
}
return dialog;
}
For reference, this is cover_dialog.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/coverDialog"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp">
<ImageView android:id="#+id/coverLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitStart"
/></LinearLayout>
Now, when the image previously described is clicked, the application immediately crashes and throws the following error through LogCat:
06-08 13:29:17.727: ERROR/AndroidRuntime(2220): Uncaught handler: thread main exiting due to uncaught exception
06-08 13:29:17.757: ERROR/AndroidRuntime(2220): java.lang.NullPointerException
06-08 13:29:17.757: ERROR/AndroidRuntime(2220): at org.kylehughes.android.brarian.AndroidBrarian.onCreateDialog(AndroidBrarian.java:259)
The line in question refers to this line inside of onCreateDialog:
coverLarge.setImageBitmap(book.getCover());
Basically, I don't get why coverLarge is null at that point. Any help would be much appreciated.
What's about:
/** snip **/
LayoutInflater factory = LayoutInflater.from(mContext);
View dialogView = factory.inflate(R.layout.cover_dialog,null);
ImageView coverLarge = (ImageView)dialogView.findViewById(R.id.coverLarge);
dialog = new Dialog(mContext);
dialog.setContentView(dialogView);
dialog.setTitle(book.getTitle());
coverLarge.setImageBitmap(book.getCover());
/** snip **/
Just written from scratch. Please check the syntax
This
(ImageView)findViewById(R.id.coverLarge);
returns a nullvalue. You may be passing an invalid/malformed id String to the findViewById method. Have you checked (debugged) what this String looks like before you get the NPE?
Is it possible that you have a different xml file defining the same ID (coverLarge) for a different kind of View (say a Button)? Also, notice how the id you use to setup the dialog is cover_dialog but in the XML file you have coverDialog
You have a few things going on at that line that some debug output would help. I'd start by System.out.println'ing the values of coverLarge and book immediately before the offending line. I know they shouldn't be null, but it wouldn't hurt to rule those possibilities out.
Related
I'm using Android Studio and trying to show some chosen Street View paths in VR. I already have Street View running well and now I'm trying to show it in VR.
I have put the com.google.vr.sdk.widgets.pano.VrPanoramaView in the layout and, inside onCreate in my class, referenced it to a VrPanoramaView variable through findViewById. Now I'm trying to show an image calling a method which I've defined in this class, loadPanoImage. This method loads an image from the storage and shows it through loadImageFromBitmap.
The problem is that it isn't able to show anything, even though I've followed a guide and I've done everything as showed. I've even tryed calling it in different parts of the code (before doing any other action, on clicking a button, before and after showing streetview) but I can't understand why it isn't working and how will I be able to use it to show images taken from StreetView (I don't know if I will be able to do it dinamically or I should download them and put them in the storage).
I'm putting part of the code for reference:
public class VrExperience extends FragmentActivity {
Button buttonCitta;
Button buttonMare;
Button buttonMontagna;
TextView titleTextView;
// George St, Sydney
private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689);
// LatLng with no panorama
private static final LatLng INVALID = new LatLng(-45.125783, 151.276417);
//VrPanoramaView is inserted in the layout
private VrPanoramaView panoWidgetView;
//StreetViewPanorama is another class in my project which shows Street View
private StreetViewPanorama mStreetViewPanorama;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_vrexperiences);
panoWidgetView = (VrPanoramaView) findViewById(R.id.pano_view);
panoWidgetView.setEventListener(new VrPanoramaEventListener());
//download image and show it, but it doesn't show anything
loadPanoImage();
titleTextView = (TextView) findViewById(R.id.titleTextView);
buttonCitta = (Button) findViewById(R.id.buttonCitta);
buttonCitta.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!checkReady()) {
return;
}
titleTextView.setVisibility(View.GONE);
buttonCitta.setVisibility(View.GONE);
buttonMare.setVisibility(View.GONE);
buttonMontagna.setVisibility(View.GONE);
loadPanoImage(); //it doesn't show anything
mStreetViewPanorama.setPosition(SYDNEY);
loadPanoImage(); //it doesn't show anything
}
}};
//code for buttonMontagna and buttonMare as well, it's identical
SupportStreetViewPanoramaFragment streetViewPanoramaFragment =
(SupportStreetViewPanoramaFragment)
getSupportFragmentManager().findFragmentById(R.id.streetviewpanorama);
streetViewPanoramaFragment.getStreetViewPanoramaAsync(
new OnStreetViewPanoramaReadyCallback() {
#Override
public void onStreetViewPanoramaReady(StreetViewPanorama panorama) {
mStreetViewPanorama = panorama;
// Only set the panorama to INVALID on startup (when no panoramas have been
// loaded which is when the savedInstanceState is null).
if (savedInstanceState == null) {
mStreetViewPanorama.setPosition(INVALID);
}
}
});
}
/**
* When the panorama is not ready the PanoramaView cannot be used. This should be called on
* all entry points that call methods on the Panorama API.
*/
private boolean checkReady() {
if (mStreetViewPanorama == null)
return false;
return true;
}
/**
* Called when the Animate To Invalid button is clicked.
*/
public void onGoToInvalid(View view) {
if (!checkReady()) {
return;
}
mStreetViewPanorama.setPosition(INVALID);
}
//retrieves image from the assets folder and loads it into the VrPanoramaView
private void loadPanoImage() {
VrPanoramaView.Options options = new VrPanoramaView.Options();
InputStream inputStream = null;
AssetManager assetManager = getAssets();
try {
inputStream = assetManager.open("demo2.jpg");
options.inputType = VrPanoramaView.Options.TYPE_MONO;
panoWidgetView.loadImageFromBitmap(
BitmapFactory.decodeStream(inputStream), options
);
inputStream.close();
} catch (IOException e) {
Log.e("Fail", "Exception in loadPanoImage" + e.getMessage());
}
}
#Override
protected void onPause() {
panoWidgetView.pauseRendering();
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
panoWidgetView.resumeRendering();
}
#Override
protected void onDestroy() {
panoWidgetView.shutdown();
super.onDestroy();
}
}
This is my layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/vrExperienceActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.vr.sdk.widgets.pano.VrPanoramaView
android:id="#+id/pano_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_weight="5"
android:scrollbars="none" />
<TextView
android:id="#+id/titleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:text="VR Experience"
android:textAlignment="center"
android:textAppearance="#android:style/TextAppearance.Large"
android:textColor="#0000F0"
android:visibility="visible" />
<Button
android:id="#+id/buttonCitta"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Città " />
<fragment
class="com.google.android.gms.maps.SupportStreetViewPanoramaFragment"
android:id="#+id/streetviewpanorama"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
EDIT: #LucioB
a) those are the places I've tried to call loadPanoImage, but neither of them showed anything. It acts as nothing happens calling that method, the program keeps going to the other tasks. I'd like for images to be shown directly in VR when a button is clicked, or if that isn't possible to add the classic cardboard button in Street View mode to pass to VR view.
b) I mean the code isn't doing what I expected it to do. I thought that once I created VrPanoramaView in the layout and used it to show an image through .loadImageFromBitmap it would have shown the image I loaded from asset (I have an image saved on the virtual SD), and that once I was able to do that for a single image I would have found a way to do it for a whole path.
The code doesn't give any exception, I think I'm making a logic mistake or I didn't understand how VR api work.
EDIT: I've found that the java code is working, the problem was in the layout which didn't permit to see VrPanoramaView because it was obscured by StreetViewPanorama
I'm trying to re-rig a quiz app to instead of displaying text questions, will display images (Ishihara slides to be specific).
For reference, here's a screenshot of the original quiz app:
When a user selects the true or false buttons, a toast appears with the result. Straightforward, and the previous/next buttons cycle through the questions. The questions are being stored as such:
final QuestionAndAnswer[] mQandA = new QuestionAndAnswer[]{
/*1*/ new QuestionAndAnswer(R.string.question_northAmerica, true),
/*2*/ new QuestionAndAnswer(R.string.question_antarctica, false),
/*3*/ new QuestionAndAnswer(R.string.question_canada, false),
/*4*/ new QuestionAndAnswer(R.string.question_madagascar, true),
/*5*/ new QuestionAndAnswer(R.string.question_wonders, false)
};
I thought that pointing the new QuestionAndAnswer at R.drawable.imagename could accomplish this, but instead just displays the image's location as text.
And changing it to new ImageView(R.drawable.imagename, true) throws the error:
ImageView (android.content.Context, android.util.AttributeSet)in ImageView cannot be applied to (int,boolean)
I'm sorry, I'm still very new to Android but as you've probably put together by now, I'm a student and don't have a choice but to do this.
If you have something like this on layout xml
<RelativeLayout ...
...
<TextView android:id="#+id/text_view_id" ... />
...
</RelativeLayout>
You need to change it to
<RelativeLayout ...
...
<ImageView android:id="#+id/image_view_id" ... />
...
</RelativeLayout>
Then on your activity class, maybe you have something like below
TextView textView;
public void onCreate() {
textView = (TextView) findViewById(R.id.text_view_id);
....
textView.setText(mQandA[i].question)
}
Where mQandA[i].question is your question resource a.k.a R.string.question_northAmerica
Change it to
ImageView imageView;
public void onCreate() {
imageView = (ImageView) findViewById(R.id.image_view_id);
...
imageView.setImageResource(mQandA[i].question)
}
Where mQandA[i].question is your image resource a.k.a R.drawable.imagename
EDIT 1
change every appearance of
textView.setText(mQandA[i].question)
with
imageView.setImageResource(mQandA[i].question)
counterpart
I have built my own adapter that inflates a custom view that i created. That view contains a TextView tag that's associated with an author.
<TextView
android:id="#+id/author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="John Smith" />
My problem is that when i go to populate that view, even if the object i am loading the data from (currentStory) contains a not null value, it still doesn't populate.
if (currentStory.getAuthor() == null)
holder.author.setVisibility(TextView.GONE);
else
holder.author.setText(currentStory.getAuthor());
While debugging the code, I check the object and its state after the above condition and the Text attribute is populated with the correct data. When i let it run, it doesn't show the correct.
Does anyone have any idea on what i might be doing wrong or what i missed?
I am not sure if this could solve your problem, but please try this
holder.author.post(new Runnable() {
#Override
public void run() {
if (currentStory.getAuthor() == null)
holder.author.setVisibility(TextView.GONE);
else
holder.author.setText(currentStory.getAuthor());
}
});
I am creating a times tables app, in which one of the activities allows the user to enter which times tables they would like to view, then the app will bring up that times tables.(e.g. 6x5=30) etc.
Below is the xml layout I have created for the activity:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="15dp">
<TextView
android:id="#+id/tvTop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="I want to see the: "
android:textSize="25dp" />
<EditText
android:id="#+id/etEnterNumber"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Enter Number..."
>
</EditText>
<TextView
android:id="#+id/tvBottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Times tables!"
android:textSize="25dp" />
<Button
android:id="#+id/btnGo"
android:layout_width="50dp"
android:layout_height="50dp"
android:text="Go"
android:layout_gravity="center"/>r
</LinearLayout>
And this it the java class I have created thus far for the classes functionalitiy:
public class ViewTimesTables extends Activity implements View.OnClickListener {
// Declaring Vars
Button go;
EditText enterNumber;
TextView top;
TextView bottom;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setting equal to text layout View
setContentView(R.layout.view);
// calling method to intialise vars
initialiseVars();
}// on create end
/**
* method to initialise all of the buttons, textviews etc used to clean up
* the onCreate.
*/
private void initialiseVars() {
// Setting up (initialising) all the buttons text views etc from the xml
// (vid 25)
go = (Button) findViewById(R.id.btnGo);
enterNumber = (EditText) findViewById(R.id.etEnterNumber);
top = (TextView) findViewById(R.id.tvTop);
bottom = (TextView) findViewById(R.id.tvBottom);
}
/**
* Method with on click listener that adds functionality for all of the
* buttons, text views etc
*
* #param v
*/
public void onClick(View view) {
// switch statement which determines what is clicked
switch ((view).getId()) {
case R.id.etEnterNumber:
// code to read user number (i.e. between 1 and 12)
//And possibly link to go button
break;
case R.id.btnGo:
// code to bring up new activity/screen with times table
// of the number that was entered in edit text
break;
}
}
}
I am unsure how to add the correct functionality (probably within switch statement) so that when e.g. "6" is entered in the edit text box and the "go" button is pressed then the 6 times tables will be brought up in a new activity?
I would begin by looking at Intents to start a new activity and pass data to it.
A relevant tutorial is this Android Intents Tutorial
Getting the text from a edit text is a simple as enterNumber.getText().getString()
You could then use a conditional statement to call the designated class.
Something like this would allow you to pass two values to the SixTimesTables class with the values 5 and 6 passed in.
if(enterNumber.getText().getString().equals("6")){
Intent i = new Intent(this, SixTimesTables.class);
i.putExtra("Value1", 5);
i.putExtra("Value2", 6);
// set the request code to any code you like,
// you can identify the callback via this code
startActivityForResult(i, REQUEST_CODE);
}
You probably want a dynamic layout for next activity.
It may help you.
http://www.dreamincode.net/forums/topic/130521-android-part-iii-dynamic-layouts/
Then you can switch between activities as AndyGable mentioned.
Hopefully it'll help you.
You really dont need the onClick for the editText you can handle if data is entered in the editText or not from the button click only like this:
public void onClick(View view) {
// switch statement which determines what is clicked
switch ((view).getId()) {
case R.id.btnGo:
// code to bring up new activity/screen with times table
// of the number that was entered in edit text
// check if editText has values or not
if(TextUtils.isEmpty(mEditText.getText().toString())) {
mEditText.setError("Please enter a number");
}else {
int number = Integer.parseInt(mEditText.getText().toString());
Intent intent = new Intent(YourCurrentActivity.this, NextActivity.class);
intent.putExtra("value", number);
startActivity(intent);
// it is always good to check if the value entered is a number only or not
// add inputType tag in the xml
// android:inputType="number" for the editText.
}
break;
}
}
Now, in order to get value in the next activity do this:
// write this inside the onCreate of the Activity.
int number;
if(getIntent().getExtras() != null) {
number = getIntent().getIntExtra("value");
}
// use the number then to display the tables
I'm taking an Android class based on this book:
http://www.deitel.com/Books/Android/AndroidforProgrammers/tabid/3606/Default.aspx
I'm working on the TipCalculator example, though it's been modified by the professor I think (to make it work with the new versions and he got the project most of the way done. It's TipCalculator-partial-layout.zip). I don't understand the concepts of how the stuff in the java file knows what seekbar to listen to. Can someone explain it to me? I've been told it has to do with the id, but I don't understand what that means.
This is a snippet from the main.xml file regarding the seekbar:
<SeekBar
android:id="#+id/customSeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_span="2"
>
</SeekBar>
This is a snippet from the main.xml file regarding the seekbar:
(part of onCreate)
// get the SeekBar used to set the custom tip amount
SeekBar customSeekBar = (SeekBar) findViewById(R.id.customSeekBar);
customSeekBar.setOnSeekBarChangeListener(customSeekBarListener);
Then there's the listener object:
private OnSeekBarChangeListener customSeekBarListener =
new OnSeekBarChangeListener()
{
// update currentCustomPercent, then call updateCustom
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser)
{
// sets currentCustomPercent to position of the SeekBar's thumb
currentCustomPercent = seekBar.getProgress();
updateCustom(); // update EditTexts for custom tip and total
} // end method onProgressChanged
#Override
public void onStartTrackingTouch(SeekBar seekBar)
{
} // end method onStartTrackingTouch
#Override
public void onStopTrackingTouch(SeekBar seekBar)
{
} // end method onStopTrackingTouch
}; // end OnSeekBarChangeListener
In this xml:
<SeekBar
android:id="#+id/customSeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_span="2"
>
There's a line that says "#+id/customSeekBar". That line approximately meands "add an android id with the name 'customseekbar'.
Then, in the java code, you're calling:
SeekBar customSeekBar = (SeekBar) findViewById(R.id.customSeekBar);
Which says: find the android view with the id "customSeekBar" (from the XML) and cast it as a SeekBar, since findViewById returns a more generic View.
Then you can call all your java methods on it, like assigning listeners.
Does this make sense?
It might be worth looking into an "android basics", "android for beginners" or "getting started with android" book.
If you change something in the XML files, Java classes are generated from that. If an item has an id you can look it up. The class where all the ids are stored is named R
So if you execute
SeekBar customSeekBar = (SeekBar) findViewById(R.id.customSeekBar);
You are getting the numeric id for customSeekBar from the R class and looking for the component with that id, which is your SeekBar. In the next line you just use that SeekBar and add a listener to it.
android:id="#+id/customSeekBar" declares the name of your SeekBar that we have used before. If you change it to e.g. android:id="#+id/foo" you would get your SeekBar with
SeekBar customSeekBar = (SeekBar) findViewById(R.id.foo);
If you put an element in your layout (e.g. SeekBar) with the id "#+id/customSeekBar", it will be mapped in the code to R.id.customSeekBar. This "magic" is done by the R automatically generated file. Thus findViewById(R.id.customSeekBar) can be used to reach exactly that layout element.
The R file (located in the /gen folder) can map layout elements (called views - for example R.id.myView), layouts themselves (R.layout.myLayout), predefined strings (R.string.my_string), and other elements you will learn in due time.