Attempt to invoke virtual method in material dialog - java

I am using a library which can be found HERE to create material-design style dialog in an android app. I have made it so that the dialog opens when a FAB is clicked.
public void onClick(View v) {
final RatingBar mRatingBar = (RatingBar) findViewById(R.id.ratingBar);
final EditText input = (EditText) findViewById(R.id.editText);
new MaterialDialog.Builder(MainActivity.this)
.title(R.string.title)
.positiveText(R.string.agree)
.negativeText(R.string.disagree)
.customView(R.layout.dialog_view, true)
.callback(new MaterialDialog.ButtonCallback() {
#Override
public void onPositive(MaterialDialog dialog)
String sentReview = input.getText().toString();
float starCount = mRatingBar.getNumStars();
}
})
.show();
}
The dialog successfully opens, and everything works well until I click the positive button "send". It then says "unfortunately DemoApp has stopped".
The exception is : java.lang.NullPointerException: Attempt to invoke virtual method 'android.text.Editable android.widget.EditText.getText() on a null object reference.
The line that appears to be causing it is: String sentReview = input.getText().toString();.
If I comment the section which deals with the edit text and sent Review, the same problem will appear with my rating bar.
I have seen similar questions, but none of them precisely match my problem, and none of the methods they use work when I attempt to apply them to my application.
Thanks,
Geffen Avraham

Related

Android Studio Error: Attempt to invoke virtual method 'android.text.Editable android.widget.EditText.getText()' on a null object reference [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 1 year ago.
I have been trying to create this custom dialog window for my app, where it will pop up when pressed and request the user's numerical input. I have tested this custom dialog thing before and it has worked in the past successfully, however when I tried it in this case, it kept throwing out the error of "Attempt to invoke virtual method 'android.text.Editable android.widget.EditText.getText()' on a null object reference" at
final EditText inputNumber = input_score.findViewById(R.id.inputNumber);
numberOfPoints = Integer.parseInt(inputNumber.getText().toString());
This error, when pressing the button to bring up the custom pop-up window, would cause the screen to blackout for a few seconds before returning to the app's main menu. What's supposed to happen is the dialog window popping up to get the user's input
private void openDialog() {
input_score = new Dialog(this);
beginButton = findViewById(R.id.beginButton);
final EditText inputNumber = input_score.findViewById(R.id.inputNumber);
numberOfPoints = Integer.parseInt(inputNumber.getText().toString());
input_score.setContentView(R.layout.input_score);
input_score.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
input_score.show();
beginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (inputNumber.getText().toString().trim().isEmpty()) {
//change textview to error for a few seconds before returning to normal
} else {
if (Integer.parseInt(inputNumber.getText().toString()) <= 0 || Integer.parseInt(inputNumber.getText().toString()) > 900) {
startActivity(new Intent(MainMenu.this, MainGame.class));
}
}
}
});
Full Error Log:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.rockpaperscissors, PID: 4683
java.lang.NullPointerException: Attempt to invoke virtual method 'android.text.Editable android.widget.EditText.getText()' on a null object reference
at com.example.rockpaperscissors.MainMenu.openDialog(MainMenu.java:67)
at com.example.rockpaperscissors.MainMenu.access$000(MainMenu.java:20)
at com.example.rockpaperscissors.MainMenu$1.onClick(MainMenu.java:47)
at android.view.View.performClick(View.java:7217)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119)
at android.view.View.performClickInternal(View.java:7191)
at android.view.View.access$3500(View.java:828)
at android.view.View$PerformClick.run(View.java:27679)
at android.os.Handler.handleCallback(Handler.java:900)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:219)
at android.app.ActivityThread.main(ActivityThread.java:8347)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)
I'm not sure how I go about exactly fixing this, so please do point out the errors made in the code to improve and sort it out. Thank you
EDIT: As #Shay Kin showed, he used a onShowListener then put the button Listener within it, so that it would know that when this dialog would pop up, then to pop up the button function along with it. In my case, the reason the code kept breaking was not only because of mispositioning the .show but also due to the fact that I had this variable "numberOfPoints" which kept parsing an empty text field and breaking the code since no value was inside. I had not noticed this until I went through it deeply again and deleted that variable.
The things I did to fix the code was by implementing his solution, which had already incorporated the buttonListener into it, and delete the numberOfPoints variable. This resulted in the program being fixed and working successfully
Maybe because the EditText is in a different scope? Try declaring the EditText outside the function (Beside your other components). The onClick() function is a callback so maybe the EditText is being disposed of once the openDialog() finishes executing.
Before you call Dialog.show(), the view doesn't yet exist, thus your findViewById() doesn't find the desired view, returning null instead. The views would only be available after calling either show() or create().
Since you don't actually need it in advance, you can move this initialization to where you actually need it.
beginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Initialize it here
final EditText inputNumber = input_score.findViewById(R.id.inputNumber);
if (inputNumber.getText().toString().trim().isEmpty()) {
//change textview to error for a few seconds before returning to normal
} else {
if (Integer.parseInt(inputNumber.getText().toString()) <= 0 || Integer.parseInt(inputNumber.getText().toString()) > 900) {
startActivity(new Intent(MainMenu.this, MainGame.class));
}
}
}
});
However, it's important to mention that you should avoid using the Dialog class directly, as per official documentation.
As #Gabriel said You got NullPointerException because you initialize the EditText After the dialog is shown so you can add listener and when you're Dialog is become visible here you can initialize all your view
private void openDialog() {
input_score = new Dialog(this);
input_score.setContentView(R.layout.speach_dialog);
input_score.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
input_score.setOnShowListener(new DialogInterface.OnShowListener() {
#Override
public void onShow(DialogInterface dialog) {
beginButton = findViewById(R.id.beginButton);
final EditText inputNumber = input_score.findViewById(R.id.inputNumber);
numberOfPoints = Integer.parseInt(inputNumber.getText().toString());
beginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (inputNumber.getText().toString().trim().isEmpty()) {
//change textview to error for a few seconds before returning to normal
} else {
if (Integer.parseInt(inputNumber.getText().toString()) <= 0 || Integer.parseInt(inputNumber.getText().toString()) > 900) {
startActivity(new Intent(MainMenu.this, MainGame.class));
}
}
}
});
}
});
input_score.show();
}

