I've read hundreds of explanations on "this" in java and I'm really having trouble grasping it. I'm learning android and java side-by-side, I know it's harder that way but I'm enjoying it. The one thing I'm getting killed on is "this"... I'm pasting code from a tutorial below that utilizes "this" one time. I was going to just put a piece of the code but want to be as helpful as possible.
I'm looking for a good explanation of "this" that I can add to my notes. Any and all help is appreciated. Thanks in advance.
example code starts below:
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;
import android.view.View;
import android.content.DialogInterface;
import android.app.Dialog;
import android.app.AlertDialog;
public class DialogActivity extends Activity {
CharSequence[] items = { "Google", "Apple", "Microsoft" };
boolean[] itemsChecked = new boolean [items.length];
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onClick(View v) {
showDialog(0);
}
#Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case 0:
return new AlertDialog.Builder(this)
.setIcon(R.drawable.ic_launcher)
.setTitle("This is a dialog with some simple text...")
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton)
{
Toast.makeText(getBaseContext(),
"OK Clicked!", Toast.LENGTH_SHORT).show();
}
}
)
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton)
{
Toast.makeText(getBaseContext(),
"Cancel clicked!", Toast.LENGTH_SHORT).show();
}
}
)
.setMultiChoiceItems(items, itemsChecked,
new DialogInterface.OnMultiChoiceClickListener() {
public void onClick(DialogInterface dialog,
int which, boolean isChecked) {
Toast.makeText(getBaseContext(),
items[which] + (isChecked ? " checked!":" unchecked!"),
Toast.LENGTH_SHORT).show();
}
}
).create();
}
return null;
}
}
this refers to the current Object's reference.
Read this for more understanding.
To give an example from the link:
public class Point {
public int x = 0;
public int y = 0;
//constructor
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
Here, to differentiate from the x of the Point and x of the argument, you need to tell the compiler the difference. You achieve that using this. Meaning, when I write, this.x it means, the particular x belongs to the current Object, which in the case is Point.
Taking example from the code that you have provided:
AlertDialog.Builder(this)
AlertDialog.Builder() takes in a Context as a parameter in its constructor. But here, you don't do Context someContext = new Context(); and pass that as the parameter, because you simply need to pass your current Activity's Context. So you simply use this.
Think of this as "itself". If you pass this to a method, you're simply passing an instance of the object to the method.
ie: Student is an object, as is Classroom. If I want to add a Student to the Classroom, I might tell Student to add itself to the classroom (classrooms can't find students, can they?). So, I will say student.addToClassroom(new Classroom(), this);
The keyword this, like others have said, is just a reference to the current object. This is usually implicit, such that if you have a class as so:
class ThisExample{
int x;
public ThisExample(int x){
this.x = x;
someMethod();
this.someMethod();
}
void someMethod()
{
...
}
}
Using this.x = x helps to differentiate between the member variable owned by the class and the variable being passed into the constructor. Also, calling this.someMethod() and someMethod() does exactly the same thing because the this is implied.
In Android, sometimes you will see a method with this being passed in like someMethod(this). What happens here is that this is referring to the current Activity's Context, which is just a bunch of information explaining everything about the Activity.
Ok I'll see how I go :P
Think of a Java object (class) as an individual entity, which has certain things which define what it IS (properties) and certain things it can DO (methods)
For example, take a (very abstract) class named Machine
class Machine {
Piston piston1;
ArrayList<Gear> gears;
public void addSomeNewGears(ArrayList<Gear> gears)
{
for(int i = 0; i < gears.size(); i++)
{
this.gears.Add(gears[i]);
}
}
}
In the Method addSomeNewGears we actually have access to TWO Lists named gears:
The Machine object's current gears,
The new ones we want to add.
Because they are both called gears it can be ambiguous as to which one we want to access, however the new List will take priority as it is declared locally in the method.
To access the Machine's gears, we need to use the this keyword, which tells the compiler we are looking for the class's gears, not the method's
Hope this helps!
Instance methods (those not declared static) of a class can only be executed by reference to some instance of the class. For example:
class Foo {
public void doSomething() {
// "this" refers to the current object
. . .
}
. . .
}
// then later:
Foo aFoo = new Foo();
aFoo.doSomething(); // "this" will be equal to "aFoo" for this call
// The following is illegal:
doSomething();
// so is this:
Foo.doSomething();
Inside the method doSomething(), the variable this refers to the specific instance of Foo that was used to invoke the method (in this example, the current object referenced by aFoo).
this is none other than the reference of current object. this will be very useful to identify that the members belongs to the current class.
For example,
Class Sample{
int a;
Sample(int a){
this.a=a;
}
}
"this" will differentiate current class variable and other variable
Related
I know there are already some questions on global methods and variables in android but I'm running into problems with static methods probably due to my less experience with objectoriented programming. So here is what I want to have:
I am writing an app which counts points which the user can earn for certain things he does. Because of that I want to call the method addPoints from different activities and services. This method should also set the points textview in the main activity and some other things.
I realized it by adding a static variable
static int sPoints;
in the MainActivity, that I use as a "global" variable in each activity.
However, with the addPoints method I have some problems. If I use a non-static method, I have to create an instance of MainActivity in the other activities, which is not very nice and changing the values of that instance does not have an effect on the actual MainActivity.
If I use a static function it works fine as long as I don't want to use non-static methods like in this example:
public static void addPoints(Context context, int points){
int levelBefore, levelAfter;
levelBefore = getLevelFromPoints(sPoints);
sPoints = sPoints + points;
levelAfter = getLevelFromPoints(sPoints);
if(levelBefore!=levelAfter){
String rank = getRankFromLevel(levelAfter);
levelTextView.setText("Lvl. " + String.valueOf(levelAfter));
Toast.makeText(context, "Congrats! You reached the next level!", Toast.LENGTH_LONG).show();
}
}
Here I can't easily use levelTextView.setText and I run into this problem in many other cases. Moreover, I've read that using static methods is not good, anyway.
So would the correct way be creating an instance of MainActivity each time and then call addPoints on it which has to return the new number of points? Or is there another way (I hope so, because both above ways seem to be not very satisfying).
a. Static methods can safely be used in case your work can not be accomplished by ShardPreferences and requires the use of same code at multiple classes like in your case.
b. First create an interface that will pass the updated rank to respective activities or classes
public interface ScoreUpdater {
void updateScore (String rank);
}
c. then implement it in all activities where required to use, MainActivity in this case
public class MainActivity extends AppCompatActivity implements ScoreUpdater{
//
//other methods and codes
//
#Override
public void updateScore(String rank) {
runOnUiThread(new Runnable() {
#Override
public void run() {
levelTextView.setText("Lvl. " + String.valueOf(levelAfter));
Toast.makeText(MainActivity.this.getApplicationContext(), "Congrats! You reached the next level!", Toast.LENGTH_LONG).show();
}
});
}
}
d. then implement your static methods. not sure where you have declared few variables. so my method below is on guess work.
public static void addPoints(Context context, int points){
//not sure where you are declaring sPoints
int levelBefore, levelAfter;
levelBefore = getLevelFromPoints(sPoints);
sPoints = sPoints + points;
levelAfter = getLevelFromPoints(sPoints);
if(levelBefore!=levelAfter){
String rank = getRankFromLevel(levelAfter);
if(context instanceof ScoreUpdater){
((ScoreUpdater)context).updateScore(rank);
}
}
}
private static int getLevelFromPoints(int points){
//your operations
return points;
}
Can I break the set-listener line into smaller pieces?
Here is the code I have:
protected void onCreate(Bundle savedInstanceState) {
Preference button = (Preference)getPreferenceManager().findPreference("exitlink");
button.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference arg0) {
finish();
return true;
}
});
I would like this to look something like:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Preference button = (Preference)getPreferenceManager().findPreference("exitlink");
if(button != null) {
button.setOnPreferenceClickListener(onPreferenceClick);
}
}
public boolean onPreferenceClick(Preference arg0) {
finish();
return true;
}
You can also create a variable outside of your method:
private Preference.OnPreferenceClickListener listener = new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference arg0) {
finish();
return true;
}
};
Then you use it as a variable: setListener(listener). This would allow you to have multiple instances of the same listener class in your Activity.
Your code above nearly works already. Use your above code with this tiny change:
button.setOnPreferenceClickListener(this);
Then you just let your class implement the specific interface needed, in this case Preference.OnPreferenceClickListener.
In addition to dmon's suggestion below about using variables for this, it is also possible to write a function that returns a listener, which is very useable when you want to have similar listeners but with slight changes, like in the example below.
private Preference.OnPreferenceClickListener getListener(int listenerId) {
return new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference arg0) {
Log.i("MyTag", "Listener " + listenerId + " invoked!");
finish();
return true;
}
};
}
As others have mentioned, even though you cannot pass a method name to setOnPreferenceClickListener you can create a variable of a type that extends Preference.OnPreferenceClickListener. In your original code, that is actually exactly what you are doing: you are creating an object of an anonymous inner class.
The advantage of this approach, say over Simon André Forsberg's answer above is of scope: it keeps the listener functionality in that small block, instead of potentially all over the class.
Creating a separate variable outside the method as in dmon's answer loses one big benefit of the anonymous inner class, that they can access the variables in the containing scope: in your original code, the listener can access the variables button and savedInstanceState. This is not possible with a separate variable defined outside the function.
None of this means that you must use anonymous inner class. Oracle has an excellent tutorial titled General Information about Writing Event Listeners that you will greatly benefit from.
Not exactly. The set-listener requires an instance of listener, so you always need to create one. And I don't think it's a good manner for activity implementing listener interfaces.
The workaround is that you can use annotations with reflection, such as http://code.google.com/p/roboguice/. This may make the code cleaner, but also introduces dependencies.
In the following code, the first if statement complains that current_guy can't be a final but the second if statement complains that current_guy isn't a final. I am out of ideas.
final int current_guy=0;
if (a.equals("bf")){
current_guy=1;
}
guy1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (current_guy==1) {
// TODO Auto-generated method stub
}
}
final int current_guy = a.equals("bf") ? 1 : 0;
Jordan Denison had this in an answer that was deleted .. not sure why, because it is correct. This is then just a re-post for "completeness" of the current answers. (That being said, I would likely use the ternary operator approach here.)
Note that a final variable's assignment can be delayed as long as it is assigned exactly once on all code-paths before use.
final int current_guy; // no assignment here
if (a.equals("bf"))
{
current_guy=1;
}
else
{
current_guy=0;
}
You can assign current_guy to another final variable
final int finalCurrentGuy = current_guy;
guy1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (finalCurrentGuy==1) {
....
}
}
This makes copy of the variable current_guy at that point in time and passes that into the inner class
This SO post explains why it must be final inside the inner class
What i would do is :
int current_guy=0;
// Set the value that you want based on a condition
if (a.equals("bf"))
{
current_guy=1;
}
final int valueToTest = current_guy;
guy1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (valueToTest ==1) {
// your code
}
}
The reason, this is imposed is because the onClick() method may execute some time later in response to an event and may be in a separate thread. Then you wont want the value of the variable to be changed either inside that handler or somewhere outside while the handler is being executed. You could say it is to prevent a dirty read of the value.
The reason the first one is complaining is because you can't set a final variable. The reason it's complaining that it's not final is that you're creating what is called an anonymous inner class. So your OnClickListener is a completely separate class and can't access variables from your main class at runtime. This is why it has to be Final. Then when the compiler is building your app it knows what that value is and can substitute it in there. If you want to have this variable be, well variable, then you have to pass the value into the OnClickListener so that it can get the updates as the variable changes.
Make another class that implements your OnClickListener and pass it the current_guy as a parameter. This will stop it from complaining about the variable not being final. You cannot reference non-final variables when declaring inner classes and methods like that.
Once you check/adjust, assign current_guy to a final variable:
int current_guy=0;
if (a.equals("bf"))
{
current_guy=1;
}
final int final_current_guy = current_guy;
guy1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
if (final_current_guy==1) {
}
}
Or use one-line assignment:
final int current_guy = (a.equals("bf") ? 1 : 0);
I've read hundreds of explanations on "this" in java and I'm really having trouble grasping it. I'm learning android and java side-by-side, I know it's harder that way but I'm enjoying it. The one thing I'm getting killed on is "this"... I'm pasting code from a tutorial below that utilizes "this" one time. I was going to just put a piece of the code but want to be as helpful as possible.
I'm looking for a good explanation of "this" that I can add to my notes. Any and all help is appreciated. Thanks in advance.
example code starts below:
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;
import android.view.View;
import android.content.DialogInterface;
import android.app.Dialog;
import android.app.AlertDialog;
public class DialogActivity extends Activity {
CharSequence[] items = { "Google", "Apple", "Microsoft" };
boolean[] itemsChecked = new boolean [items.length];
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onClick(View v) {
showDialog(0);
}
#Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case 0:
return new AlertDialog.Builder(this)
.setIcon(R.drawable.ic_launcher)
.setTitle("This is a dialog with some simple text...")
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton)
{
Toast.makeText(getBaseContext(),
"OK Clicked!", Toast.LENGTH_SHORT).show();
}
}
)
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton)
{
Toast.makeText(getBaseContext(),
"Cancel clicked!", Toast.LENGTH_SHORT).show();
}
}
)
.setMultiChoiceItems(items, itemsChecked,
new DialogInterface.OnMultiChoiceClickListener() {
public void onClick(DialogInterface dialog,
int which, boolean isChecked) {
Toast.makeText(getBaseContext(),
items[which] + (isChecked ? " checked!":" unchecked!"),
Toast.LENGTH_SHORT).show();
}
}
).create();
}
return null;
}
}
this refers to the current Object's reference.
Read this for more understanding.
To give an example from the link:
public class Point {
public int x = 0;
public int y = 0;
//constructor
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
Here, to differentiate from the x of the Point and x of the argument, you need to tell the compiler the difference. You achieve that using this. Meaning, when I write, this.x it means, the particular x belongs to the current Object, which in the case is Point.
Taking example from the code that you have provided:
AlertDialog.Builder(this)
AlertDialog.Builder() takes in a Context as a parameter in its constructor. But here, you don't do Context someContext = new Context(); and pass that as the parameter, because you simply need to pass your current Activity's Context. So you simply use this.
Think of this as "itself". If you pass this to a method, you're simply passing an instance of the object to the method.
ie: Student is an object, as is Classroom. If I want to add a Student to the Classroom, I might tell Student to add itself to the classroom (classrooms can't find students, can they?). So, I will say student.addToClassroom(new Classroom(), this);
The keyword this, like others have said, is just a reference to the current object. This is usually implicit, such that if you have a class as so:
class ThisExample{
int x;
public ThisExample(int x){
this.x = x;
someMethod();
this.someMethod();
}
void someMethod()
{
...
}
}
Using this.x = x helps to differentiate between the member variable owned by the class and the variable being passed into the constructor. Also, calling this.someMethod() and someMethod() does exactly the same thing because the this is implied.
In Android, sometimes you will see a method with this being passed in like someMethod(this). What happens here is that this is referring to the current Activity's Context, which is just a bunch of information explaining everything about the Activity.
Ok I'll see how I go :P
Think of a Java object (class) as an individual entity, which has certain things which define what it IS (properties) and certain things it can DO (methods)
For example, take a (very abstract) class named Machine
class Machine {
Piston piston1;
ArrayList<Gear> gears;
public void addSomeNewGears(ArrayList<Gear> gears)
{
for(int i = 0; i < gears.size(); i++)
{
this.gears.Add(gears[i]);
}
}
}
In the Method addSomeNewGears we actually have access to TWO Lists named gears:
The Machine object's current gears,
The new ones we want to add.
Because they are both called gears it can be ambiguous as to which one we want to access, however the new List will take priority as it is declared locally in the method.
To access the Machine's gears, we need to use the this keyword, which tells the compiler we are looking for the class's gears, not the method's
Hope this helps!
Instance methods (those not declared static) of a class can only be executed by reference to some instance of the class. For example:
class Foo {
public void doSomething() {
// "this" refers to the current object
. . .
}
. . .
}
// then later:
Foo aFoo = new Foo();
aFoo.doSomething(); // "this" will be equal to "aFoo" for this call
// The following is illegal:
doSomething();
// so is this:
Foo.doSomething();
Inside the method doSomething(), the variable this refers to the specific instance of Foo that was used to invoke the method (in this example, the current object referenced by aFoo).
this is none other than the reference of current object. this will be very useful to identify that the members belongs to the current class.
For example,
Class Sample{
int a;
Sample(int a){
this.a=a;
}
}
"this" will differentiate current class variable and other variable
My code is here:
public static boolean showConfirmationDialog(Context context, String title, String dialogContent) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setTitle(title);
builder.setMessage(dialogContent);
builder.setPositiveButton("Confirm", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// what to do ?
}
});
right now, I want to return true after I clicked the "confirm" button. so how do I return "true" from a inner class - OnClickListener for the method.
Need some help, thanks.
You can't return things from an inner class in this instance. In this case it doesn't make much sense. Is the program supposed to wait inside your onClick function until it returns something? That's not really how listeners work. What you need to do is take what ever code you plan on executing if "true" was returned, and put it inside your inner class.
OnClickListeners dont return values. Without knowing what exactly you need to do when the click listener fires I cant give you any specifics but
private boolean classBoolean = false;
public static boolean showConfirmationDialog(Context context, String title, String dialogContent) {
//local variables must be declared final to access in an inner anonymous class
final boolean localBoolean = false;
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setTitle(title);
builder.setMessage(dialogContent);
builder.setPositiveButton("Confirm", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// what to do ?
//you can't change a local var since to access it it needs to be final
//localBoolean = true; can't do this
//so you can change a class var
classBoolean = true;
//or you can also call some method to do something
someMethod();
}
});
You either need to set your return on an instance variable (not within a method) - but this may lead to concurrency issues, or use a "container" object. Pass-in, or use a "final" method variable, on which you can set the return value you want to return. However, I use the term "return" loosely, as at least in your example, this code won't immediately execute, so you really need to do the processing you're interested within the inner class instead.
The onClick paradigm doesn't let you return values, it lets you respond to "events" later, so you'll have to rethink your code paradigm a bit.
For followers, in the event that the inner class is "blocking" (i.e. not this case), you can return values using AtomicReference, ex:
AtomicReference<String> returnValue = new AtomicReference<>();
someMethod( new Runnable() { returnValue.set("my inner class value");} );
return returnValue.get();
though better would be (if possible) have someMethod modified so it can return your value out itself (and use something besides Runnable in this instance). GL!
You can do follow simple step:
create a POJO class object inside method.
call setter method by setting return value and use it.
Example:
public void process(){
Contact contact=new Contact();
String selectCount="select * from firmId where id=? for update";
PreparedStatementCreatorFactory pscf = new
PreparedStatementCreatorFactory(selectCount,new int[] {Types.INTEGER});
pscf.setUpdatableResults(true);
pscf.setResultSetType(ResultSet.CONCUR_UPDATABLE);
RowCallbackHandler rch = new RowCallbackHandler() {
#Override
public void processRow(ResultSet resultSet) throws SQLException {
// Here You can set your value
contact.setContactId(incrementCount);
resultSet.updateLong("firmCount",incrementCount);
resultSet.updateRow();
return;
}
};
return contact.getId();
}