access variables of outer class in Java - java

in Java android application how can i access variables of outer class from the inner anonymous class ?
Example:
ProgressDialog dialog = new ProgressDialog(this);
.....
send.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v) {
//here i'd like to do something with **dialog** variable
.......
}
});

If the dialog variable is a field of the outer class, you can use this prefixed with the outer class name (a qualified this):
send.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v) {
ProgressDialog dlg = OuterClass.this.dialog;
.......
}
});
Alternatively, if the dialiog variable is a local variable it needs to be marked as final:
final ProgressDialog dialog = new ProgressDialog(this);
.....
send.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v) {
// The dialog variable is in scope here ...
dialog.someMethod();
}
});

Make the outer local variable (dialog) final so you can refer to it from the inner class.

If it's a local variable (like the signature suggests), it needs to be final for the inner class to be able to access it. If it's a member variable, the visibility modifier needs to be default (no modifier) or higher (protected or public). With private -modifier, it still works, but you might get a warning (depending on your compiler-settings):
Read access to enclosing field SomeClass.someField is emulated by a
synthetic accessor method

Related

Calling methods without reference variable [duplicate]

This question already has answers here:
Calling a method inside another method in same class
(5 answers)
Why am I able to access a method without object in java [duplicate]
(2 answers)
Closed 3 years ago.
Could someone explain to me one thing about call methods, viz. When I was learning at Neatbeans, calling a method was always done using a reference variable, where I had to create a real object before, for example:
public class Question {
public static void main(String[] args) {
Test test = new Test();
test.method();
}
}
class Test {
void method() {
System.out.println("Test");
}
}
In this case, I had to create an object, assign its reference to the test variable, and then call the method.
However, in Android Studio, to call a method, I do not have to create a reference variable or an object, I only directly call the method ... for example:
public class SecondActivity extends AppCompatActivity {
EditText editText;
Button button2;
String name;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
editText = findViewById(R.id.editText);
button2 = findViewById(R.id.button);
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
prepareResult();
}
});
}
public void prepareResult() {
Intent i = new Intent();
name = editText.getText().toString();
i.putExtra("name", name);
setResult(RESULT_OK, i);
finish();
}
}
In this case, I do not create an object, and I do not assign its reference to 'X' variables, I immediately call the prepareResult method. Why is this happening?
In Java, when you call another method in the same class, you do not need to reference by it's class object.
Where when you call the method from same class, you can access method directly.
It's all a matter of scope. In your first example, you were trying to use the method method() from the class Test from within another class, Question.
In the second example, you can call prepareResult() directly because the method from where that call is issued, onCreate(), belongs to the same class SecondActivity.
This is possible because, essentially, they are in the same scope. All methods and variables in a particular class are visible amongst each other. Visibility outside of the class depends on the access modifiers, public, private, protected or the default package-private
You can find more details in this Oracle Java tutorial:
https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
In Java, whenever you call a function which is outside the activity, you are calling. You have to use a reference variable to call the other class constructor to build an object. It can be done in your case.
Test test = new Test();
test.method();
OR
new Test().method();
Whenever you call a function which is inside the same class(within where you defined the function), you can call directly using its name directly because you do not have to call the constructor of the class which is already created. Like you have done in your other code.
You can see the class do not change here.
public class SecondActivity extends AppCompatActivity {
EditText editText;
Button button2;
String name;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
editText = findViewById(R.id.editText);
button2 = findViewById(R.id.button);
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
prepareResult();
}
});
}
public void prepareResult() {
Intent i = new Intent();
name = editText.getText().toString();
i.putExtra("name", name);
setResult(RESULT_OK, i);
finish();
}
}

Using object from other class

I have mainActivity class and class1. In class1 i have something like this
public void ownedAdd(int a)
{
owned = owned +a;
}
Simple. But when i want to call this method in MainActivity
Class1 obj1 = new Class1();
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
obj1.ownedAdd(10);
}
});
And in this place i have few question. Android Studio saying that obj1 need to be declared as final. I dont like that. What i want to do is using class1 object in main method. Is that possible? I want to make few objects of class1 each with some variable as price, owned etc and i have no idea how. For any help, thanks a lot ;)
What's wrong is that in JAVA, you cannot access a variable from a method to an anonymous class inside that method unless the variable is declared final inside the method, or the variable is itself global to the parent Class.
To solve your problem, set the obj1 variable to be global. Something like:
public class MainActivity extends AppCompatActivity {
//Declare the obj1 object here
Class1 obj1;
#Override
public void onCreate(Bundle savedInstanceState) {
//inflate layout and do other stuff
//from where you posted
obj1 = new Class1();
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
obj1.ownedAdd(10);
}
});
}
}
From the code given, you don't need the reference to the Class1 instance other than in the click listener, so you can simply make it a member variable of the View.OnClickListener:
button1.setOnClickListener(new View.OnClickListener() {
final Class1 obj1 = new Class1();
#Override
public void onClick(View v) {
obj1.ownedAdd(10);
}
});
(Although it is still worth making it final).
However, it's not super-useful like that, since only the click listener can access the instance - you can't display the value in another control, for example. It is simplest just to make your current local variable final.

Unit testing a method declared inside a method

