首页 > 解决方案 > 滚动视图不会填充

问题描述

我有一个 ListView 从 Firestore 获取数据,将其全部放入 UserItem 类型的 ArrayList 中,然后将其放入要显示的适配器中。

问题是由于某种原因,它拒绝显示任何东西。

我尝试了一些方法,例如实现 .notifyOnSetChanged() 但无济于事(更确定我没有正确执行它,它已在下面的代码中删除)。

我该如何解决?

UserItem(ListView 中每个项目的类):

package com.example.create4me;

public class UserItem {
    String username, timestamp, offerID, isComplete;
    public UserItem(String username, String timestamp, String offerID, String isComplete){
        this.username = username;
        this.timestamp = timestamp;
        this.offerID = offerID;
        this.isComplete = isComplete;
    }
    public String getUsername(){
        return this.username;
    }
    public String getTimestamp(){
        return this.timestamp;
    }
    public String getOfferID(){
        return this.offerID;
    }
    public String getIsComplete(){
        return this.isComplete;
    }
}

UserAdapter(ListView 的适配器):

package com.example.create4me;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import java.util.ArrayList;

public class UsersAdapter extends ArrayAdapter<UserItem> {
    public UsersAdapter(Context context, ArrayList<UserItem> users) {
        super(context, 0, users);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        UserItem user = getItem(position);
        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.userlayout, parent, false);
        }
        TextView username = (TextView) convertView.findViewById(R.id.userlayoutUsername);
        TextView timestamp = (TextView) convertView.findViewById(R.id.userlayoutTimestamp);
        TextView isComplete = (TextView) convertView.findViewById(R.id.isComplete);
        username.setText(user.getUsername());
        timestamp.setText(user.getTimestamp());
        isComplete.setText(user.getIsComplete());
        return convertView;
    }
}

负责向用户显示项目的活动:

package com.example.create4me;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.QueryDocumentSnapshot;
import com.google.firebase.firestore.QuerySnapshot;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;

import java.util.ArrayList;

public class MyCreatedOfferActivity extends AppCompatActivity {
    ImageView image, profilepic;
    TextView madeBy, title, desc, price;
    String offerid, madyByUuid;
    FirebaseAuth auth = FirebaseAuth.getInstance();
    private static final long ONE_MB = 1024 * 1024;
    FirebaseStorage storage = FirebaseStorage.getInstance();
    FirebaseFirestore db = FirebaseFirestore.getInstance();
    StorageReference ref = storage.getReference();
    FirebaseUser user;
    Button backToHome;
    String madeByUsername = "";
    ListView usersListView;
    ArrayList<UserItem> usersList;
    UsersAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_created_offer);
        getSupportActionBar().hide();
        user = auth.getCurrentUser();
        Intent data = getIntent();
        offerid = data.getExtras().getString("offerID");
        image = findViewById(R.id.OfferActivityImage);
        backToHome = findViewById(R.id.backToHomeButton);
        //profilepic = findViewById(R.id.OfferActivityProfileImage);
        title = findViewById(R.id.OfferActivityTitle);
        desc = findViewById(R.id.OfferActivityDescription);
        price = findViewById(R.id.OfferActivityPrice);
        madeBy = findViewById(R.id.OfferActivityCreatorName);

        //Over here, we create the List and also get the container for the ListView
        usersListView = findViewById(R.id.listcontainer);
        usersList = new ArrayList<UserItem>();

        //Here we get the data from Firestore
        getData();

        //Here we put the data into the adapter so it could be populated, but isn't
        adapter = new UsersAdapter(this, usersList);
        usersListView.setAdapter(adapter);
        backToHome.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MyCreatedOfferActivity.this, HomeActivity.class);
                startActivity(intent);
            }
        });
        loadData();
    }
    public void getData(){
        db.collection("ongoing")
                .whereEqualTo("creatorID", user.getUid())
                .get()
                .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                    @Override
                    public void onComplete(@NonNull Task<QuerySnapshot> task) {
                        if(task.isSuccessful()){
                            for(QueryDocumentSnapshot doc : task.getResult()){
                                usersList.add(new UserItem(doc.getData().get("buyerUsername").toString(),
                                              doc.getData().get("timestamp").toString(),
                                              doc.getData().get("offerID").toString(),
                                              doc.getData().get("isComplete").toString()));

                            }
                        }
                    }
                });
    }
    public void loadData(){
        db.collection("offers")
                .whereEqualTo("offerID", offerid.toString())
                .get()
                .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                    @Override
                    public void onComplete(@NonNull Task<QuerySnapshot> task) {
                        if(task.isSuccessful()){
                            for(QueryDocumentSnapshot doc : task.getResult()){
                                title.setText(doc.getData().get("title").toString());
                                desc.setText(doc.getData().get("description").toString());
                                price.setText(doc.getData().get("price").toString());
                                madeBy.setText(doc.getData().get("madeByName").toString());
                                madyByUuid = doc.getData().get("madeByID").toString();
                                StorageReference imageref = ref.child(doc.getData().get("image").toString());
                                imageref.getBytes(ONE_MB).addOnSuccessListener(new OnSuccessListener<byte[]>() {
                                    @Override
                                    public void onSuccess(byte[] bytes) {
                                        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                                        image.setImageBitmap(bitmap);
                                    }
                                }).addOnFailureListener(new OnFailureListener() {
                                    @Override
                                    public void onFailure(@NonNull Exception exception) {
                                        // Handle any errors
                                    }
                                });

                            }
                        }
                    }
                });
        db.collection("users")
                .whereEqualTo("uuid", madyByUuid)
                .get()
                .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                    @Override
                    public void onComplete(@NonNull Task<QuerySnapshot> task) {
                        for (QueryDocumentSnapshot doc : task.getResult()) {
                            StorageReference imageref = ref.child(doc.getData().get("profilePic").toString());
                            imageref.getBytes(ONE_MB).addOnSuccessListener(new OnSuccessListener<byte[]>() {
                                @Override
                                public void onSuccess(byte[] bytes) {
                                    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                                    profilepic.setImageBitmap(bitmap);
                                }
                            }).addOnFailureListener(new OnFailureListener() {
                                @Override
                                public void onFailure(@NonNull Exception exception) {
                                    // Handle any errors
                                }
                            });
                        }
                    }
                });
    }

}

