Como ler dados do Firebase Database e exibir vários campos em ListView com ArrayAdapter

Sep 20 2020

Passei a melhor metade do dia tentando descobrir como ler dados do meu banco de dados Firebase e exibir vários campos em um ListViewvia um ArrayAdapter. Depois de finalmente conseguir que meu ListView exiba um dado em um textview, estou preso tentando exibir dois outros campos.

Em minha MainActivityclasse, usei android.R.layout.simple_list_item_1no construtor Adapter porque me disseram que o argumento textViewResourceID deve conter apenas um TextView. Portanto, para reiterar meu problema: não consigo descobrir como exibir vários campos com um adaptador de array. Este aplicativo atualmente exibe apenas o campo make . Muito obrigado antecipadamente, só comecei o desenvolvimento do Android há cerca de uma semana! Aqui está meu código abaixo:

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

(Omiti a seção irrelevante inferior da classe depois 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();
            }
        });
    }

Aqui está o ListViewem content.main.xml:

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

E aqui está o list_item.xmlque deve ficar dentro do meu ListView. É aqui que eu gostaria de exibir os três valores de String (marca, modelo, estoque) em uma instância de 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>

Este é o layout do meu banco de dados Firebase:

Respostas

rusty1996 Sep 21 2020 at 23:37

após dois dias paralisado, consegui responder à minha própria pergunta! Esperançosamente, isso ajudará os futuros iniciantes a tentar exibir uma visualização personalizada em um ArrayAdapter. Basicamente, criei uma ArrayAdapterclasse personalizada que poderia conter três TextViewsdentro dela.

Não sou um especialista e não poderei explicar isso tão bem quanto os outros, então, em vez disso, colarei um link para os dois tutoriais em vídeo que segui e tive sucesso.

Tutorial do Android para iniciantes no. 8 - Adaptador ListView personalizado para exibição de colunas múltiplas https://www.youtube.com/watch?v=E6vE8fqQPTE&t=392s

Tutorial para iniciantes em Android nº 9 - Adaptador ListView personalizado [com animação de carregamento] https://www.youtube.com/watch?v=SApBLHIpH8A

Aqui está meu código atualizado abaixo:

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(Apenas o onCreatemétodo)

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) {
            }
        });