Acquiring a view in the hierarchy I have both of these functions available. While findViewById is easier to use, I often saw suggestions that it can be an expensive operation and should be avoided if possible.
Therefore, would it be any quicker to use getChildAt instead? Is there any guideline as to when it is better to use which?
findViewById vs getChildAt - which one is quicker?
getChildAt is indeed faster than findViewById, since it is just accessing an array of Views at the specified index.
Therefore, would it be any quicker to use getChildAt instead
it will indeed, but you have to know the index of the View you are looking for. If you don't have any mechanism to keep track of the index, than you have to look for it, and you got back to findViewById. You will probably ended up re writing your own version of findViewById. My two cents, don't worry about that.
Looking at ViewGroup implementation findViewById will eventually loop through children and compare id so I suggest to just use the findViewByIdmethod.
#Override
protected View findViewTraversal(#IdRes int id) {
if (id == mID) {
return this;
}
final View[] where = mChildren;
final int len = mChildrenCount;
for (int i = 0; i < len; i++) {
View v = where[i];
if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
v = v.findViewById(id);
if (v != null) {
return v;
}
}
}
return null;
}
Related
I am applying images to my ImageButtons in code, but I'm wondering if there is a better way than shown in my example. I definitely know that it's not the correct way to do it as it can take way too much time with large numbers of views.
btn1.setImageResource(R.drawable.plus);
btn2.setImageResource(R.drawable.plus);
btn3.setImageResource(R.drawable.plus);
btn4.setImageResource(R.drawable.plus);
btn5.setImageResource(R.drawable.plus);
btn1.setAdjustViewBounds(true);
btn1.setPadding(0,0,0,0);
btn2.setAdjustViewBounds(true);
btn2.setPadding(0,0,0,0);
btn3.setAdjustViewBounds(true);
btn3.setPadding(0,0,0,0);
btn4.setAdjustViewBounds(true);
btn4.setPadding(0,0,0,0);
btn5.setAdjustViewBounds(true);
btn5.setPadding(0,0,0,0);
you need to get the root view in the activity, cast it to ViewGroup, get all children, check their type and update accordingly. Namely as follows,
ViewGroup rootView = (ViewGroup) findViewById(android.R.id.content);
int children = rootView.getChildCount();
for (int i = 0; i < children; i++) {
View view = rootView.getChildAt(i);
if (view instanceof ImageButton) {
((ImageButton) view).setImageResource(R.drawable.plus);
((ImageButton) view).setAdjustViewBounds(true);
((ImageButton) view).setPadding(0,0,0,0);
}
}
I went to the official doc page android google official doc, but it seems that they made a serious typo : we have no information about the third argument of the method. So I just wonder if someone already knows how to define this third int argument.
The childMeasuredState is the value returned by View.getMeasuredState(). A layout will aggregate its children measured states using View.combineMeasuredStates(). Here is an example:
int childState = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
measureTheChild(child);
childState = combineMeasuredStates(childState, child.getMeasuredState());
}
}
In most case however you can simply pass 0 instead. The child state is currently used only to tell whether a View was measured at a smaller size than it would like to have. This information is in turn used to resize dialogs if needed. In your particular case you shouldn't worry about it.
I did get the drag and drop working and the TouchListView class works great. However in my case I have rows of various height due to my adapter which contains an EditText that can have multiple lines. Therefore after I drop, all my rows convert to the tlv:normal_height which in my case is 74dip. This causes many rows to cut off all my text in the EditTexts. I tried re initializing my adapter (mylistview.setAdapter= myadapter), setting the ListView to GONE then VISIBLE and invalidateViews() but nothing seems to reset the ListView back to before I dragged, short of leaving the activity and coming back. What can be done here? -Thx
tlv:normal_height="74dip"
tlv:expanded_height="128dip"
There's little question that the original AOSP code was designed for uniform row heights, and the whole expanded_height construct was there to provide space for the user to visualize where the drop would occur.
One starting point would probably be to create a TouchListAdapter mixin interface (akin to SpinnerAdapter) where the normal_height and expanded_height would be retrieved dynamically from the adapter based on position as opposed to being fixed values declared in the layout. Whether that alone would be sufficient or more work would need to be done, I can't say.
If you come up with a solution, patches are welcome. Otherwise, I'll probably take a look at this sometime, but not very soon.
My apologies for not having a near-term silver bullet.
I edited the unExpandViews() method - called getAdapter() and for every item in my adapter set the height to 0 and then all the rows were set back to original. I also bypassed the delete part of the method since it did not apply to me.
private void unExpandViews(boolean deletion) {
int height_saved = 0;
CheckBoxifiedTextListAdapter cbla = (CheckBoxifiedTextListAdapter)getAdapter();
for (int i = 0;i < cbla.getCount(); i++)
{
//View v = getChildAt(i);
View v = cbla.getView(i, null, null);
//if (v == null)
//{
/*
if (deletion)
{
// HACK force update of mItemCount
int position = getFirstVisiblePosition();
int y = getChildAt(0).getTop();
setAdapter(getAdapter());
setSelectionFromTop(position, y);
// end hack
}
layoutChildren(); // force children to be recreated where needed
v = getChildAt(i);
if (v == null)
{
break;
}
height_saved = v.getHeight();
*/
//}
//else
//height_saved = v.getHeight();
if (isDraggableRow(v))
{
ViewGroup.LayoutParams params = v.getLayoutParams();
params.height = 0;
v.setLayoutParams(params);
v.setVisibility(View.VISIBLE);
}
}
}
Does anyone have a quick and easy method for removing dynamically added buttons from a Linear Layout in Android? They seem to be kept in the saved instancestate and I don't want them when I return to the activity.
You may clear ALL views in a linear layout by using the following code:
LinearLayout myLayout = (LinearLayout)findViewById(R.id.your_linear_layout);
myLayout.removeAllViews();
However, if you are looking to remove only the views that were dynamically added (and you have views in there that are not) this will not work.
If you need to do it this way you can do something like this
LinearLayout l = (LinearLayout)findViewById(R.id.linearLayout);
List<View> removeViews = new ArrayList<View>();
int count = l.getChildCount();
for (int i = 0; i < count; i++) {
View v = l.getChildAt(i);
if (v != null && v.getTag() != null
&& v.getTag().toString().equals("dynamicView")) {
removeViews.add(v);
}
}
for (View v : removeViews) {
l.removeView(v);
}
Please notice the v.getTag() != null && v.getTag().toString().equals("dynamicView") portion. You don't have to do it this way, however, this would be an easy way to differentiate between a view you added and a view that was statically created.
Edit in order for this to work when you create the view you need to call view.setTag("dynamicView"); of course
Hey this is my first time trying anything like so I don't know if this is even close to the best way to do this, but I thought it would work. I'm trying to go through the XML layout file and set all TextView's to be INVISIBLE. When the following method is called I get a NullPointerException
public void numPlayerSetup(){
{
for(int i = 3; i <= 6; i++)
for(int z = 2; z <= 10; z++){
int resID = getResources().getIdentifier("TextView"+Integer.toString(z) + Integer.toString(i), "id", this.getPackageName());
if(resID != 0){
TextView text = (TextView) this.findViewById(resID);
text.setVisibility(View.INVISIBLE);
}
}
Let me know if you have any suggestions. Thanks!
Well, are the ids going to change? If not, just set up an int[] of TextView IDs, and loop through those, e.g.:
int[] ids = {
R.id.tv1, R.id.tv2, R.id.tv3 //...
}
for(int i : ids) {
TextView tv = (TextView)findViewById(i);
tv.setVisibility(View.INVISIBLE);
}
I would definitely not try using reflection, it'd be a lot less efficient than doing it in other ways. If you don't know the IDs of the TextViews ahead of time, why not try something like this (assuming your root layout is a RelativeLayout):
RelativeLayout root = (RelativeLayout)findViewById(R.id.root);
for(int i = 0; i < root.getChildCount(); i++) {
View v = findViewById(i);
if(v instanceof TextView) {
((TextView)v).setVisibility(View.INVISIBLE);
}
}
Since you've already accepted, I'll assume method 1 worked, because I just realized I was horribly off on method 2. It should be getChildAt(i), not findViewById(i), as that would just be calling findViewById(0|1|2|...etc). Below is a corrected version:
RelativeLayout root = (RelativeLayout)findViewById(R.id.root);
for(int i = 0; i < root.getChildCount(); i++) {
View v = root.getChildAt(i);
if(v instanceof TextView) {
((TextView)v).setVisibility(View.INVISIBLE);
}
}
I haven't tested that, but it sounds good in theory. :)
Did you do some debugging?
For instance, have a look if the resIDs match. At least they're not zero, if your error occurs right there. (Have you checked that?).
It may sound odd, but you could also check if getResources() and this.findViewById() refer to the same object.
That's all I can think of for the moment.
As the others have indicated, the most obvious cause of a NullPointerException would be that you're not checking if text is null before calling setVisibility(). You'll want to look into why text would be null in the first place- but you should check your pointers regardless.
Or just go with kcoppock's alternative.
Any particular reason you're using setVisibility? It isn't always appropriate- I believe all it does is keep draw from being called, which can cause issues later if you hoped to treat it as drawn but invisible.