编辑:有人要求提供 XML 文件,所以在这里(是的,它很丑,但现在可以使用):

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MyCreatedOfferActivity">
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        tools:layout_editor_absoluteX="0dp">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <Button
                android:id="@+id/backToHomeButton"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Back to home"
                android:textSize="10dp" />
            <ImageView
                android:id="@+id/OfferActivityImage"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:layout_marginTop="25dp"/>
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
            <TextView
                android:id="@+id/OfferActivityTitle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="15dp"
                android:layout_marginTop="25dp"
                android:text="Title"
                android:textColor="@color/black"
                android:textSize="30dp"
                android:layout_weight="1"/>

                <TextView
                    android:id="@+id/OfferActivityPrice"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="price"
                    android:layout_marginRight="15dp"
                    android:layout_marginTop="25dp"
                    android:textColor="@color/black"
                    android:textSize="20dp"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent" />
        </LinearLayout>
            <LinearLayout
                android:id="@+id/linearLayout2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:orientation="horizontal"
                android:layout_marginLeft="15dp">
                <ImageView
                    android:id="@+id/OfferActivityProfileImage"
                    android:layout_width="50dp"
                    android:layout_height="50dp" />
                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_gravity="center"
                    android:gravity="center"
                    android:orientation="vertical">
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="Made By:"
                        android:textColor="@color/black" />
                    <TextView
                        android:id="@+id/OfferActivityCreatorName"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="name"
                        android:textColor="@color/black"
                        android:textSize="17dp" />
                </LinearLayout>
            </LinearLayout>
            <TextView
                android:id="@+id/OfferActivityDescription"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="50dp"
                android:text="Description"
                android:textColor="@color/black"
                android:textSize="20dp" />
            <ListView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/listcontainer"
                app:layout_constraintBottom_toBottomOf="@+id/OfferActivityDescription"/>
        </LinearLayout>
    </ScrollView>

</androidx.constraintlayout.widget.ConstraintLayout>

标签: javaandroidfirebaselistview

解决方案


完成对数据库的查询后填充 userList。但是,从它在另一个线程中完成的那一刻起,主 UI 线程继续运行,因此您基本上在适配器中传递了一个空的 arrayList,因为当 userList 被填充时,您已经显示了您的 UI。为了解决这个问题,您应该将 db 请求包装在一个新线程中,一旦请求完成,移动到 UI 线程以填充布局。

这是一个非常基本的例子:

new Thread(() -> {

    //Make the request to your DB, but NOT by using any type of asynchronous method, 
    //as you are already in a separate and secure thread, so you don't need it.


    //Just and example. When you query your DB, is always better to get the most out of a single transaction, 
    //so that you don't have to query it multiple times for very little informations.
    ArrayList<UserItem> userList = getUserItemList();

    //Now that you have all the data that you need, you can move to the UIThread

    runOnUiThread(() -> {
        //I just copied your code for setting up the ScrollView
        adapter = new UsersAdapter(this, usersList);
        usersListView.setAdapter(adapter);
    });


}).start();


推荐阅读