java - 滚动视图不会填充
问题描述
我有一个 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>
解决方案
完成对数据库的查询后填充 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();
推荐阅读
- android - 如何检查用户是否为我的应用阻止了互联网?
- javascript - Vite / Vue 3 : "require is not defined" when using image source as props
- node.js - Socket.io/Ws 事件无法正常工作
- excel - 对象在更改标签标题时不支持此属性或方法(错误 438)
- python - 如何从数据框中绘制多条线
- python - 如何从字典列表创建 .geojson?
- python - 使用 pip 或 pip3 安装 pyseer 包时出错
- reactjs - Gatsby-plugin-image:更新 Gatsby 客户端后缺少图像道具
- r - 为什么 tibble 在逐行比较中的执行速度比 data.frame 慢
- vb.net - VB.net中字节变量占用内存4字节