• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Apps Button Issue

I am developing a small android application for my martial arts club however, whenever it opens, it force closes straight away.

The way it is meant to go is like so.. You open the app (loads main.xml) then you press a button (button1) to continue to bels.xml. So far, I am trying to make the whitebelt button (button2) go to whitebelt.xml.

I have the pages/screens created and here is the activity.java file.
[Java] EvolutionTheoryHelperActivity.java - Pastebin.com

Now, its this part that is causing the issue as if I remove it, it works fine... However it doesn't allow my button2 to work.
Code:
Button button2 = (Button)this.findViewById(R.id.button2);
    button2.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View whitebelt) {
           // button 1 was clicked!
                setContentView(R.layout.whitebelt);
        }
        });
Do you think you could help?
Regards,

--Conor Calby
 
I personally hate when I see someone create an object within a method parameter....oh well, java.

Basically part of the problem is scope I think. You are calling a method of the activity from within a listener. And since a listener does not extend Activity, AND it is being created inside a method of another object it has no such method itself.

Anyways, try this -- it should be more clear this way:
Code:
//MyActivity.java

Button button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(myButton2listener);


// this is now an inner class and can "see" the methods in the activity
// let's have it call our own protected method setSecondContentView()

View.OnClickListener myButton2listener = new View.OnClickListener() 
{         
     @Override         
     public void  onClick(View v) 
     { 
         // button 2 was clicked!                  
          setSecondContentView();
     }         
}



protected void setSecondContentView()
{
     setContentView(R.layout.whitebelt);
}
if that doesnt work, post the stack trace and we'll see if we can figure it out from there :)
 
Your problem is, indeed, a scope issue.

Furthermore, alostpacket's solution will not work either. The reason is that, like alostpacket stated, you are both creating an inner class. Inner classes are ultimately bad programming practices, but they are often "forgiven" in Android development (why, I am not sure). In any rate, the reason they are looked down upon in normal practice is for this reason. Scope becomes a pain in the rear end to manage and often leads to hard-to-find bugs.

At any rate, what you both are doing is creating a new interface and attempting to call a method of another class (the Activity subclass) in your new interface (the listener). You really only have a couple ways to go about this correctly:

1) Perhaps the simplest is to make your activity class the listener by implementing the listerner using the implements keyword.

Example:
Code:
public class MyActivity extends Activity implements View.OnClickListener
{
       ...
       Button button2;
       ...
       @override
       public void onCreate(Bundle savedInstanceState)
       {
               super.onCreate(savedInstanceState);
               ...
               button2 = (Button)findViewById(R.id.button2);
               button2.setOnClickListener(this);
               ...
       }

       @Override
       public void onClick(View v)
       {
            if(v == button2)
                 this.setContentView(R.layout.whitebelt);
       }
}

2) The second, more accepted approach, is to create another class that implements the listener and pass a pointer to the Activity subclass as a parameter of the constructor. Then, use that pointer to call the setContentView method inside onClick. Inside of your Activity subclass, you would create an instance of the new class.

Since you are apparently new to Java, and likely OOP in general, I would recommend making things easy on yourself and using the 1st approach. Although it is not the best programming practice, it gets the job done and is easy to implement.
 
Furthermore, alostpacket's solution will not work either.

Ahem :)

I do this all the time...I'm looking at an identical method in one of my apps :p


Anyways, the problem with my solution is that the compiler generates all those $access2000 static methods because it's not sure if inner classes accessing private/protected methods of the outer class is valid (even though it technically is)

One way to solve that though is to make any method called by an inner class have package level scope. A bit "dangerous" but it reduces code size and is better for performance.

The problem with your solution (#1) is you have taken a step towards making the activity the God anti-pattern. I dont like having my activities handle all the work. Making listener objects (seems at least) to make them more portable down the road for refactoring. Solution #2 is good though.

Either way they all have ups and downs :) Also I totally agree/hate inner classes.
 
Example:
Code:
public class MyActivity extends Activity implements View.OnClickListener
{
       ...
       Button button2;
       ...
       @override
       public void onCreate(Bundle savedInstanceState)
       {
               super.onCreate(savedInstanceState);
               ...
               button2 = (Button)findViewById(R.id.button2);
               button2.setOnClickListener(this);
               ...
       }

       @Override
       public void onClick(View v)
       {
            if(v == button2)
                 this.setContentView(R.layout.whitebelt);
       }
}

Since you are apparently new to Java, and likely OOP in general, I would recommend making things easy on yourself and using the 1st approach. Although it is not the best programming practice, it gets the job done and is easy to implement.
This is honestly the only app I will ever create for Android. I only started with OOP a few months ago so it is fairly new to me.

Here is what I have.
[Java] package com.example.android.apis.tests; import android.app.Activity; import - Pastebin.com

Sorry for the n00bness. :P
 
The code looks correct in paste bin to me, maybe something in your manifest? did you add the activity correctly?

What does Logcat say?
 
OK it looks like button 2 is null...
Caused by: java.lang.NullPointerExceptionE/AndroidRuntime( 428): at com.example.android.apis.tests.EvolutionTheoryHelperActivity.onCreate(EvolutionTheoryHelperActivity.java:22
^ check line 22... then make sure R.id.button2 is the id for your second button and that it exists in the main.xml layout
 
Button 2 does not exist in main.xml but belt.html. Could that be the problem?

The way it goes to
User loads app>> main.xml (click to continue type page (button 1))>>belt.xml (click belt for belt info type page. buttons 2-10)>> *User clients white belt (button 2)*>>whitebelt.xml
 
ah yes, that is the problem then. You should move the part where you set the listener of button2 to AFTER you change the content view. You will also need to move the "findViewById" bit.
 
basically, any time you change the contentview, you will reset what objects are available.

You might want to look at something like a viewstub, instead of changing your whole content view
 
Wow. Thanks mate! Got it now. Added
Code:
    @Override
    public void onClick(View v)
    {
         if(v == button1)
              this.setContentView(R.layout.belt);
         
         button2 = (Button)findViewById(R.id.button2);
         button2.setOnClickListener(this);
         if(v == button2)
             this.setContentView(R.layout.whitebelt);
    };

What you said makes sense regarding the reset objects. Thanks again!
 
Ahem :)

I do this all the time...I'm looking at an identical method in one of my apps :p


Anyways, the problem with my solution is that the compiler generates all those $access2000 static methods because it's not sure if inner classes accessing private/protected methods of the outer class is valid (even though it technically is)

One way to solve that though is to make any method called by an inner class have package level scope. A bit "dangerous" but it reduces code size and is better for performance.

The problem with your solution (#1) is you have taken a step towards making the activity the God anti-pattern. I dont like having my activities handle all the work. Making listener objects (seems at least) to make them more portable down the road for refactoring. Solution #2 is good though.

Either way they all have ups and downs :) Also I totally agree/hate inner classes.

Oops... after reconsidering what I said, I realize now that I was wrong.. In fact, the way he had it initially should have worked as well. Since the class was defined withing another class, all data members of the outer class would therefore be available to the inner class as well...

I apologize for the brain fart. haha
 
Oops... after reconsidering what I said, I realize now that I was wrong.. In fact, the way he had it initially should have worked as well. Since the class was defined withing another class, all data members of the outer class would therefore be available to the inner class as well...

I apologize for the brain fart. haha


No worries, I was thinking to myself when I read the OP "shouldn't this work?" But somehow was convinced since he was creating the inner class/object IN the param of a method it somehow lost scope.... but I guess it doesnt matter :)
 
I think for scrollview you need a single child set to wrap content for it to work correctly..... not sure if that helps :)
 
Back
Top Bottom