0

How do I create a working ListView in Android?

I am not looking for you to just fix my code, but am looking for a simple working example of a ListView in Android so I can understand the process of creating one and working with it. But I have included my code so you can see where I am coming from and what I have been trying.

I have done the following and had no success:

--

Made a xml layout with only a TextView item in it:

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

Created the following class as per the instructions at the following tutorial: http://www.vogella.com/tutorials/AndroidListView/article.html

public class DataTempleArrayAdapter extends ArrayAdapter<String> {

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

public DataTempleArrayAdapter(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;
}

}

And in the main activity I have a snippet of code where I attempt to add a list of strings to the ArrayList associated with the DataTempleArrayAdapter here:

int i;
for (i=0;i<dirContents.length;i++) {
    dirList.add(dirContents[i]);
    //Toast.makeText(this, dirList.get(i), Toast.LENGTH_SHORT).show();
}
adapter.notifyDataSetChanged();

dirList is successfully populated, while the adapter doesn't update the ListView at all.

--

Before you ask for it, here I am including the rest of the relevant code:

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="org.hacktivity.datatemple.MainActivity">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

<EditText
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:inputType="text"
    android:hint="@string/directory"
    android:ems="10"
    android:layout_alignParentTop="true"
    android:layout_alignParentStart="true"
    android:id="@+id/dirEditText" />

    <Button
        android:text="→"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true"
        android:id="@+id/dirButton"
        android:onClick="populateDirList" />

</LinearLayout>

<ListView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    android:id="@+id/dirListView" />

</LinearLayout>


</RelativeLayout>

And alas the MainActivity class:

public class MainActivity extends AppCompatActivity {

ListView dirListView;
EditText et;
DataTempleArrayAdapter adapter;
ArrayList<String> dirList;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    dirListView = (ListView) findViewById(R.id.dirListView);
    et = (EditText) findViewById(R.id.dirEditText);

    dirList = new ArrayList<String>();


    dirListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                                int position, long id) {

            Toast.makeText(getApplicationContext(),
                    "Click ListItem Number " + position, Toast.LENGTH_LONG)
                    .show();

            populateDirList(view);
        }

    });


    ArrayList<String> dirList = new ArrayList<String>();
    adapter = new DataTempleArrayAdapter(this,
            R.id.dir_text_view, dirList);

    dirListView.setAdapter(adapter);

}

public void populateDirList (View view) {

    File f;

    // NO INPUT.
    if (et.getText().toString().equals("")) {
        Toast.makeText(this, "empty string", Toast.LENGTH_SHORT).show();
        return;
    }

    f = new File(et.getText().toString());
    if (f == null) { return; }

    String dirContents[] = f.list();
    if (dirContents == null) { return; }
    dirList = new ArrayList<String>(Arrays.asList(f.list()));

    adapter.clear();

    int i;
    for (i=0;i<dirContents.length;i++) {
        dirList.add(dirContents[i]);
        //Toast.makeText(this, dirList.get(i), Toast.LENGTH_SHORT).show();
    }
    adapter.notifyDataSetChanged();

}
}
Graffiti Plum
  • 95
  • 1
  • 8
  • http://www.androidhive.info/2011/10/android-listview-tutorial/ check this link..and you may use recycler view which is a improved version of listview http://www.androidhive.info/2016/01/android-working-with-recycler-view/ – Arpan Sharma Oct 10 '16 at 11:26

3 Answers3

1

Excerpt from your code:

@Override
protected void onCreate(Bundle savedInstanceState) {
//...
dirList = new ArrayList<String>();
//...
ArrayList<String> dirList = new ArrayList<String>();
adapter = new DataTempleArrayAdapter(this,
        R.id.dir_text_view, dirList);
//...
}

I bet you already see what the problem is, but in case you don't: You have a field and a local variable with the same name. You pass the local variable to the adapter. It is only naturally that the adapter does not react to changes on the field, as it has no knowledge of its existence.

F43nd1r
  • 7,212
  • 3
  • 21
  • 50
1

I think what you have done wrong is to supply a UI Component to the Array Adapter with:

adapter = new DataTempleArrayAdapter(this, R.id.dir_text_view, dirList);

The second item should not be an ID, but a layout file. Android have already implemented a List item layout with a textview that you can use: android.R.layout.simple_list_item_1.

so replace your row with

adapter = new DataTempleArrayAdapter(this, android.R.layout.simple_list_item_1, dirList);

and you are one step closer.

(This way you don't need your "xml layout with only a TextView item in it")

Joakim
  • 2,863
  • 1
  • 24
  • 48
1
  • One of the best resources for understanding ListView is indeed the one you mentioned from Vogella

  • Another cool resource to understand how the the notifyDataSetChanged() method works in ListView this post from StackOverflow

  • For a short, simple explanation of how to use CustomLayouts in ListView (without the ViewHolder pattern) check another of the best references available: Mkyong

  • Discussing the benefits of the ViewHolder pattern in ListView: check this StackOverflow post

  • Concise example and explanation of the ViewHolder pattern in ListView: check this example from JavaCodeGeeks

And to fix your code I think the answer given before is only part of the problem:

You must indeed comment the line

 //ArrayList<String> dirList = new ArrayList<String>();

because, like @F43nd1r mentioned this would also be a different instance of a list passed into the adapter

but there is more, when you do this:

dirList = new ArrayList<String>(Arrays.asList(f.list()));

you are instantiating a new, different, list, the old reference held by the adapter will NOT be changed... it will still hold the OLD object list

you should perhaps substitute it for something like:

    dirList.clear();
    dirList.addAll(Arrays.asList(f.list()));

Hope this helps!

Community
  • 1
  • 1
HenriqueMS
  • 3,321
  • 2
  • 26
  • 36