I have a linearlayout, which contains my TextView I want access.
In this linearlayout there is a listview, where every item is a linearlayout and contains also custom views.
Deep in there is a button with an onclickListener. After performing onClick(), I want to call a method which sets the text of my textview.
At the moment I am doing it like this:
(View)this.getParent().getParent().getParent().getParent().getParent().getParent().getParent().findViewById(R......)
It works, but it looks bad. Is there any possibility to do it a better way?
Image
Yes, its ugly, don't do that.
In your onClick(View v) get hold of TextView by asking Activity holding the layout:
#Override
public void onClick(View v) {
TextView tv = (TextView) YourActivity.this
.findViewById(R.id.your_text_view_id);
tv.setText("blabla");
}
if you do it from fragment instead of activity use :
YourFragment.this.getView().findViewById(R.id.your_text_view_id)
Or simply create a member TextView mTv, initialize it in your #OnCreate and use it everywhere as suggested in comments to your question
It looks bad, because it is generally a bad idea for a view to know something about outside of it self. So it is probably okay to know about your children but not back.
You'd better keep your views as simple as views, without any other logic. Do your logic in Activities/Fragments
See Circular dependency
Related
I realize that a similarly-worded question has been asked before, but this is different. I am pretty new at developing android apps and I have three questions regarding the difference(s) between the android:onclick="" XML attribute and the setOnClickListener method.
What are the differences between the two? Is the difference between the two implementations found at compile time or run time or both?
What use cases are favorable to which implementation?
What difference(s) does the use of fragments in Android make in implementation choice?
Difference Between OnClickListener vs OnClick:
OnClickListener is the interface you need to implement and can be set
to a view in java code.
OnClickListener is what waits for someone
to actually click, onclick determines what happens when someone
clicks.
Lately android added a xml attribute to views called android:onclick,
that can be used to handle clicks directly in the view's activity
without need to implement any interface.
You could easily swap one listener implementation with another if you need to.
An OnClickListener enable you to separate the action/behavior of the click event from the View that triggers the event. While for simple cases this is not such a big deal, for complex event handling, this could mean better readability and maintainability of the code
Since OnClickListener is an interface, the class that implements it has flexibilities in determining the instance variables and methods that it needs in order to handle the event. Again, this is not a big deal in simple cases, but for complex cases, we don't want to necessary mix up the variables/methods that related to event handling with the code of the View that triggers the event.
The onClick with function binding in XML Layout is a binding between onClick and the function that it will call. The function have to have one argument (the View) in order for onClick to function.
Both function the same way, just that one gets set through java code and the other through xml code.
setOnClickListener Code Implementation:
Button btn = (Button) findViewById(R.id.mybutton);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
myFancyMethod(v);
}
});
// some more code
public void myFancyMethod(View v) {
// does something very interesting
}
XML Implementation:
<?xml version="1.0" encoding="utf-8"?>
<!-- layout elements -->
<Button android:id="#+id/mybutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me!"
android:onClick="myFancyMethod" />
<!-- even more layout elements -->
Performance:
Both are the same in performance. Xml is pre-parsed into binary code while compiling. so there is no over-head in Xml.
Limitation:
android:onClick is for API level 4 onwards, so if you're targeting < 1.6, then you can't use it.
I'm shocked nobody talked about this but be careful, although android:onClick XML seems to be a convenient way to handle click, the setOnClickListener implementation do something additional than adding the onClickListener. Indeed, it put the view property clickable to true.
While it's might not be a problem on most Android implementations, according to the phone constructor, button is always default to clickable = true but other constructors on some phone model might have a default clickable = false on non Button views.
So setting the XML is not enough, you have to think all the time to add android:clickable="true" on non button, and if you have a device where the default is clickable = true and you forget even once to put this XML attribute, you won't notice the problem at runtime but will get the feedback on the market when it will be in the hands of your customers !
In addition, we can never be sure about how proguard will obfuscate and rename XML attributes and class method, so not 100% safe that they will never have a bug one day.
So if you never want to have trouble and never think about it, it's better to use setOnClickListener or libraries like ButterKnife with annotation #OnClick(R.id.button)
Simply:
If you have android:onClick = "someMethod" in xml, it looks for the public void someMethod in your Activity class. OnClickListener is called right from your Activity and it is linked to some particular View. For example someButton.setOnClickListener and in the code below is said what has to be done when someButton is pressed.
Hope it helps :)
As said before: they both are a way to add logic in response to an event, in this case a 'click' event.
I would go for a separation between logic and presentation, just like we do in the HTML/JavaScript world: Leave the XML for presentation and add event listeners by means of code.
There are a couple of reasons why you might want to programmatically set an OnClickListener. The first is if you ever want to change the behaviour of your button while your app is running. You can point your button at another method entirely, or just disable the button by setting an OnClickListener that doesn't do anything.
When you define a listener using the onClick attribute, the view looks for a method with that name only in its host activity. Programmatically setting an OnClickListener allows you to control a button's behaviour from somewhere other than its host activity. This will become very relevant when we use Fragments, which are basically mini activities, allowing you to build reusable collections of views with their own lifecycle, which can then be assembled into activities. Fragments always need to use OnClickListeners to control their buttons, since they're not Activities, and won't be searched for listeners defined in onClick.
If you have several buttons using only one method, I suggest doing it in java. But if you have a button with one specific method, onClick in XML would be better.
It's more convenient to always use android:onClick attribute unless you have a good reason not to, for example, if you instantiate the Button at runtime or you need to declare the click behavior in a Fragment subclass.
I think main difference between them is:
OnClick: When you click on the button with your finger.
OnClickListner: It is may be a wider choice that be implemented in various codes.
For example when you type url "ymail.com", yahoo finds your username and your password from your browser and enable click state button to open your mail. This action should be implemented only in onClickListener.
This is my idea!
In my application's main layout I have a button of Search task. Now when user clicks that button I want to change the layout xml file to search_layout.xml.
I don't want to create a new activity for Search task and want to use my activity_main.java class for its coding. So how do I inflate search_layout from existing activity_main.xml .
My activity_main layout is Coordinating layout with Collapsing toolbar and Recycler view.
In my search_layout.xml I have a Simple relative layout.
So how to deal with this ? I searched for this but everywhere I get how to inflate view adding to an existing view. But in my case I want to totally change view.
Thanks
You can simply call setContentView(R.layout.your_search_layout) in the click listener of your button.
Example -
yourButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setContentView(R.layout.your_search_layout);
}
});
However, it is always good practice to make your code modular, hence you should consider using Fragments to achieve this.
You can have a look at this question, but, this is not a good practice to follow and you should consider using Fragment or any other mechanism. By doing this you are cluttering your Activity's logic with search logic.
There are two ways to do it: one is make frame layout the parent tag for your layout and then create two layouts: one that you have already created and and one for search layout framed over it and make visibility for search layout GONE and when you click search make its visibility visible.
The second method is to create the new XML layout file for search layout and inflate it like this:
View v = getLayoutInflater().inflate(R.layout.YOUR_LAYOUT_ID, null);
and elements of this layout will go like this:
Button button=(Button)v.findviewbyid(R.id.your_button_id);
Changing visibility of view will help in your case where you totally want to change the views
I think in your case, you should fragments to handle this situation.
Read this for more details on how to replace Fragments using FragmentManager.
Here's a nice example on how to change fragments in android :
I've got a custom dialog layout that has two EditText fields and I've initially set the visibility to GONE for both (in the layout XML). In the dialog onCreate I want to do a findViewByTag to locate one of the two EditText fields so I can switch visibility to VISIBLE. Everything works find in the dialog if I switch visibility in the XML but I don't know how to get a reference to the dialog's main View from within the dialog so I can call findViewByTag.
I am inflating the layout in the dialog class's onCreate because that's how the example I found did it. I'm willing to change that if necessary to get the reference in the caller and set visibility before showing the dialog if that's the best way to do it.
Still pretty new to Android so any tips on how best to handle custom dialogs is appreciated.
I'm going to assume this example from outside of a view class.
Dialog amazingDialog = new Dialog(context);
amazingDialog.setContentView(R.layout.amazingdialogcontentview)
MyAmazingView view = (MyAmazingView)amazingDialog.findViewById(R.id.amazingview);
TextView tv = (TextView)amazingDialog.findViewById(R.id.textview);
I'm not sure precisely what your use case is, so there may be a better way to do this if you have access to some member variables you could initialize in onCreate, but if you don't:
You could try
View parent = myDialog.findViewById(R.id.parentId)
to get a known parent view of those EditTexts, and then call
parent.findViewWithTag(myTag)
to find your EditText.
Looking at the way you've phrased your question, and the fact you said you're new at Android, are you familiar with the difference between IDs and Tags?
An ID is a resource number assigned to an item (e.g., a View) by Android when you tell it to give something a name. You'd declare, in your XML:
<TextView android:id="#+id/myTextView"/> <!--with other parameters as necessary-->
And then you'd use
TextView tv = (TextView)findViewById(R.id.myTextView);
to find that TextView.
A Tag is an object that you can attach to a View (which I am pretty sure you can't do by XML), either for finding it later or for persisting some interesting information about it to use whenever you might next look it up (like a data object associated with its contents). So, you might say:
tv.setTag(myInterestingData);
so that you could later look up myInterestingData just by having a reference to tv.
After much reading and trial and error, I've concluded that the only way to do this is to use multiple EditText in the XML, all with visibility="gone". Then, in the Java code, have an if or switch to lookup and show the control either by tag or by ID. I was just trying to force too much abstraction into the Dialog class. With the multiple EditText I can use the class for multiple dialogs instead of having one class for each dialog.
lets assume i have a LinearLayout , horizontal that contains a TextView and afterward a Spinner or another clicable TextView or an EditText.
I want that a click on any part of the line (if the layout has padding then the layout area as well!) will deleage the onTouchEvent to the Right part of the layout (EditText, TextView or Spinner) as if they were clicked themselves.
Doing it myself will require me either create my own versions of those widgets (too much work for little effect :-( ) or putting listeners on many items for the touch events and delegate them. I'm pretty sure Android has some methods or properties to do that, just didn't see any so far.
Can anyone help ?
I had to do something similar to this a while back, and ended up writing my own delegate and assigning the onclicklisteners for all of the components in my layout to that delegate. It's cumbersome, but not too painful to implement, and it turned out well.
Point being, I didn't see anything in the API to handle that sort of thing. The only other thing I might offer is that it is certainly possible to assign an onclicklistener to a component and simply send the event to another component's onclicklistener like so:
thislinearlayout.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
getOtherComponent().performClick();
}
});
You can do the same thing with touch listeners.
I have an android question:
I've successfully created a countdown kitchen timer activity, however my goal is to have an activity that has 3 timers on it that all work independently. I created a separate layout just for the timer itself and moved the timer code into a class and I've used layoutinflater to create the views and then added them into the linear layout for the activity. I get the layouts fine, however there's no functionality. There doesn't seem to be anything that ties the class code to the activity.
How should I approach this? Can anyone point me to some working example code?
thanks in advance!
Assuming you have inflated a view from an XML layout you could call findViewById(Int) on
the inflated view to get a hold of any view in that layout. Then you could do the wireing manually, for instance adding a onClick listener to some button:
inflatedView.findViewById(ID_OF_SOME_BUTTON_IN_THE_INFLATED_VIEW).setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
// DO SOMETHING WHEN BUTTON IS CLICKED
}
});
This was simply a case of not knowing enough. What I did in the end was to extend relativelayout in my class and fix my constructors to inflate the view in the class with the context of the activity. Then the view was added into the correct layout in the activity.
Thanks for all the good suggestions