Android: findViewById of an ImageView (custom adapter)
Asked Answered
B

1

1

I've been trying to re-set the size of an ImageView. I'm using a custom adapter.

View row = convertView;
if (row == null) {
    LayoutInflater inflater =  (LayoutInflater)
        context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    row = inflater.inflate(R.layout.grid_item, null);
}

thumb = (ImageView) row.findViewById(R.id.bookThumb);

When I use ImageView thumb = (ImageView) row.findViewById(R.id.bookThumb); inside the custom adapter it works great but because it's looping through every row it makes the scrolling very slow.

So... I'm now trying to get the thumb = (ImageView) row.findViewById(R.id.bookThumb); from my Main Activity and set its size but I get Null and therefore the app force closes.

Tried:

LinearLayout layout = (LinearLayout) findViewById(R.id.gridLayout);
ImageView thumbRow = (ImageView)layout.findViewById(R.id.bookThumb);

Also tried:

// gv is the gridview (R.id.gridview)
ImageView thumbRow = (ImageView)gv.findViewById(R.id.bookThumb);

Always get null.

Appreciate any help! feels like I'm missing something silly :)

Bantam answered 20/3, 2011 at 15:1 Comment(8)
Try using hierarchyviewer to see what actually your view hierarchy looks like.Collusive
Where in your main activity are you doing this? Is it after setContentView has been called?Sjambok
@Gil, I'll try using that... thanks. @slund, yeah, after. Also, checked for any false imports of android.R, closed ImageView with /> instead of </imageview> and basically did everything I found on google :)Bantam
as you're using an adapter, I suppose there are many elements with id R.id.bookThumb. If some branch of the view hierarchy contains many elements with the same id, and you call findViewById() from the root of that branch, it will return null because it doesn't know which one you want.Sharpfreeze
@Sharpfreeze - you're right of course. My question is how can I set it for all bookThumb imageviews? When I set the width through the adapter, it worked but made the scrolling very slow.Bantam
oh. I'm not sure at all if it will work, but maybe you could set in first place on all the ImageView (when adding them) the same LayoutParams object, then modify that object and call a requestLayout() on the gridview?Sharpfreeze
@liorry it didn't work, did it?..Sharpfreeze
nope :) at least not for me. I ended up optimizing my code a bit more and changed some of the logic.. helped a little.Bantam
C
3

I think the problem stems in two places.

First off the original problem. Your Adapter is slow because of the findViewById call. You make use of the recycled view and that's great, but you still traverse the view for the thumbnail. There is a technique, informally called ViewHolder, which basically makes it more of a direct call.

So instead of just using the recycled view as a place to start filling data, also attach some structure to it so you can prefetch the elements you want to manipulate

if (row == null) {
    LayoutInflater inflater =  (LayoutInflater)
        context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    row = inflater.inflate(R.layout.grid_item, null);
    row.setTag(row.findViewById(R.id.bookThumb));

}

thumb = (ImageView) row.getTag();

Here we call directly by variable and no traversing is done. This should be much faster.

Also the second problem, the NullPointerExcepton.

I think it's the ambiguity of ids mixed with the point at which you call findViewById in your main activity. You can't really do it well in your mainActivity especially if there is scrolling involved as you would have to intercept the call to render within the adapter view. Most of the callbacks are already on the main thread so two things cannot happen at the same time on that thread.

So at the point you called findViewById() the adapter may not have even run yet and attached that view to the hierarchy. And if it did, it might not have finished manipulating it yet.

I would try to speed up your adapter before approaching the second issue as I am not sure it is even possible to do it safely or accurately, without abandoning the use of an adapter view entirely.

Caballero answered 20/3, 2011 at 18:14 Comment(5)
Greg, thank you for your well explained answer! Unfortunately, it did not influence on my speed issue. What causes my speed issue is a function I wrote that changes the thumbnail size according to the user screen size and some settings. I know this is the cause to the major slow down as when I disable it, the gridview scrolls smooth (just like the listview I have in my app). I find it weird it's impossible to change the XML of an ImageView from anywhere I want using code... I only want to change its width and height..Bantam
But can't you change the thumbnail upfront? You don't have to do that on the UI Thread. The imageview will scale the image too (unfortunately on the UI Thread). How much of a slow down are you seeing?Caballero
Not that much of a slowdown but noticeable comparing to my listview where I don't do these calculations. The problem is I calculate the thumbnail size on runtime because the user can select if he wants 2 columns or 3 columns. with that, I also take the screen resolution in consideration.Bantam
I still don't understand I guess. I think you could do all this through the grid view (it's not as fast as the listview, but it's tolerable usually). The only thing I could say then is if grid view is too slow, then don't use adapter views and do the rendering yourself using raw draws. That will get you the faster render but at the cost of more implementation and more maintenance.Caballero
I'll try to make the code smaller and more efficient. Remove some Ifs and elses :) Thank you!Bantam

© 2022 - 2024 — McMap. All rights reserved.