1

I'm having a bit of a problem with my code for a ListView, it is supposed to present a list of available devices that have not yet been paired with the device.

I've included the error below:

FATAL EXCEPTION: main
at com.zephyr.bolt.UnpairedDeviceViewer$StableArrayAdapter.getItemId(UnpairedDeviceViewer.java:110)
at android.widget.AbsListView.obtainView(AbsListView.java:2198)

(I didn't include the entire error sadly, the error is on my tablet, and I can't seem to copy it out of AIDE)

Below is the referenced class file and it's XML file

UnpairedDeviceViewer.java

package com.zephyr.bolt;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

public class UnpairedDeviceViewer extends Activity{
    Activity a = this;
    private ListView listview;
    private Button b1;
    public StableArrayAdapter adapter;
    private ArrayList strings;
    private BroadcastReceiver recv;

protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.udv);

    b1 = (Button) findViewById(R.id.b5);

    listview = (ListView) findViewById(R.id.l2);

    strings = new ArrayList<String>();

    adapter = new StableArrayAdapter(this, android.R.layout.simple_list_item_1, strings);

    recv = new BroadcastReceiver() {

        @Override
        public void onReceive(Context arg0, Intent arg1) {
            String action = arg1.getAction();

            if(BluetoothDevice.ACTION_FOUND.equals(action))
            {
                BluetoothDevice device = arg1.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

                adapter.add(device.getName() + "\n" + device.getAddress());
                adapter.notifyDataSetChanged();

            }
            else if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action))
            {
                Toast.makeText(a, "Device Discovery Started", Toast.LENGTH_LONG).show();
            }
            else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action))
            {
                Toast.makeText(a, "Device Discovery Completed", Toast.LENGTH_LONG).show();
            }

        }

    };

    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
    filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
    registerReceiver(recv, filter);

    listview.setAdapter(adapter);

    b1.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            MainActivity.bTAdapter.startDiscovery();

        }
    });


}

protected void onDestroy()
{
    MainActivity.bTAdapter.cancelDiscovery();
    unregisterReceiver(recv);
}


private class StableArrayAdapter extends ArrayAdapter<String> {

    HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();

    public StableArrayAdapter(Context context, int textViewResourceId,
                              List<String> objects) {
        super(context, textViewResourceId, objects);
        for (int i = 0; i < objects.size(); ++i) {
            mIdMap.put(objects.get(i), i);
        }
    }

    @Override
    public long getItemId(int position) {
        String item = getItem(position);
        return mIdMap.get(item);
    }

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

}

}

udv.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:android="http://schemas.android.com/apk/res/android" >
    <Button 
        android:id = "@+id/b5"
        android:layout_centerHorizontal="true"
        android:layout_width = "match_parent"
        android:layout_height = "wrap_content"
        android:text = "Begin Discovery"
        />  
    <ListView 
        android:id = "@+id/l2"
        android:layout_below="@+id/b5"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </ListView>
</RelativeLayout>
brad95411
  • 141
  • 1
  • 1
  • 12

1 Answers1

1

Your mIdMap is an overly complicated way of doing what ArrayAdapter already does. Its implementation of getItemId(pos) returns pos.

Note you are only building your mIdMap once, any items you add post-construct - like in your receiver callback - will not have ids, and will cause a NPE in your getItemId implementation trying to unbox null.

Also, calling notifyDataSetChanged() is unnecessary, ArrayAdapter will automatically call it after each add() by default.

jspurlock
  • 1,466
  • 10
  • 7
  • Thanks much for a quick answer, I switched to the regular ArrayAdapter and everything seems to be working the way it should. Guess I should be more aware of the code I use from online tutorials. – brad95411 Nov 02 '13 at 04:46