Search code examples
javaandroidlistviewarraylistbaseadapter

Android: Only last item in ListView is displayed implementing BaseAdapter


Some background information first:

In my android application I have some information in a SQLite database relating to a physical key. This information includes the name of the 'service provider' who issued the key as well as a description of what door the key is for and the id of that door. What I am attempting to do is display all of the information for each 'key' in a row of a ListView element and have a delete button at the end of the row which can be used to delete that information from the database.

Now the problem is when I have tried this the only entry that displays in the activity is the last one and where the other entries would have been is empty space. See screen shot here: (https://i.sstatic.net/8C15B.png)

The space I outlined in red is the blank space left from where the first 3 entries would be. I have looked this up and all of the responses to this kind of question have been a problem with the way that they have entered the data into the arraylist but I have tested and the arraylist is populated with all 4 entries correctly. I just don't know why they are not displaying and I am relatively new to android so any help would be appreciated!

Here is the code from the relevant files: MainActivity.java: (Complete with my debugging print statements. These print statements all show that there are 4 different entries in the ArrayList after adding them in the do while loop of the addKeyItems() method.)

public class MainActivity extends AppCompatActivity {

private ListView mKeyListView;
//for the nav drawer
private ListView mDrawerList;
private ArrayAdapter<String> mAdapter;
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
private String mActivityTitle;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if(SaveSharedPreference.getUserName(MainActivity.this).length()==0){
        //log in
        Intent intent = new Intent(this, LoginActivity.class);
        startActivity(intent);
        finish();
    }else{
        setContentView(R.layout.activity_main);

        TextView textView = (TextView) findViewById(R.id.display_username);
        String name = SaveSharedPreference.getUserName(this);
        textView.setText("Logged in: " + name);

        //navigation drawer
        mDrawerList = (ListView)findViewById(R.id.navList);
        System.out.println(mDrawerList);
        addDrawerItems();
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);
        mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
        mActivityTitle = getTitle().toString();
        setupDrawer();

        //main content
        mKeyListView = (ListView) findViewById(R.id.keyList);
        addKeyItems();

    }
}
private void addKeyItems(){
    DbAccess dba = new DbAccess();
    Cursor cursor = dba.getKeys(getApplicationContext());
    if(cursor.moveToFirst()) {

        List<KeyModel> myKeyModelList = new ArrayList<KeyModel>();
        int position = 0;
        do {
            KeyModel key = new KeyModel();
            key.setReaderId(cursor.getLong(cursor.getColumnIndexOrThrow(KeyReaderContract.KeyEntry._ID)));
            key.setSpName(cursor.getString(cursor.getColumnIndexOrThrow(KeyReaderContract.KeyEntry.SP_NAME)));
            key.setReaderDesc(cursor.getString(cursor.getColumnIndexOrThrow(KeyReaderContract.KeyEntry.READER_DESCRIPTION)));
            myKeyModelList.add(key);
            System.out.println(position+ " "+ key.getSpName()+ " "+ key.getReaderDesc());
            position++;
        } while (cursor.moveToNext());

        for(int i = 0; i < myKeyModelList.size(); i++){
            KeyModel test = myKeyModelList.get(i);
            System.out.println(test.spName+ " "+ test.readerDesc);
        }

        //create adapter with the arraylist of keys
        MyListAdapter mKeyAdapter = new MyListAdapter(getLayoutInflater().inflate(R.layout.key_list_entry, (ViewGroup)findViewById(R.id.main_linear_layout)));
        mKeyAdapter.setModel(myKeyModelList);

        //set the adapter to the ListView
        mKeyListView.setAdapter(mKeyAdapter);

    } else{
        System.out.println("No keys");
    }

}

private class KeyModel{

    long readerId;
    String spName;
    String readerDesc;

    public long getReaderId() {
        return readerId;
    }

    public void setReaderId(long readerId) {
        this.readerId = readerId;
    }

    public String getSpName() {
        return spName;
    }

    public void setSpName(String spName) {
        this.spName = spName;
    }

    public String getReaderDesc() {
        return readerDesc;
    }

    public void setReaderDesc(String readerDesc) {
        this.readerDesc = readerDesc;
    }

    View.OnClickListener listener = new View.OnClickListener(){

        @Override
        public void onClick(View v) {
            Toast.makeText(MainActivity.this, spName, Toast.LENGTH_SHORT).show();
            //do other things to delete this once all items are displaying correctly
        }
    };
}

