Rows are repeated in ListView

I know this question has popped up several times, but for some reason I cannot get it to work. The fact that getView gets called multiple times in certain cases.

However, in the example shown here: http://android.amberfog.com/?p=296 it says that the first call for every row in the data should get a null value in currentView. This is not happening.

What is happening for me is that calls where position is 0 have currentView set to null, whereas calls where position is 1 have currentView set to the existing object.

There are 16 calls to "getView" in total, but I am getting rows duplicated once (ie, two from each row). Line 0 Line 1 Line 0 Line 1

I probably just didn't understand anything from this post.

Markup:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"   
    android:layout_height="fill_parent"
    >
    <TextView android:id="@+id/title_paired_devices" 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/title_paired_devices" 
        android:visibility="gone"
        android:background="#666"
        android:textColor="#fff"
        android:paddingLeft="5dp"
    />
    <ListView android:id="@+id/paired_devices"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:stackFromBottom="true"
        android:layout_weight="1"
    />
    <TextView android:id="@+id/title_new_devices"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/title_other_devices"
        android:visibility="gone"
        android:background="#666"
        android:textColor="#fff"
        android:paddingLeft="5dp"
    />
    <ListView android:id="@+id/new_devices"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:stackFromBottom="true"
        android:layout_weight="2"
    />
    <Button android:id="@+id/button_scan" 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/button_scan"
    />
</LinearLayout>

      

Listview string:

    <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android="http://schemas.

android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/list_selector"
    android:orientation="horizontal"
    android:padding="5dip" >

    <!--  ListRow Left side Thumbnail image -->
    <LinearLayout android:id="@+id/thumbnail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="3dip"
        android:layout_alignParentLeft="true"
        android:background="@drawable/image_bg"
        android:layout_marginRight="5dip">

        <ImageView
            android:id="@+id/list_image"
            android:layout_width="50dip"
            android:layout_height="50dip"
            android:src="@drawable/icon"/>

    </LinearLayout>

    <!-- Device Address -->
    <TextView
        android:id="@+id/tvwDeviceAddress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@+id/thumbnail"
        android:layout_toRightOf="@+id/thumbnail"
        android:textColor="#040404"
        android:typeface="sans"
        android:textSize="15dip"
        android:textStyle="bold"/>

    <!-- Display Name -->
    <TextView
        android:id="@+id/tvwDisplayName"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/tvwDeviceAddress"
        android:textColor="#343434"
        android:textSize="10dip"
        android:layout_marginTop="1dip"
        android:layout_toRightOf="@+id/thumbnail"/>


</RelativeLayout>

      

Adapter:

    private class LazyAdapter extends BaseAdapter {

    private Activity activity;
    private ArrayList<MPGDeviceDetails> data;
    private LayoutInflater inflater=null;

    public LazyAdapter(Activity a, ArrayList<MPGDeviceDetails> d) {
        activity = a;
        data=d;
        inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public int getCount() {
        return data.size();
    }

    public Object getItem(int position) {
        return position;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        View vi=convertView;
        Log.e("MPG","Position = " + position + ".  ConvertView = " + convertView);
        if(convertView==null)
            vi = inflater.inflate(R.layout.device_name, null);

        TextView address = (TextView)vi.findViewById(R.id.tvwDeviceAddress); // Device Address
        TextView name = (TextView)vi.findViewById(R.id.tvwDisplayName); // Display name
        ImageView thumb_image=(ImageView)vi.findViewById(R.id.list_image); // thumb image



        address.setText(data.get(position).deviceAddress);
        name.setText(data.get(position).getDisplayName());
        Bitmap photo = data.get(position).getContactPhoto();
        if (photo != null)
            thumb_image.setImageBitmap(photo);


        return vi;
    }
}

      

Using:

    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Setup the window
    requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
    setContentView(R.layout.device_list);

    // Set result CANCELED incase the user backs out
    setResult(Activity.RESULT_CANCELED);

    // Initialize the button to perform device discovery
    Button scanButton = (Button) findViewById(R.id.button_scan);
    scanButton.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            doDiscovery();
            v.setVisibility(View.GONE);
        }
    });

    // Initialize array adapters. One for already paired devices and
    // one for newly discovered devices


    // Find and set up the ListView for paired devices
    pairedListView = (ListView) findViewById(R.id.paired_devices);
    pairedDevicesList = new ArrayList<MPGDeviceDetails>();
    pairedListView.setAdapter((mPairedDevicesArrayAdapter = new LazyAdapter(this,pairedDevicesList)));
    pairedListView.setOnItemClickListener(mDeviceClickListener);
    registerForContextMenu(pairedListView);

    // Get the local Bluetooth adapter
    mBtAdapter = BluetoothAdapter.getDefaultAdapter();

    // Get a set of currently paired devices
    Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();

    // If there are paired devices, add each one to the ArrayAdapter
    if (pairedDevices.size() > 0) {
        findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
        for (BluetoothDevice device : pairedDevices) {
          pairedDevicesList.add(MPGDeviceDetailsControl.getDeviceDetails(this, device.getAddress(), device.getName()));
        }
    } 

}

      

