I'm new to Java and I encountered the following code:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = new Button(this);
button.setText("Touch That!");
button.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
MainActivity.this.onButtonClick(v);
}
});
RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.rootlayout);
relativeLayout.addView(button);
}
public void onButtonClick(View view){
//do something when button is clicked.
}
}
I didn't understand the syntax, View.OnClickListener() c'tor is called and it is followed by {} and overidding method.
what does this syntax stand for?
to which object this refers?
My guess is the button. but if I'm right why to use MainActivity.this instead of this? (the object that invoked the method)
This is an anonymous class declaration. It means that you will override some methods inside the class dynamically.
Take a look at this arcticle:
http://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html
About your second question, MainActivity.this refers to the instance of the Activity you are currently in. If you call only this, it would refer to the actual object. When you call MainActivity.this, you will get the instance of MainActivity you are in, even if there is more activities created. Take a look at Android's activity lifecycle.
What's the difference between this and Activity.this
Hope it helps.
By calling
new View.OnClickListener(){}
you are creating an object implementing interface OnClickListerner that requires you to implement the click method.
Someone can correct if I am wrong.
Related
I call a view class from my activity. Then the view class calls the same activity. Here is the problem, once the activity comes back up, it won't register any more button pushes.(I'm trying to call another view class. Here is some code:
View Class
public class AnimationView extends View {
Activity myActivity;
//...
public AnimationView(Context context, Activity activity) {
super(context);
//...
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//...
myActivity.setContentView(R.layout.activity_home);
}
}
Home Activity
public class HomeActivity extends AppCompatActivity {
private AnimationView mDrawViewA;
///...
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
mDrawViewA = new AnimationView(this,this);
start = (Button) findViewById(R.id.startButton);
//...
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//...
setContentView(mDrawViewA);
//calls more views
//......
});
}
I realize now maybe I should have been calling the view classes in different activities, but I would very much like a get all the view classes working within the same activity.
The problem is you're calling setContentView every time you press the "start" button. This method will overwrite the current layout (if any) with the new value you're setting.
What you can do to get the result you're expecting, which, from what I understand, is to add a new AnimationView to your current layout on every button click, you can try something like this:
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AnimationView animationView = new AnimationView(getApplicationContext());
// I'm using ConstraintLayout as an example, since I don't know exactly what layout you're using
ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
// Set the layout params the way you want
addContentView(animationView, params); // This is where the magic happens
}
});
In short, addContentView is the method you should use when you want to add new views into your activity's root layout.
PS.: It's a terribly bad practice to let the views "know" the activity controlling it. It's always the opposite way around: the activity/fragment knows the view(s) it's controlling.
I have been doing this for all my activities when I reference an element from my UI, I create a class variable. This can sometimes lead to 10 - 20 class variables just for UI elements:
public class CommentActivity extends AppCompatActivity {
LinearLayout addComment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_comment);
addComment = (LinearLayout) findViewById(R.id.addcomment);
addComment.setOnClickListener( // add an onclick listener here //);
}
}
Now, I have observed by looking at other people's code that sometimes they would do this instead:
public class CommentActivity extends AppCompatActivity {
// LinearLayout addComment; no more reference to class variable
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_comment);
//they just findViewById and add on the onclick listener
findViewById(R.id.addcomment).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
}
Is the second method more memory efficient? There is no longer a class variable strong reference and therefore garbage collection can happen more easily. But I'm just wondering what the risk is of using the second method. If garbage collection happens when using the app, does the addComment linearLayout lose its click functionality?
I'm just trying ways to optimise my app's memory use.
Is the second method more memory efficient?
Not particularly. The LinearLayout addComment reference costs ~8 bytes.
There is no longer a class variable strong reference and therefore garbage collection can happen more easily
Not in this case, since other things are holding onto the LinearLayout. After all, findViewById() is getting the LinearLayout from somewhere.
I'm trying to execute more then one layout screens from single class using onClick() method
Here goes my code
Button bt1,bt2;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt1 = (Button)findViewById(R.id.button);
bt2 = (Button)findViewById(R.id.button1);
onClick(); //onClick(View) in MainActivity cannot be applied to ()
}
public void onClick(View v){
if(v.getId()==R.id.button){
setContentView(R.layout.next1);
}
else if(v.getId()==R.id.button){
setContentView(R.layout.next1);
}
}
Kindly help me out, Thank you
Fragment is what you have to use, in this case. Load either of the fragment based on button click.
If you go for setContentView in this scenario, then your code will be clumsy and it will be very tedious for you to keep track on view.
I'm making an application on Android which is to contain 2 games. I've done this but I've come across a problem that the two buttons that are supposed to extend to different GameViews are extending to the same GameViews. The classes both have different names and I've tried changing some of the content to specifically refer to the BallGameView class however it causes the program not to compile. I've had a look around to see if there's anything on extending to 2 separate GameViews in a single application but not came across anything so far.
EDIT: For clarity, the problem is that the buttons that should open different games are opening the same game. The game is compiling but not as I want it to. I'll post the code that's referring to the different games below.
public class BallGameActivity extends Activity {
GameView GV;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ballgame);
GV = new GameView(this);
setContentView(GV);
To refer to Ball Game.
public class BallSplash extends Activity implements View.OnClickListener {
Button playBallButton;
Button guideButton;
Intent ballIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ball_splash);
playBallButton = (Button)findViewById(R.id.startBallGame);
guideButton = (Button)findViewById(R.id.guideButton);
playBallButton.setOnClickListener(this);
guideButton.setOnClickListener(this);
}
public void onClick(View view) {
switch (view.getId()) {
case R.id.startBallGame:
ballIntent = new Intent(this,BallGameActivity.class);
startActivity(ballIntent);
break;
case R.id.guideButton:
ballIntent = new Intent(this,Guide.class);
startActivity(ballIntent);
break;
}
}
To refer to Sprite Game
public class Splash extends Activity implements View.OnClickListener {
Button playButton;
Button instructionButton;
Intent intent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
playButton = (Button)findViewById(R.id.toPlay);
instructionButton = (Button)findViewById(R.id.toInstructions);
playButton.setOnClickListener(this);
instructionButton.setOnClickListener(this);
}
public void onClick(View view) {
switch (view.getId()) {
case R.id.toPlay:
intent = new Intent(this,GameActivity.class);
startActivity(intent);
break;
case R.id.toInstructions:
intent = new Intent(this,InstructionActivity.class);
startActivity(intent);
break;
}
}
Maybe the problem exists because you call setContentView() twice. You should remove the wrong one.
The correct way to do it is to call that class that you want to use as the view
BallGameView GV = new BallGameView(this);
setContentView(GV);
in your current code you are instantiating GameView but that isn't what you want for this Activity. You need to instantiate BallGameView GV instead. Since you are using
GV = new GameView(this);
setContentView();
in both Activities, you are seeing the same thing no matter which Activity you start. So the problem was never with starting an activity or extending anything.
Also, you can remove
setContentView(R.layout.activity_ballgame);
That line will set the Activity to use that layout. But since you are calling setContentView() again and using the class which extends SurfaceView then it will set the Activity to use that as the layout instead, making the above line useless.
What is the difference between:
public class MainActivity extends Activity {
public void onCreate (Bundle savedInstanceState) {
button1 = (Button) findViewById(R.id.btn1);
button1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// Click code
}
)};
}
}
And:
public class MainActivity extends Activity implements OnClickListener {
public void onCreate (Bundle savedInstanceState) {
button1 = (Button) findViewById(R.id.btn1);
button1.setOnClickListener(this);
}
public void onClick(View arg0) {
switch(arg0.getId()) {
case R.id.button1:
// Click code
break;
}
}
}
They have both the exact same functionality and results.
The first method uses an anonymous inner class that implements the interface method. By using this approach, you receive events only for that particular View.
In the second method, you entire Activity class implements the OnClickListener interface. You can set the OnClickListener of every View to this, and receive all the click events in one method, where you can then filter them and act upon them.
The first method translates to:
Button.OnClickListener anonymous_listener = new Button.OnClickListener() { ... };
button.setOnClickListener(anonymous_listener);
Which is to say that it dynamically creates and stores a new OnClickListener instance when you use it.
In the second method, your entire class uses one single instance of the OnClickListener, that is passed to all the Views you want to listen for clicks on.