private class MyListAdapter extends BaseAdapter{
    View renderer;
    List<KeyModel> keys;
    // call this one and pass it layoutInflater.inflate(R.layout.key_list_entry)
    public MyListAdapter(View renderer) {
        this.renderer = renderer;
    }

    // whenever you need to set the list of keys just use this method.
    // call it when you have the data ready and want to display it
    public void setModel(List<KeyModel> keys){
        this.keys = keys;
        System.out.println(keys.size());
        notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        if(keys!=null){
            return keys.size();
        }
        return 0;
    }
    @Override
    public Object getItem(int position) {
        if(keys!=null){
            return keys.get(position);
        }
        return null;
    }
    @Override
    public long getItemId(int position) {

        if(keys!=null){
            System.out.println("item id "+ position);
            return position;
        }
        System.out.println(-1);
        return -1;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView==null){
            convertView = renderer;
        }
        KeyModel key = keys.get(position);
        System.out.println(position+ " "+ key.getSpName()+ " "+ key.getReaderDesc());

        TextView rIdView = (TextView)convertView.findViewById(R.id.key_id);
        rIdView.setText(Long.toString(key.readerId));

        TextView spNameView = (TextView)convertView.findViewById(R.id.sp_name);
        spNameView.setText(key.spName);

        TextView readerDescView = (TextView)convertView.findViewById(R.id.reader_desc);
        readerDescView.setText(key.readerDesc);

        Button button = (Button)convertView.findViewById(R.id.delete_keyButton);
        button.setOnClickListener(key.listener);
        convertView.setVisibility(View.VISIBLE);
        return convertView;
    }
}

activity_main.xml:

<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The first child in the layout is for the main Activity UI-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/main_list_layout">
    <TextView
        android:id="@+id/display_username"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <ListView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/keyList"
        android:orientation="vertical" >
    </ListView>
</LinearLayout>
<!-- Side navigation drawer UI -->
<ListView
    android:id="@+id/navList"
    android:layout_width="200dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:background="#424242"/>

key_list_entry.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/main_linear_layout">

<RelativeLayout
    android:layout_width="0dip"
    android:layout_height="fill_parent"
    android:layout_weight="0.05">
    <TextView
        android:id="@+id/key_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</RelativeLayout>

<RelativeLayout
    android:layout_width="0dip"
    android:layout_height="fill_parent"
    android:layout_weight="0.35">
    <TextView
        android:id="@+id/sp_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</RelativeLayout>

<RelativeLayout
    android:layout_width="0dip"
    android:layout_height="fill_parent"
    android:layout_weight="0.35">
    <TextView
        android:id="@+id/reader_desc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</RelativeLayout>
<RelativeLayout
    android:layout_width="0dip"
    android:layout_height="fill_parent"
    android:layout_weight="0.25">
    <Button
        android:id="@+id/delete_keyButton" style="?android:textAppearanceSmall"
        android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="@string/delete" android:textStyle="bold"  />
</RelativeLayout>

In the print statement in the GetView method of MyListAdapter: System.out.println(position+ " "+ key.getSpName()+ " "+ key.getReaderDesc()); It prints each of the 4 elements in the list correctly as that method is called:

Here is the ouput:

09-28 20:23:47.731  20156-20156/com.blah.blah I/System.out﹕ 0 Company1 Front door
09-28 20:23:47.745  20156-20156/com.blah.blah I/System.out﹕ 1 Company1 Back Door
09-28 20:23:47.745  20156-20156/com.blah.blah I/System.out﹕ 2 Occipitech Front door
09-28 20:23:47.746  20156-20156/com.blah.blah I/System.out﹕ 3 Occipitech Garage door

Again any help would be appreciated! This is my first post so let me know if I have done something wrong or you need any more information. I think the problem may be in my implementation of BaseAdapter, since the list itself has all of the correct information in it.


Solution

  • There must not be single view used in all list item. All rows displayed in list must be a unique view which are recycled according to data passed.

    So change ..

    if(convertView==null){
            convertView = renderer;
     }
    

    to

    if(convertView==null){
         LayoutInflater inflater = LayoutInflater.from(parent.getContext());
         convertView = inflater.inflate(R.layout.key_list_entry);
     }