MPGDeviceDetails is an object that contains all the data about a specific device.

This is the output of the "debug" command:

03-27 10:03:30.730: E/MPG(2841): Position = 0.  ConvertView = null.
03-27 10:03:30.742: E/MPG(2841): Position = 1.  ConvertView = android.widget.RelativeLayout@4062d608. 
03-27 10:03:30.746: E/MPG(2841): Position = 0.  ConvertView = null. 
03-27 10:03:30.750: E/MPG(2841): Position = 1.  ConvertView = android.widget.RelativeLayout@40628d78. 
03-27 10:03:30.750: E/MPG(2841): Position = 0.  ConvertView = android.widget.RelativeLayout@4062d608. 
03-27 10:03:30.753: E/MPG(2841): Position = 1.  ConvertView = android.widget.RelativeLayout@4062d608. 
03-27 10:03:30.753: E/MPG(2841): Position = 0.  ConvertView = android.widget.RelativeLayout@40628d78. 
03-27 10:03:30.753: E/MPG(2841): Position = 1.  ConvertView = android.widget.RelativeLayout@40628d78. 
03-27 10:03:30.761: E/MPG(2841): Position = 1.  ConvertView = android.widget.RelativeLayout@4062d608. 
03-27 10:03:30.761: E/MPG(2841): Position = 0.  ConvertView = null. 
03-27 10:03:30.769: E/MPG(2841): Position = 1.  ConvertView = android.widget.RelativeLayout@40628d78. 
03-27 10:03:30.769: E/MPG(2841): Position = 0.  ConvertView = null. 
03-27 10:03:30.777: E/MPG(2841): Position = 0.  ConvertView = null. 
03-27 10:03:30.781: E/MPG(2841): Position = 1.  ConvertView = android.widget.RelativeLayout@406d4af8. 
03-27 10:03:30.781: E/MPG(2841): Position = 0.  ConvertView = null. 
03-27 10:03:30.785: E/MPG(2841): Position = 1.  ConvertView = android.widget.RelativeLayout@40694970. 
03-27 10:03:30.789: E/MPG(2841): Position = 0.  ConvertView = android.widget.RelativeLayout@406d4af8. 
03-27 10:03:30.789: E/MPG(2841): Position = 1.  ConvertView = android.widget.RelativeLayout@406d4af8. 
03-27 10:03:30.789: E/MPG(2841): Position = 0.  ConvertView = android.widget.RelativeLayout@40694970. 
03-27 10:03:30.792: E/MPG(2841): Position = 1.  ConvertView = android.widget.RelativeLayout@40694970. 

      

It looks like this: enter image description here

It's funny that while all 4 buttons work, the context menu only works for the first two!

+3


source to share


4 answers


Try calling notifyDataSetChanged()

your adapter when you're done filling pairedDevicesList

:

if (pairedDevices.size() > 0) {
    findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
    for (BluetoothDevice device : pairedDevices) {
        pairedDevicesList.add(MPGDeviceDetailsControl.getDeviceDetails(this, device.getAddress(), device.getName()));
    }
}
((BaseAdapder)getListAdapter()).notifyDataSetChanged();

      

Or create an adapter after filling pairedDevicesList

.



Also try specifying that your adapter data has stable identifiers:

@Override
public boolean hasStableIds() {
    return true;
}

      

+2


source


In general, apart from regular calls to getView for each item (s), it gets called about 3 times that much because it needs to calculate the dimensions for views for the size of the scrollbar, layout, etc. As for the repeated lines, I think you should paste your code. You may be wrong.



For more information, have a look at this and read this

0


source


The value currentView

should be used for optimization. Android suggests reusing views to save memory and respond faster.

When yor is currentView

not null, you can use it to display the current item.
Take a look at an example:

public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    if (v == null) {
        // we can't reuse view and must read it from layout
        LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.whatever, null);
    }

   // ... use v as view for row
}

      

0


source


You just need an clear

ArrayList before adding values ​​to it.

here in your if

condition

if (pairedDevices.size() > 0) { 
 pairedDevicesList.clear();
 // other code as it is
}

      

also you can put one log before clearing ArrayList.

Log.i("Size","ArrayList Size = "+pairedDevicesList.size());

      

So, you will get more ideas.

0


source







All Articles