i would like to ask a lot of questions about how this whole id system works in android. I looked up the View documentation, but the description was too shallow for my taste.
Is there a pattern, how the IDE (Eclipse/Netbeans) generates the ids
when i use android:id="#+id/..."? Or is it completely random?
If i set ids programmatically, then will it be found by the Context
classes findViewById() function?
If the answer for the previous question is yes, then if i want to
create a large amount of Views, but i want them to have distinct ids
for later identification, then wich one is better to use? (To answer
this question, it would be really useful to know the answer for the
first two)
For example generating random ids in the largest possible range:
Random random = new Random();
for(int i=0; i<100; i++)
{
View view = new View(someContext);
view.setId(random.nextInt(Integer.MAX_VALUE));
}
Or setting the ids in some sort of order, for example:
final int addToId = 5670;
for(int i=0; i<100; i++)
{
View view = new View(someContext);
view.setId(i+addToId);
}
Also i would like to know, what happens, when you use a
LayoutInflater for example to populate a ListView using a
pre-defined xml layout for every item in the list. Then you get your
sub-views in the getView() function by the findViewById(). So i
assume, that all the identical Views across your listitems have the
same id. If so, then is it a good practice to use the tag
attribute to distinguish the items in an inflated layout?
Any clear explanation for these question would be highly appreciated!
#+id/.... creates an id value that lives within the applications namespace. Contrast this with #android:id/.... which lives in the android namespace.
When you set the id in code and add the view element to the layout it will then become available to access through the code. You won't be able to reference it from the xml
Not sure you want to be using random to generate your ids? think sequential would be better but even then what is the point of a random id? How do you know which view you are referring to?
Definitely use the tag option and look to use the ViewHolder pattern for smoother list scrolling. You could add the id to the view holder class if you need access to it but it would be available anyway through the data set being used to populate the list. A quick search will give you plenty of examples for this.
Related
I want to give ids to multiple views created programmatically and each id to be a specific integer based on my own logic. Consider the following example:
I have M colors defined in a sequential way, e.g. using enum, or using an array to put M color values. (Which implementation/structure to use is part of the puzzle and suggestions need to be provided for this as well, in order to achieve the final goal described below.)
Create N instances of a custom Class and store them in a sequential way too (e.g. an array of N elements). This custom Class will just have a member mColor where a color for the specific instance will be stored.
Create (programmatically always) N RadioGroups with M RadioButtons for each RadioGroup.
The goal is when user clicks the j-th RadioButton of the i-th RadioGroup, then the i-th instance will use as background color the j-th color.
So, I would like to do something like this when OnCheckedChanged event occurs for a RadioGroup:
public void onCheckedChanged(RadioGroup group, int checkedId) {
int i = group.getId();
/*j variable is not actually needed here, but is used for concistency
with the description above.*/
int j = checkedId;
/*assume for simplicity that an array of N elements is used to store
the N CustomCLass instances and an array of M elements is used for
colors*/
customClassArray[i].setmColor(colorsArray[j]);
}
From the above, I think it is necessary that specific ids for the programmatically created RadioGroups and RadioButtons need to be set. If there is a way for this to be done, then code will be clear, optimized and no switch statements will be needed for N RadioGroups and M RadioButtons (for which, in any case, I have no clue about how it could be implemented too).
Which is the best way to achieve this, firstly with efficiency in mind and secondly, with clear code in mind?
Thank you in advance for any suggestions.
Edit: For clarification, I have read about setting my own ids by using View.setId(), but there are many resources on the web which are against this hardcoded approach (and I also vote against this if there is another way) and many of them suggest using xml resource to put your ids. However, as I said earlier, I think this is not what I want in order to achieve my goal.
Example links suggesting this approach: https://code.google.com/p/android/issues/detail?id=75081 or also How to set Id of dynamic created layout?.
Also, this approach is the suggested one in the android developer documentation: http://developer.android.com/guide/topics/resources/more-resources.html#Id
Lastly, I have also read this: What is the main purpose of setTag() getTag() methods of View? which explains the purpose of Tags and the use of setTag()/getTag() methods. This may be the best approach I've found so far for what I need. However, it surely introduces more complicated, unsupportable code. In any case, the right way, I think, has to be connected with ids, whose purpose is to uniquely identify views, rather than tags.
As you are creating RadioGroups and RadioButtons from java, I suggest to create a map and use radiobutton reference as key and instance-color combination as value. assign a single checkChangedListener to all your radioButtons and process the event as follows
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
colorInstanceCombo = map.get(buttonView);
//use colorInstanceCombo to do your work
}
assigning ids dynamically can cause problems as id is an integer and your assigned ids may cause conflict with system assigned ids to other components.
I have a view which I get from the parent ViewGroup:
mActiveCard = getChildAt(LAST_OBJECT_IN_STACK);
I later what to check if mActiveCard equals to another view:
anotherCard = getChildAt(x);
A naive approach would have been to check if x== LAST_OBJECT_IN_STACK however there might be many changes in the ViewGroup e.g. removed objects. So the positions are relative.
Also I can save the object for later but that will consume some more memory, like:
mActiveCard.equals( getChildAt(LAST_OBJECT_IN_STACK) )
One idea is to setId() of the view or setTag(). So if I have a unique String/int then I could later get the id or the tag. So saving just the id/tag would require less memory, right?
First of all is my theory correct? Also, does Android SDK offer a way to identify tags and what can be an good id/tag to generate and set on that view?
If you are truly holding onto a reference to a View (mActiveCard) that you know is also in the child list, you can simply compare their references.
if (mActiveCard == getChildAt(x))
{
// ...
}
I would like to create dynamic table in android (custom number of rows and columns). Minimum sdk is 3.0
I suppose to crate it via one of 2 ways:
1) via creating new TextView
TableRow tr = ....;
for ( i = 0; i < NumOfRows .... ) {
TextView tv = new TextView(this);
tv.setLayoutParams(...);
tv.setText("Text I wanna to see");
tr.add(tv);
}
2) via inflater
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for ( i = 0; i < NumOfRows .... ) {
TextView tv = (TextView) mInflater.inflate(R.layout.my_cell_layout, null, false)
.findViewById(R.id.my_cell_item);
tv.setText("Text I wanna to see");
tr.add(tv);
}
3) Your way :)
What is faster? What should I select?enter code here
It's all as per your requirement that which is better.
from link http://www.aslingandastone.com/2010/dynamically-changing-android-views/
Because layouts can be created either in XML or in code, you could probably make do without ever having to do dynamic XML layout loading. That being said, there are some clear advantages as to why I think one may want to do so:
Code cleanliness. Doing anything more than basic layouts in code can get very messy, very fast.
Code re-use. It’s extremely easy to inflate an XML layout into a specified view with one or two lines of code
Performance. Creating the objects necessary for an in-code layout leads to unnecessary garbage collection. As per the Android Designing for Performance article, “avoid creating short-term temporary objects if you can.”
Attribute availability. Defining Views in an XML layout exposes attributes that are not always available by object methods.
*
Possible disadvantages:
It make take more time to do an XML layout versus defining the layout in code, especially if there are only one or two interface elements that need to be changed.
*
To find out which is faster, implement both methods and use the method profiling utility, TraceView. That being said, its easier to maintain an XML file when making changes than it is to modify code. So, if I were you, I would prefer technique #2.
Lets say that I have two different types of RelativeLayouts. That is to say these 2 RelativeLayouts differ because they contain different views. One might have textviews, an image view etc and the other might have also have some textviews which mean something completely different than the other set of textviews in the other relativelayout. Lets say however that both have a Submit Button. So to make my point more clear here is some code:
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
ViewParent parent = v.getParent();
if(parent instanceof CustomRelativeLayout){
CustomRelativeLayout aRelativeLayout = (CustomRelativeLayout)parent;
for(int childrenIndex = 0; childrenIndex < r.getChildCount(); childrenIndex++){
View childView = aRelativeLayout.getChildAt(childrenIndex);
}
}
}
The problem here is is that we don't know which CustomRelativeLayout aRelativeLayout is referring to. Depending on which CustomRelativeLayout it is will depend on what specific childViews i will want to search for and what logic I implement relevant to those views. I would like to be able to have a switch statement to check which type of CustomRelativeLayout is the parent.
So the questions that i would like to ask is:
how do i get more information about which instance of CustomRelativeLayout refers to the button that was clicked? Is there a way to get the instance variable name?
Once i have found out that information how do i get specific information about the children of the parent view that i am working on? The thought is, is that i might have 30 child views in the parent but i am only interested in one specific view(i might want to get the text of one specific textview as an example). I will know to look for it specifically because i would have done a switch statement on the different instances of my CustomRelativeLayouts(the first question) and therefore i know which view i want to look at, which logic to perform or what other methods that i need to call.
Would appreciate any thoughts or help with this.
For your first question, there are couple options:
Use separate OnClickListeners for each button. Then, each button will only trigger its own listener's onClick() method.
You can give each button a different id either in XML (via the android:id property) or in code (via setId(int id)). Then in onClick() you can check the id of the View that was passed as the argument.
For your second question:
Since you have the parent ViewGroup, you can find specific views within it by using:
TextView interestingView = (TextView) parent.findViewById(R.id.interesting);
This will only search the children of the parent view.
If you need to get an unknown number of views the best strategy is probably iterating through them like you are now. You can identify groups of views by setting a tag either in XML (android:tag) or code (setTag(Object tag) and check them as you iterate. For example, if you have a set of TextViews and in each one is either a color or an animal, you might handle that like this:
// defined elsewhere
private static final String TAG_COLOR = "color";
private static final String TAG_ANIMAL = "animal";
...
int count = parent.getChildCount();
for (int i = 0; i < count; i++){
View view = parent.getChildAt(i);
if (TAG_COLOR.equals(view.getTag()) {
// handle color
} else if (TAG_ANIMAL.equals(view.getTag()) {
// handle animal
}
}
There are several ways to do this.
Use "id" to identify views. You can give different id to different views, and then it will be possible to identify them. See http://developer.android.com/reference/android/view/View.html#getId() (the API documentation of View.getId()) for more information.
Mark each view with different tags, and identify them through tags. See http://developer.android.com/reference/android/view/View.html#getTag() (the API documentation of View.getTag()) for more information.
If you want to customize more, just inherit default Android views, and use "instanceof" to identify them.
I use a custom list adapter and ArrayList for my ListView. This solution was good enough but now I need to use Map of ArrayLists, something like this:
TreeMap<String, ArrayList<ItemsModel>>
where ItemsModel is a Java bean. Earlier I used to populate this ArrayList it that way:
itemsDataArrayList.add(itemModel)
Now I faced some difficulties with Map interface. First, I don't know how to populate my new Map structure: I suppose this
mapInstance.put(itemModel.getItemName.toString(), itemsDataArrayList)
won't work because itemsDataArrayList is the list of elements, not a certain element.
Second, I'm not sure how to properly declare this map instance in my ItemsAdapter class. When I was using just ArrayList it was very simple. Some examples would be very helpful.
What I recommend you look into / try is creating your own BaseAdapter. When you override this class it will give you all the functions you need to override to populate the list view.
This has the advantage of giving you complete control of what is put into the listview and how each view is created.
Then after you get it working I recommend looking into the ViewHolder design pattern along with recycling views which is a great way of improving efficiency when scrolling the listview.
What you are really looking for seem to be a MultiMap. To your first Question - your attemp was quite good, you can only put ArrayLists as values into your TreeMap.
The Problem with this might be, that if you want to add some ItemsModel to your Map, you first need to get the List of the key, and then add the ItemsModel to that list. Additionally you need to ensure, that this list for this particular key exist, and if not, create it.
Example:
String key = "hi";
ArrayList keyList = mapInstance.get(key);
if (keyList == null) {
keyList = new ArrayList();
mapInstance.put(key, keyList);
}
keyList.add(itemsModelInstance);
A get()/contains() and so on may be somehow equal. I'd suggest you build your own Multimap<?,?> Implementation or just take an existing one, like the one from Guava (link above).
Kind regards,
avi