views:

57

answers:

3

I have a ListActivity. Each item in the ListView contains a RatingBar. When the user manipulates the RatingBar, I want to update the corresponding data attached to the Adapter.

Unfortunately, inside my RatingBar handler, I can't refer to the position variable. I understand why. I'm just having trouble finding a way around it.

How would I handle what I'm trying to do here?

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    // grab view
    View v = convertView;
    // set view layout
    if (v == null) {
        LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.layout_rating_ratingbubble, null);
        RatingBar r = (RatingBar)v.findViewById(R.id.rating_rating);
        if (r != null) {
            r.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
                    public void onRatingChanged(RatingBar ratingBar, float rating,
                            boolean fromUser) {
                        // CANT REFER TO position HERE
                        m_items.get(position).setRating((int)rating);
                    }
                });
        }
A: 

I understand that your code is not working giving you an error on:

m_items.get(position).setRating((int)rating);

Try doing this:

if (r != null) {
            final int position2 = position;
            r.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
                    public void onRatingChanged(RatingBar ratingBar, float rating,
                            boolean fromUser) {
                        m_items.get(position2).setRating((int)rating);
                    }
                });
Macarse
Thanks for your response. This doesn't work for me. When I debug the handler, it says position2 cannot be resolved.
Andrew
A: 

How about something like this:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    // grab view
    View v = convertView;
    // set view layout
    if (v == null) {
        LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.layout_rating_ratingbubble, null);
        RatingBar r = (RatingBar)v.findViewById(R.id.rating_rating);
        if (r != null) {
            r.setTag(position); // Set the position number as the tag on the view
            r.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
                    public void onRatingChanged(RatingBar ratingBar, float rating,
                            boolean fromUser) {
                        int item_position = (int)ratingBar.getTag(); // Retrieve tag
                        m_items.get(item_position).setRating((int)rating);
                    }
                });
        }
        return v;
}

Although, I would probably add the RatingBar.OnRatingBarChangeListener interface to another object that is instantiated once. (Even the adapter, if you wanted, although it probably doesn't belong there.) As it is, you're creating a new listener object for each RatingBar and that's a little wasteful in the memory department.

TJF
Someone posted this solution and then deleted the solution once I posed my problem with it. My problem is that my list can be altered by the user (ex: deleting a row). This messes up all the indices of the rows below the deleted row. Perhaps adding an ELSE case to that IF-statement and updating the tag would help, but obviously that only happens when the row comes into view. There may be situations where that causes strange behavior.
Andrew
I think tag is really only useful when you are using the ID of a row as it pertains to the data behind it. Uses indexes becomes problematic.
Andrew
A: 

Here is what I have done...

Inside the onRatingChanged handler, we first need to find the position. I've created a small method to do this:

    private int getListPosition(View v) {
        View vParent = (View)v.getParent();
        if (vParent != null) {
            ViewGroup vg = (ViewGroup)vParent.getParent();
            if (vg != null) {
                return getListView().getFirstVisiblePosition() + vg.indexOfChild(vParent);
            }
        }
        return -1;
    }

The rest is simple. Take the result of this method (x) and call:

m_items.get(x).setRating((int)rating);
Andrew