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.
Related
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();
}
}
final EditText textview = new EditText(this);
textview.setText("Nothing to display as DB Read failed!!");
textview.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
textview.setText("Stop clicking me");
}
});
Ideally build should fail since textview object is defined local to my onCreate() method and the object is not passed to onClick() method.
I am relatively new to Java. Could anyone explain how the object is accessible?
1 more thing.. Why do I need to pass View v argument and how is it useful to this method?
The reference to the objects of the outer class, which are accessed from inside the anonymous class, are copied via an auto-generated constructor.
But you can only access variables which are declared final , so they can't possibly be modified by the rest of the outer class once copied.
As for the View v , like SimonR said, it's a reference to the textview itself.
But you will have to cast it to TextView before calling setText(...)
View v is the Element, on which the OnClickListener has been attached to. You can simply change textview within the method to v.
v.setText("Stop clicking me");
My DialogFragment contains an -initially invisible- OK button and a ListView of clickable items. When any of the ListView items is clicked I set button's visibility to VISIBLE.
This is done through an anonymous OnItemClickListener. The code below works but I don't get why. Since Java does not support closures, I would expect the compiler to complain about button not being final.
Isn't this a typical case of a closure? How come the code below doesn't produce a compiler error?
Thank you
public class AlternativeRoomsDialog extends DialogFragment {
private Button okButton;
static AlternativeRoomsDialog newInstance(String name) {
AlternativeRoomsDialog f = new AlternativeRoomsDialog();
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_alternative_rooms, container);
getDialog().setTitle("Change Room");
ListView lv = (ListView) view.findViewById(R.id.alternative_rooms_list);
final adapter = /*some initialization*/;
lv.setAdapter(adapter);
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View linlay, int position, long id) {
okButton.setVisibility(View.VISIBLE);
ListView lv = (ListView) linlay.getParent();
int total = lv.getChildCount();
for (int i=0; i< total; i++){
lv.getChildAt(i).setBackgroundColor(Color.BLUE);
}
linlay.setBackgroundColor(Color.GREEN);
}
});
// setup OK button
okButton = (Button) view.findViewById(R.id.btn_ok);
okButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(AlternativeRoomsDialog.this.getActivity(), "ok button clicked", Toast.LENGTH_SHORT).show();
}
});
return view;
}
}
The requirement of variables being declared final only applies to local variables, because they are the ones that go out of scope when the method returns. Your button is referenced by a member variable, and there's no need for it to be final: the member won't go anywhere as long as the object exists.
You don't need to make the instance variable final, that is only the case with local variables. The local variables needs to be final, they are copied to the anonymous class you use inside the method, as instance variables of that class. This is done because the anonymous inner class instance might stay in heap memory, after the method returns. So, it may require to access the variable even after the method stack frame is de-allocated.
Now, since there are 2 copies of the local variables, they can go out of sync, if the local variable is changed outside the anonymous inner class. That would really go weird, that is why it is required to make the local variable final.
As with instance variables, they are instead shared between enclosing class instance, and anonymous inner class instance. So, you don't need to make them final.
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
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);
}
});