I have an Android application, where inside an onCreate() method of an Activity a button is defined to have an onClick method. In code:
public void onCreate(Bundle savedInstanceState) {
/.../
buttonSave = (Button) findViewById(R.id.store_button_save);
buttonSave.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
saveEditor(v);
}
});
/.../
}
My question is, how can I call this nested method onCLick() from an Android unit test? myActivity.onClick(myButton) does not work, since onClick() is not a method defined in the activity itself.
Btw, I should not be changing any original source code for my tests.
You can test this by not creating such an anoynmous class.
Instead create a normal inner class, and assign a new instance to to the listener:
public static class MyClickListener implements OnClickListener {
Editor editor;
public MyClickListener(Editor e) {
this editor= e;
}
public void onClick(View v) {
editor.saveEditor(v);
}
}
buttonSave.setOnClickListener(new MyClickListener());
In JuniTest
public void testOnClickListener() {
Editor e = new Editor();
MyClickListener l = new MyClickListener(e);
l.onClick();
// however you check for correct result
assertTrue(checkSaveEditor(e));
}
But why not just write unitest for method saveEditor() only?
This is sufficient, you can rely that onClick() works.
The onClick method is defined inside an anonymous class, so you cannot directly invoke it. Instead you need trigger the click event from the outer class. Don't know much about Android development but the following post explains how to test such as scenario using ActivityManager to simulate a button click with #UIthreadTest annotation. How to call Button.performClick in Android JUnit test case?

Android Final vs Private textviews

simple maybe stupid question. I have a login activity which launches another activity, and here's the code:
public class LoginActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
ActionBar actionBar = getActionBar();
actionBar.hide();
Button btnLogin = (Button) findViewById(R.id.btnLogin);
final TextView tvUsername = (TextView) findViewById(R.id.tvUsername);
final TextView tvPassword = (TextView) findViewById(R.id.tvPassword);
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (tvUsername.getText().toString().length()<1) {
Toast msg = Toast.makeText(LoginActivity.this, "Enter a Username", Toast.LENGTH_LONG);
msg.setGravity(Gravity.TOP|Gravity.LEFT, 0, 70);
msg.show();
tvUsername.requestFocus();
} else if (tvPassword.getText().toString().length()<1) {
Toast msg = Toast.makeText(LoginActivity.this, "Enter a Password", Toast.LENGTH_LONG);
msg.setGravity(Gravity.TOP|Gravity.LEFT, 0, 200);
msg.show();
tvPassword.requestFocus();
} else {
startActivity(new Intent(LoginActivity.this,CrewScheduleActivity.class));
finish();
}
}
});
}
}
My question is about the textviews. Eclipse basically said i had to make them final in order to use them in the onClick event of the button. NP so i did that and it worked.
The question is What is the difference between putting these above the #Override as private vs inside the OnCreate as final?
This has to do with closure in Java. Basically, when you use an anonymous class, the values (not objects themselves) used within it are copied to that class for usage. Therefore, it does not make sense to return or modify those variables within the class, hence they must be final.
However, if the variable is instead part of the class containing the anonymous class, that's different. Basically, your inner class has a reference to the LoginActivity object (as LoginActivity.this), and can use and modify its members and methods.
When you put them "above the #Override", you are making them member variables of the LoginActivity class. Therefore, they can be accessed by the anonymous class.
Succinctly, the difference is that: final variables are local to the method, and copied to the anonymous class; member variables are local to the containing class and are modified by the anonymous class.
If you want to reuse the data from the anonymous class later, use a member variable. If you only need it within onCreate() and the anonymous class, then a final variable will suffice.
When you declare the TextView field (or any field for that matter) as public, it can be accessed directly by any other class, which I don't believe is your intention; there's no reason to make the TextView variable public.
If it is set as private, there is a guarantee that its value won't be overridden in another class, which is what the final keyword was designed to do in the first place. So, simply set it as private, and you won't have to worry about Eclipse correcting you.
So, in summary: making the field private/final ensures that the value cannot be overridden from another class, which is a good design.
Hope this rambling helps. I'll be glad to clarify it better if it doesn't.

final variable in android programming

This is the code I am using in android programming
EditText pass1,pass2;
Button register=(Button) findViewById(R.id.register);
register.setOnCllickListener(new OnClickListener(){
public void onClick(View v)
{
passq=(EditText) findViewById(R.id.password_fill);
}
});
But i always get an error:
Cannot refer to non-final variable inside an inner class defined in different method.
Even after I declare the pass1 as final, I get the following error:
The final local variable pass1 cannot be assigned since it is defined in an enclosing type.
But why is this error coming and how can I remove it? I have been encountering it many times.
You have to declare edit text globally. The reason for this is in your activity class you have a method called "onCreate" where you declared the Edit text "pass1" and you trying to define by another pre defined method "setOnClickListener". This is not possible. So you have to declare it globally or as final.
When we use any variable in anynomus class then we have to use final variable.
So use
final EditText passq;
then use it in onClick method.
//declare your editext in global
or
final EditText pass1;
Button register=(Button) findViewById(R.id.register);
register.setOnCllickListener(new OnClickListener(){
public void onClick(View v)
{
pass1=(EditText) findViewById(R.id.password_fill);
or
EditText pass2=(EditText) findViewById(R.id.password_fill);
}
});

Categories

Resources