Test a Snackbar with UiAutomator, is there a way?

I'm starting to study UIAutomator on Android.
I created a simple poc project, inside this there are a very few elements : one button and one editText.
The behaviour is quite simple:
When I push the botton the message written in the editText appears in a snackBar.
Now I want to make two simple test :
see if the snackbar correctly appears
see if the editTest message is
correctly reported in the snackbar
For point one I have done in this way :
#Test
public void pressEmailButton() throws UiObjectNotFoundException {
mDevice.findObject( By.res(POC_PACKAGE,"fab") ).click();
// wait for the snackBar appear
UiObject snackBar2 = new UiObject (new UiSelector().text("Send"));
// Verify the snackBarIsShowed is displayed in the Ui
assertTrue("Timeout while snackbar", snackBar2.waitForExists(1000));
}
That is i'm watching the snackbar's action to check if the snack bar is correctly opened . Are there the better ways to do that? In this way if there are more elements named in the same way of the snackbar's action I will have a problem
For the second point I don't find a way to test it.
I have to use only uiAutomator and not Espresso :)
Thanks to everyone :)
I just tried it in a new android project: I have one Button in the main layout and show the snackbar on button click like this:
button = (Button) findViewById(R.id.button);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
View parentLayout = findViewById(R.id.root_layout);
Snackbar.make(parentLayout, "Snackbar Text", Snackbar.LENGTH_LONG)
.show();
}
});
In my test I then test it like this:
//With espresso:
onView(withId(R.id.button)).perform(click()); //click the button
onView(withText("Snackbar Text")).check(matches(isDisplayed()));
and the same with using UI Automator:
UiDevice mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
UiObject snackbarTextView = mDevice.findObject(new UiSelector().text("Snackbar Text"));
if(!snackbarTextView.getText().equals("Snackbar Text")) {
throw new RuntimeException("No snackbar!");
}
Both tests are working just fine!
Another way to select the Snackbar text would be via the resource id like this:
//replace the package name in the next line with your package name
UiObject snackbarTextView = mDevice.findObject(new UiSelector().resourceId("com.example.testespressoapplication:id/snackbar_text"));
The way you did it also works but is deprecated so I would not use it, as the documentation says:
* #deprecated Use {#link UiDevice#findObject(UiSelector)} instead. This version hides
* UiObject's dependency on UiDevice and is prone to misuse.

Refactored Android AlertDialogBuilder code to another class, style of the dialog breaks

