Reputation: 215
I must be doing something very stupid. This is my second app - the first worked fine (honest).
I've just got a basic title screen with a button on it but nothing happens when I click on the button. The screen appears correctly but no response from the button - I've tried it in debug but nothing...no error, no info message, zilch (I'm using the AVD).
This is my code...
Manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.spyeye"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/spyEyeTheme" >
<activity
android:name="com.example.spyeye.TitleScreen"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.spyeye.createNewGameActivity"
android:label="@string/app_name"
android:parentActivityName="com.example.spyeye.TitleScreen" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.spyeye.TitleScreen" />
</activity>
XML file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".TitleScreen" >
<ImageView
android:src="@drawable/spyeyelogo"
android:contentDescription="@string/logo"
android:layout_centerHorizontal="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/logo" />
<Button
android:id="@+id/newBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/logo"
android:layout_centerHorizontal="true"
android:layout_marginTop="50dp"
android:onClick="newGame"
android:text="@string/newTxt" />
Java file:
public class TitleScreen extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_title_screen);
}
public void newGame (View v) {
// create intent to start another activity
Intent newGameIntent = new Intent(this, createNewGameActivity.class);
startActivity(newGameIntent);
}
}
The only major difference between this and my other app is that I have now tried to use a single style file and I've re-designed my own buttons:
<style name="spyEyeTheme" parent="android:Theme.Light">
<item name="android:buttonStyle">@style/myButton</item>
</style>
<style name="myButton" parent="android:Theme.Light">
<item name="android:background">#008080</item>
<item name="android:textColor">#FFFFFF</item>
<item name="android:textSize">24sp</item>
<item name="android:typeface">sans</item>
<item name="android:padding">10sp</item>
</style>
Anyone see the obvious mistake I must have made?
Upvotes: 0
Views: 76
Reputation: 49807
Personally I am really not a big fan of that android:onClick="newGame"
stuff. You should try it the good old-fashioned way, like this:
public class TitleScreen extends Activity {
private Button newBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_title_screen);
this.newBtn = (Button) findViewById(R.id.newBtn);
this.newBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent newGameIntent = new Intent(this, createNewGameActivity.class);
startActivity(newGameIntent);
}
});
}
}
Or like this:
public class TitleScreen extends Activity implements View.OnClickListener {
private Button newBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_title_screen);
this.newBtn = (Button) findViewById(R.id.newBtn);
this.newBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Intent newGameIntent = new Intent(this, createNewGameActivity.class);
startActivity(newGameIntent);
}
}
If you are dealing with multiple Buttons
you can handle them in one OnClickListener
like this:
private final View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
final int id = view.getId();
switch (id) {
case R.id.newBtn:
Intent newGameIntent = new Intent(this, createNewGameActivity.class);
startActivity(newGameIntent);
break;
case R.id.otherButton:
Toast.makeText(this, "Other Button clicked!", Toast.LENGTH_SHORT).show();
break;
case R.id.cancelButton:
...
break;
}
}
};
You get the id of the calling View
and use a switch to differentiate between the specific Buttons
. For example in your Activity
you can implement this like this:
public class TitleScreen extends Activity implements View.OnClickListener {
private Button newBtn;
private Button otherBtn;
private Button cancelBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_title_screen);
this.newBtn = (Button) findViewById(R.id.newBtn);
this.newBtn.setOnClickListener(this);
this.otherBtn = (Button) findViewById(R.id.otherBtn);
this.otherBtn.setOnClickListener(this);
this.cancelBtn = (Button) findViewById(R.id.cancelBtn);
this.cancelBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
final int id = view.getId();
switch (id) {
case R.id.newBtn:
Intent newGameIntent = new Intent(this, createNewGameActivity.class);
startActivity(newGameIntent);
break;
case R.id.otherBtn:
Toast.makeText(this, "Other Button clicked!", Toast.LENGTH_SHORT).show();
break;
case R.id.cancelBtn:
...
break;
}
}
}
A few things that caught my eye:
createNewGameActivity
you Activity
should be called CreateNewGameActivity
.Fragments
. The golden age of Activities
is over. Since Fragments
were introduced Activities
are just supposed to be containers for the Fragments
. So even if you just have one Button
in your layout you should have an empty Activity
which just contains one Fragment
and in that Fragment
you implement your UI and logic.android:onClick
. There is no indication in the code that this method will be called at all. And there is no reason for the layout to assume that such a method exists anywhere in the View
, Fragment
or Activity
which loads the layout. And aside from that it isn't even that convenient. In 99,9% of all cases in which you need to set an OnClickListener
you also need to do other stuff with the Button
and then you need the reference anyway. android:onClick
just clutters your code and makes it more confusing. it spreads implementation details out and obscures it to the developer. That the layout knows or even defines specific implementation details is in itself already pretty bad.Upvotes: 2