Need understanding of implementation of onClick callback in android view - java

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");

Related

Does accessing a local final variable from a listener require check for null?

When we have the following:
final TextView view = (TextView) layout.findViewById(R.id.some_view);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
view.setText(“blah”);
}
}
//etc
view unless is final can not be accessed by the onClick method.
If this snippet is inside a method then view is allocated on the stack holding a reference to the heap. So in the end of the method call view is lost. Since the onClick is in the same scope the view is still visible. My question is: The onClick can be called at any time. Marking it as final does it ensure that view will not be null when the listener runs? Or is a check for null required? And why is that the case?
It's possible that findViewById() will return null, if your layout doesn't contain R.id.some_view. So you probably need to check that for null.
Where to check for null depends on your app logic. Anonymous OnClickListener object will create inner "view" copy, so even if outer "view" goes out of scope, the listener will still hold reference to the "view" variable.
Where to check for null is your choice, but if you findViewById() return null then you probably should not create click a listener.
I tested your final code
But This Textview is not null.
Maybe layout don't have textview
You have to check textview your layout.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R
.layout.activity_main);
Button button =(Button)findViewById(R.id.button);
final TextView view = (TextView)findViewById(R.id.some_view);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
view.setText("Hello world");
}
});
}

Is there any benefit to using View in Java code when using findViewById from an XML ImageView?

I'm writing code where in XML I'm using ImageViews and occasionally TextViews to act as buttons. I don't need to do anything with them other than setOnClickListeners in my Java code, so I'm wondering if there's any benefit to leaving them as View objects in Java as opposed to casting them to ImageView or TextView objects.
private ImageView mPlayButton;
mPlayButton = (ImageView) findViewById(R.id.playButton);
mPlayButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "Audio Play", Toast.LENGTH_SHORT).show();
}
});
as opposed to
private View mCurrentSongButton;
mCurrentSongButton = findViewById(R.id.currentSongIcon);
mCurrentSongButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SongInfo.class);
startActivity(intent);
}
});
I appreciate the assistance.
There is no need to cast a View to an ImageView just to set OnClickListener. Casting an object into a different class doesn't change the object's class i.e an ImageView object will remain an ImageView when cast as a View or even as an Object. And thus same methods would be called regardless the reference wrapper of the object itself.
Purpose of casting any object to a child class should only be to unlock the otherwise unavailable methods. So if you need to call any methods which are dedicated for an ImageView, you will need to cast it to an ImageView before hand (but only so you'd be able to call or use the method).
In short if there is no need to call a child specific method then don't cast the object, it is simply an overhead for the compiler.
If you only need to set click listener, then view type is enough but if you need specialized operations like setText(), setEnabled() etc, then you need to cast them

Change view on dialog when pressing a button in the dialog

Say i have two views in a layout - a Button and a TextView.
Is it possible to change the TextView text inside the button on click listener.
something like this:
button.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
textview.settext("changedText");
}
});
The obvious error is that textview is not recognized by the OnClickListener method, and making it final will make it impossible for changing.
you are making final textView so you can not assign this reference to another object
but you can do with any operation on that object.
you can change any property of textview
thanx.
Making the textview final will still allow you to set the text.
Only the assignment can be done once.
The final attribute is just restricting his initialization once. You can access is method after. (If that's what you need)
You can also make a field in your class and it will be available in the listener. Something like:
private TextView textview;
provide some ID to textview in the layout,
create new variable TextView tv=new TextView(); in the same activity where dialogue is created
tv=(TextView)findviewbyid(R.id.ID_OF_TEXT_VIEW);
Then you should be able to use tv.settext("change text.")
declare textview at class level as below
Class CLASSNAME{
public TextView textview;
//your onclickListener code inside method or wherever u have written
}

Why is this Java code working? compiler doesn't complain about closure

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.

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