TomFirth TomFirth - 3 years ago 163
Android Question

Android programmatically created button onClick from class

I have an

onClick
switch method in MainActivity.java and the buttons are programmatically created in Navigation.java. The initial menu
nav.mainMenu()
gets called correctly and the button is created as expected. My issue is that when I click the button, nothing happens.

I get no error stack trace in the logcat. I have tried putting logs in the onclick method, but it doesn't get that far. The emulator appears to work and does not freeze or crash.

I assume that when I send the code to the menu, the activity is in that class? so when I try to use the
onClickListener
in
MainActivity
, it isn't aware of it?

I'm also not sure what I should be expecting from
v.getId()
in MainActivity.java
R.id.btnGame
?

MainActivity.java

public class MainActivity extends Activity implements View.OnClickListener {

public Navigation nav = new Navigation(this);

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.empty);
nav.mainMenu();
}

@Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.btnGame:
nav.game();
break;
}
}
}


Navigation.java

public class Navigation {

Button btnGame;

Context mContext;
Navigation(Context mContext) {
this.mContext = mContext;
}

public void mainMenu() {
LinearLayout ll = new LinearLayout(mContext);
ll.removeAllViews();
LinearLayout.LayoutParams llP = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
ll.setLayoutParams(llP);
ll.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams btnParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);

btnGame = new Button(mContext.getApplicationContext());
btnGame.setLayoutParams(btnParams);
btnGame.setText("Play Game");
ll.addView(btnGame);

Activity activity = (Activity) mContext;
activity.setContentView(ll);
}

public void game() {
Toast.makeText(mContext, "I dont see this", Toast.LENGTH_SHORT).show();
}
}



  • I have tried adding
    .setOnClickListener()
    to the buttons in Navigation.java but I can't get the context right, I don't know if that's what is missing.

  • Extending Navigation.java to MainActivity or Activity gives me a loop of errors.



Logcat after the app has been built onto the emulator:

09-30 17:43:59.655 7038-7038/? I/art: Not late-enabling -Xcheck:jni (already on)
09-30 17:43:59.655 7038-7038/? W/art: Unexpected CPU variant for X86 using defaults: x86
09-30 17:43:59.854 7038-7038/com.fomtirth.barcodebattle W/System: ClassLoader referenced unknown path: /data/app/com.fomtirth.barcodebattle-2/lib/x86
09-30 17:43:59.867 7038-7038/com.fomtirth.barcodebattle I/InstantRun: starting instant run server: is main process
09-30 17:44:00.230 7038-7066/com.fomtirth.barcodebattle I/OpenGLRenderer: Initialized EGL, version 1.4
09-30 17:44:00.230 7038-7066/com.fomtirth.barcodebattle D/OpenGLRenderer: Swap behavior 1
09-30 17:44:00.230 7038-7066/com.fomtirth.barcodebattle W/OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
09-30 17:44:00.230 7038-7066/com.fomtirth.barcodebattle D/OpenGLRenderer: Swap behavior 0
09-30 17:44:00.234 7038-7066/com.fomtirth.barcodebattle D/EGL_emulation: eglCreateContext: 0x9baa38c0: maj 2 min 0 rcv 2
09-30 17:44:00.241 7038-7066/com.fomtirth.barcodebattle D/EGL_emulation: eglMakeCurrent: 0x9baa38c0: ver 2 0 (tinfo 0x99a887d0)
09-30 17:44:00.293 7038-7066/com.fomtirth.barcodebattle D/EGL_emulation: eglMakeCurrent: 0x9baa38c0: ver 2 0 (tinfo 0x99a887d0)
09-30 17:44:00.400 7038-7066/com.fomtirth.barcodebattle D/EGL_emulation: eglMakeCurrent: 0x9baa38c0: ver 2 0 (tinfo 0x99a887d0)
09-30 17:44:00.460 7038-7066/com.fomtirth.barcodebattle D/EGL_emulation: eglMakeCurrent: 0x9baa38c0: ver 2 0 (tinfo 0x99a887d0)

Answer Source

You cannot assign a Context from a field. You probably "can't assign a right", because you're actually getting a nullpointerexception and editing the wrong location. That being said, getApplicationContext() isn't needed.

Also, might I suggest that you return the content layout rather than casting the context to an Activity?

public Navigation nav;

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  nav = new Navigation(this);
  setContentView(nav.mainMenu());

} 

@Override
public void onClick(View v) {
  switch(v.getId()) {
    case R.id.btnGame:
      nav.game();
      break;
  }
}

At first glance, I see that you never set a click listener on the button, so you should probably do that.

For example

Context mContext;
View.OnClickListener mClickListener;

Navigation(Context context) {
    this.mContext = context;
    if (context instanceof View.OnClickListener) {
        this.mClickListener = (View.OnClickListener) context ;
    } 
}

Now use this

if (mClickListener!=null) {
    button.setOnClickListener(mClickListener);
}

I'm also not sure what I should be expecting from v.getId() in MainActivity.java R.id.btnGame?

The ID doesn't match the variable name. Without explicitly giving the button an ID, it'll be -1

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download