I created two fairly long functions which create an AlertDialogBuilder which builds an AlertDialog which is populated and launched. The alert dialogs produced are fairly large for dialogs, so a lot of views need to be populated within the dialog. For the sake of cleanliness, testability, SRP etc. I decided to move these functions into a new class.
Originally the functions were placed directly in the Activity class, and the alert dialogs launched fine. I've now moved both to an AlertDialogLauncher class, which takes an Activity parameter when launched, most of the original code is the same, I've got the alert dialog working, but the colours of the text and background colours of some of my views are off.
So the dialog is launching fine, just with incorrect colours, so I imagine it is loading an incorrect style or something similar?
Code...
Original version (shortened)
private void addNormalRow(final ScannedWiFiNetwork network) {
TableRow row = (TableRow) View.inflate(this, R.layout.regular_network_table_row, null);
// loads of code
row.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
launchNewNetworkDialog(network);
}
});
}
private void launchPreferredNetworkDialog(final ScannedWiFiNetwork network) {
final AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle("Connect to "+network.getSsid()+"?")
.setView(getLayoutInflater().inflate(R.layout.preferred_network_dialog,null))
.setCancelable(false)
.show();
final EditText passwordInput = (EditText) dialog.findViewById(R.id.edit_text_password);
TextView passwordText = (TextView) dialog.findViewById(R.id.dialog_password);
//loads of code
}
Essentially, the launch dialog function is called and creates a new AlertDialog by passing the AlertDialog.Builder a reference to this (the Java class for my activity).
Refactored Activity/Interface class
private void addNormalRow(final ScannedWiFiNetwork network) {
TableRow row = (TableRow) View.inflate(this, R.layout.regular_network_table_row, null);
//loads of code
row.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Activity activity = (Activity) v.getContext();
dialogs.launchNewNetworkDialog(network, activity);
}
});
}
New AlertDialogLauncher class
public void launchPreferredNetworkDialog(final ScannedWiFiNetwork network, final Activity activity) {
Context con = activity.getApplicationContext();
LayoutInflater layoutInflater = LayoutInflater.from(con);
final AlertDialog dialog = new AlertDialog.Builder(activity)
.setTitle("Connect to "+network.getSsid()+"?")
.setView((layoutInflater.inflate(R.layout.preferred_network_dialog,null)))
.setCancelable(false)
.show();
As you can see, in this new class an Activity must be passed in to be used to create the layout inflater and context objects used later on to populate the views. All this works fine, however as mentioned earlier, the text colours change and the background of the buttons.
I'm loading the same xml layout file, so I'd assume it is loading an incorrect or default style somehow when I provide it with a default activity object (retrieved from calling getContext on the button view added to the dialog).
I've tried replacing 'activity' with NetworkListActivity.this (my activity name), that compiles but gives me the same ruined style outcome.
Thanks in advance for any help. Hope the question is clear!
Figured out my problem.. I never applied a style to my dialog xml layout file, some of the text views which I did not assign explicit text colors two are defaulting to the style of the dialog, I found this out when experimenting with changing the style which can be done by adding R.style.STYLE_NAME to the AlertDialogBuilder constructor (after the 'activity' parameter).
So yeah, I just didn't apply a style and need to be careful with views I haven't applied a style to!

null pointer exception when adding an onclicklistener to a button outside the main view

I want to have access to objects in views from views other than the main content view in the app. How can I go about doing this?
I am trying to add an onclicklistener, but it fails every time because the program can't seem to find the button.
02-12 15:26:29.034: E/AndroidRuntime(11788): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.evolutionsystems.kiroco/com.evolutionsystems.kiroco.OverviewActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
Or am I going about this the wrong way? Should I include all the buttons in the main view and have them set to hidden and then change them dynamically as the user interacts with the program?
EDIT - This is the type of code that throws the error.
final Button receiver = (Button) findViewById(R.id.receiver);
receiver.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
aboutKirocoClicked(v);
}
});
The receiver button is part of a different view to the content view so the program can't find it and it returns null.
When you call findViewById( int ) you are asking for a view within the context of the object you called.
So if this is an activity then the object must be part of the xml resource from setContent.
You can also find resources from other inflated layouts ( menu, fragement ), but you must call the findViewById on that object inorder to find the view.
Not to complicate your life, but once you are more comfortable with Android you may want to check out a dependency injection framework like Roboguice or Dagger.
In your Activity, where you would like your button to appear, you add the following code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//In activity_main.xml, you have a button.
setContentView(R.layout.activity_main);
//You get this button with the referencing ID
Button myBtn = (Button) findViewById(R.id.my_btn_id);
//Now, you can set your onClickListner
myBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Handle your button click
}
});
}

Android, using Edittext

I've got a few questions about edittext..
I'm trying to create a login screen on Android. I'm taking in a username and a password and then sending the results to another method. I've just got a few questions about it...
1) If I have two edittext's and the user enters values in both and then hits a "login" button, I want the button to take the values that were entered in the 2 edittext boxes, convert and save them to a string and then pass them to a function. I'm unsure how I'd construct this button. The problem I'm having is making it a string I'm currently doing this..
String user = edittext.getText();
But that doesn't seem to work. Also I'm unsure what way Android saves Edittext inputs.. Will it just automatically save it to the string once the user is no longer working out of the box? e.g will...
public boolean onKey(View v, int keyCode, KeyEvent event) {
String user = edittext.getText();
}
work? If not how would I define it?
Thanks.
You have to subscribe for the onClick event of the button,
then simple get the text from the EditText
You don't need to run code on the onKey event of EditText
(Button) findViewById(R.id.btnName)).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//called when you press the button
String user =((EditText) findViewById(R.id.txtUser)).getText().toString();
String password =((EditText) findViewById(R.id.txtPassword)).getText().toString();
// do the rest of the job
}
});
Essentially this is what you want to do
String userName = "";
String password = "";
EditText userEdit = (EditText)findViewById(R.id.useredit);
EditText passEdit = (EditText)findViewById(R.id.passedit);
Button okButton = (Button)findViewById(R.id.okButton);
okButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
userName = userEdit.getText().toString();
password = passEdit.getText().toString();
}
});
Instead of using onKeyDown(...) you should register an on-click listener for your button and define its behavior there. Strangely enough you actually have to put .toString() after .getText() in order to store the text.
I would also suggest making all of your views (fields, buttons, images, ect) member variables so your references are persistent.

Categories

Resources