Question

I am invoking from a menu Item a Dialog and I have a Button inside that Dialog and trying to do something when I press the button. The part of my code for this is as followed:

    public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.itTip:
        final Dialog tipCalculator = new Dialog(this);
        tipCalculator.setTitle("Tip Calculator");
        tipCalculator.setContentView(R.layout.tip_layout);

        totalBill = (EditText) findViewById(R.id.editTBill);
        tips = (EditText) findViewById(R.id.editTTip);
        calculate = (Button) findViewById(R.id.bCalcTip);
        tvResult = (TextView) findViewById(R.id.tvTipResult);

        calculate.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(), "Calculate clicked", Toast.LENGTH_SHORT).show();
            }
        });

        tipCalculator.setCancelable(true);
        tipCalculator.show();
        break;

    }
    return super.onOptionsItemSelected(item);
}

When I run my app, without the setOnClickListener, it works fine and shows the Dialog perfectly. But whenever I am trying to use the Listener, it crashes. I checked in LogCat and could actually not understand the problem clearly. Hope anyone can help me here.

Was it helpful?

Solution

I think the problem is because you attempt to find the view before you have actually shown it, this causes 'calculate' to be null when attempting to assign a onClickListener, and thus throws a null pointer exception.

To explain in a bit more detail, findViewById searches all the views currently being displayed and returns the view that matches that id. The button is contained in R.layout.tip_layout, but that view is not inflated until tipCalculator.show() is called and it won't be included in the list of views searched, so findViewById returns null.

There are a few approaches you could take to make this work, but I think the following would require the least alterations to your original code:

case R.id.itTip:
    final Dialog tipCalculator = new Dialog(this);
    tipCalculator.setTitle("Tip Calculator");
    View contentView = View.inflate(this, R.layout.tip_layout, null);

    totalBill = (EditText) contentView.findViewById(R.id.editTBill);
    tips = (EditText) contentView.findViewById(R.id.editTTip);
    calculate = (Button) contentView.findViewById(R.id.bCalcTip);
    tvResult = (TextView) contentView.findViewById(R.id.tvTipResult);

    calculate.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            Toast.makeText(getApplicationContext(), "Calculate clicked", Toast.LENGTH_SHORT).show();
        }
    });

    tipCalculator.setContentView(contentView);
    tipCalculator.setCancelable(true);
    tipCalculator.show();
    break;

What we do different is inflate the view in advance (contentView) and define where to find each widget by searching that view specifically.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top