0

I have spent the better half of the day trying to figure out how to read data from my firebase database and display multiple fields in a ListView via an ArrayAdapter. After finally getting my ListView to display one piece of data in one textview, I am stuck trying to display two other fields.

In my MainActivity class I used the android.R.layout.simple_list_item_1 in the Adapter constructor because I was told that the textViewResourceID argument must only contain one TextView. So to reiterate my problem: I can not figure out how to display multiple fields with an array adapter. This app currently only displays the make field. Thanks so much in advance, I only started android development about a week ago! Here is my code below:

SearchModel.java

public class SearchModel {

    public String make;
    private String model;
    private String stock;

    public SearchModel() {}

    public String getMake() {
        return this.make;
    }

    public void setMake(String make) {
        this.make = make;
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public String getStock() {
        return stock;
    }

    public void setStock(String stock) {
        this.stock = stock;
    }
}

MainActivity.java

(I omitted the irrelevant bottom section of the class after onCreate())

public class MainActivity extends AppCompatActivity {

    private DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("users").child("user1");
    private ListView mListView;
    private TextView tv_make;
    private TextView tv_model;
    private TextView tv_stock;

    private ArrayList<String> list = new ArrayList<>();
    private ArrayAdapter<String> adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);



        tv_make = (TextView) findViewById(R.id.tv_list_item_make);
        tv_model = (TextView) findViewById(R.id.tv_list_item_model);
        tv_stock = (TextView) findViewById(R.id.tv_list_item_stock);

        databaseReference.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
                String value = snapshot.child("make").getValue(String.class);
                list.add(value);

                mListView = (ListView) findViewById(R.id.lv_searches);
                adapter = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_list_item_1, list);
                mListView.setAdapter(adapter);
            }

            @Override
            public void onChildChanged(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
            }

            @Override
            public void onChildRemoved(@NonNull DataSnapshot snapshot) {
            }

            @Override
            public void onChildMoved(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
            }
        });

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }

Here is the ListView in content.main.xml:

<ListView
    android:id="@+id/lv_searches"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</ListView>

And here is the list_item.xml which is supposed to sit inside my ListView. This is where I would like to display the three String values (make, model, stock) in an instance of SearchModel.java.

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:padding="10dp">

    <TextView
        android:id="@+id/tv_list_item_make"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_list_item_model"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />

    <TextView
        android:id="@+id/tv_list_item_stock"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

This is my firebase database layout: database layout

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
austinw
  • 594
  • 1
  • 7
  • 18
  • You'll need to load your own layout XML, and pass that into the `ArrayAdapter` where you right now pass `android.R.layout.simple_list_item_1`. You can then put the values fro the database into the correct text views in the `getView` method. Also see https://stackoverflow.com/questions/28192815/how-to-add-customised-layout-to-arrayadapter – Frank van Puffelen Sep 20 '20 at 19:29
  • Hey Frank van Puffelen, thanks for the response. When you say use the `getView` method, do you mean implement my own `ArrayAdapter` and customize the `getView` method? – austinw Sep 20 '20 at 20:05
  • You could override `getView` it seems: https://developer.android.com/reference/android/widget/ArrayAdapter#getView(int,%20android.view.View,%20android.view.ViewGroup) – Frank van Puffelen Sep 20 '20 at 21:30
  • You wouldn't by any chance be able to provide a brief example of how to do that would you? I tried reading the docs and examining a few other posts through a Google search but I do not really understand most of the moving parts and how to apply it to my code. – austinw Sep 20 '20 at 22:41
  • Apologies, I don't mean to be that guy who asks someone to write their code for them.. Just been stumped on this crucial part of my application with no end in sight. Let me know if you can help, thanks @FrankvanPuffelen ! – austinw Sep 20 '20 at 22:41
  • Did you see **this** answer to the question I linked? https://stackoverflow.com/a/28193062/209103. It shows overriding `getView`. – Frank van Puffelen Sep 20 '20 at 23:27
  • Yes I did, but it did not have an approved answer and each answer was different so I wasn't sure which to try. Which answer were you referring to? – austinw Sep 20 '20 at 23:56

1 Answers1

0

after two days of being stuck I was able to answer my own question! Hopefully this will help future beginners stuck trying to display a custom view within an ArrayAdapter. Basically, I created a custom ArrayAdapter class which could hold three TextViews inside of it.

I am in no means an expert and will not be able to explain this as well as others, so instead, I will paste a link to the two video tutorials that I followed and had success with.

Android Beginner Tutorial #8 - Custom ListView Adapter For Displaying Multiple Columns https://www.youtube.com/watch?v=E6vE8fqQPTE&t=392s

Android Beginner Tutorial #9 - Custom ListView Adapter [With Loading Animation] https://www.youtube.com/watch?v=SApBLHIpH8A

Here is my updated code below:

CustomAdapter.java

public class CustomAdapter extends BaseAdapter {

    private static ArrayList<SearchModel> searchArrayList;
    private LayoutInflater mInflater;
    private Context mContext;
    private int lastPosition;

    /**
     * Holds elements in a view
     */
    static class ViewHolder {
        TextView make;
        TextView model;
        TextView stock;
    }

    public CustomAdapter(Context context, ArrayList<SearchModel> results) {
        searchArrayList = results;
        mContext = context;
        mInflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return searchArrayList.size();
    }

    @Override
    public Object getItem(int position) {
        return searchArrayList.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        String make = searchArrayList.get(position).getMake();
        String model = searchArrayList.get(position).getModel();
        String stock = searchArrayList.get(position).getStock();

        final View result;

        ViewHolder holder;

        if (convertView == null) {

            LayoutInflater inflater = LayoutInflater.from(mContext);
            convertView = inflater.inflate(R.layout.list_item, parent, false);
            holder = new ViewHolder();
            holder.make = (TextView) convertView.findViewById(R.id.tv_list_item_make);
            holder.model = (TextView) convertView.findViewById(R.id.tv_list_item_model);
            holder.stock = (TextView) convertView.findViewById(R.id.tv_list_item_stock);

            result = convertView;
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
            result = convertView;
        }

        Animation animation = AnimationUtils.loadAnimation(mContext,
                (position > lastPosition) ? R.anim.load_down_anim : R.anim.load_up_anim);
        result.startAnimation(animation);
        lastPosition = position;

        holder.make.setText(make);
        holder.model.setText(model);
        holder.stock.setText(stock);

        return convertView;
    }
}

MainActivity.java (Only the onCreate method)

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        databaseReference.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
                String make = snapshot.child("make").getValue(String.class);
                String model = snapshot.child("model").getValue(String.class);
                String stock = snapshot.child("stock").getValue(Long.class).toString();
                SearchModel searchModel = new SearchModel(make, model, stock);
                searchList.add(searchModel);

              CustomAdapter customAdapter = new CustomAdapter(getApplicationContext(), searchList);

                mListView = (ListView) findViewById(R.id.lv_searches);
                mListView.setAdapter(customAdapter);
            }

            @Override
            public void onChildChanged(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
            }

            @Override
            public void onChildRemoved(@NonNull DataSnapshot snapshot) {
            }

            @Override
            public void onChildMoved(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
            }
        });
Dharman
  • 30,962
  • 25
  • 85
  • 135
austinw
  • 594
  • 1
  • 7
  • 18