使用FirestoreRecyclerAdapter加载数据致App崩溃,需传递文档ID
问题:FirestoreRecyclerAdapter导致App崩溃,需解决崩溃或替代方案传递文档ID
开发基于Firestore的租车App时,使用普通Adapter可正常获取数据,但切换到FirestoreRecyclerAdapter后App直接崩溃,且Logcat无输出无法定位问题。因需要在Adapter中获取车辆文档ID并传递到预订页面,必须使用该Adapter,尝试多种教程无效,附上相关代码请求解决。
相关代码
1. CarListAdapter代码
public class CarListAdapter extends FirestoreRecyclerAdapter<CarRentModel, CarListAdapter.RentCarViewHolder> { private Context context; public CarListAdapter(@NonNull FirestoreRecyclerOptions<CarRentModel> options) { super(options); } @Override protected void onBindViewHolder(@NonNull RentCarViewHolder holder, int position, @NonNull CarRentModel model) { holder.binding.nameCar.setText(model.getCarName()); holder.binding.carPrice.setText("PKR" + model.getCarPrice()); Glide.with(context) .load(model.getCarImage()) .into(holder.binding.imageCar); if (model.getCarStatus() != 1) { holder.binding.buttonRental.setText("Busy"); holder.binding.buttonRental.setEnabled(false); } if (model.isWithDriver()) { holder.binding.withDriver.setText("With Driver"); } else { holder.binding.withDriver.setText("Without Driver"); } } @NonNull @Override public RentCarViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_item_car_homepage, parent, false); return new RentCarViewHolder(view); } public class RentCarViewHolder extends RecyclerView.ViewHolder{ ActivityItemCarHomepageBinding binding; public RentCarViewHolder(@NonNull View itemView) { super(itemView); binding = ActivityItemCarHomepageBinding.bind(itemView); } } }
2. CarRentModel模型类代码
public class CarRentModel { private String carName, carImage, carColor, carBrand, carLicensePlates, carDescription, carSeat; private long carPrice; private int carStatus = 1; private boolean withDriver ; public CarRentModel() { } public CarRentModel(String carName, String carImage, String carColor, String carBrand, String carLicensePlates, String carDescription, String carSeat, long carPrice, int carStatus) { this.carName = carName; this.carImage = carImage; this.carColor = carColor; this.carBrand = carBrand; this.carLicensePlates = carLicensePlates; this.carDescription = carDescription; this.carSeat = carSeat; this.carPrice = carPrice; this.carStatus = carStatus; } public CarRentModel(boolean withDriver) { this.withDriver = withDriver; } public boolean isWithDriver() { return withDriver; } public void setWithDriver(boolean withDriver) { this.withDriver = withDriver; } public String getCarName() { return carName; } public void setCarName(String carName) { this.carName = carName; } public String getCarImage() { return carImage; } public void setCarImage(String carImage) { this.carImage = carImage; } public String getCarColor() { return carColor; } public void setCarColor(String carColor) { this.carColor = carColor; } public String getCarBrand() { return carBrand; } public void setCarBrand(String carBrand) { this.carBrand = carBrand; } public String getCarLicensePlates() { return carLicensePlates; } public void setCarLicensePlates(String carLicensePlates) { this.carLicensePlates = carLicensePlates; } public String getCarDescription() { return carDescription; } public void setCarDescription(String carDescription) { this.carDescription = carDescription; } public String getCarSeat() { return carSeat; } public void setCarSeat(String carSeat) { this.carSeat = carSeat; } public long getCarPrice() { return carPrice; } public void setCarPrice(long carPrice) { this.carPrice = carPrice; } public int getCarStatus() { return carStatus; } public void setCarStatus(int carStatus) { this.carStatus = carStatus; } }
3. CarlistActivity代码
public class CarlistActivity extends AppCompatActivity { ActivityCarlistBinding binding; private FirebaseFirestore database; private CollectionReference carsRef = database.collection("cars"); private CarListAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityCarlistBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); getSupportActionBar().setTitle("Rent Car"); getSupportActionBar().setDisplayHomeAsUpEnabled(true); FirebaseFirestore.setLoggingEnabled(true); setupCarList(); } private void setupCarList() { Query query = carsRef.orderBy("carName", Query.Direction.ASCENDING); FirestoreRecyclerOptions<CarRentModel> options = new FirestoreRecyclerOptions.Builder<CarRentModel>() .setQuery(query, CarRentModel.class) .build(); adapter = new CarListAdapter(options); binding.carList.setHasFixedSize(true); binding.carList.setLayoutManager(new LinearLayoutManager(this)); binding.carList.setAdapter(adapter); } @Override protected void onStart() { super.onStart(); adapter.startListening(); } @Override protected void onStop() { super.onStop(); adapter.stopListening(); } }
解决方案
一、修复崩溃问题
1. 解决Firestore实例未初始化的空指针
CarlistActivity中database未实例化就调用collection,直接导致空指针崩溃,修改如下:
private FirebaseFirestore database; private CollectionReference carsRef; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityCarlistBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); // 先初始化Firestore实例,再获取集合引用 database = FirebaseFirestore.getInstance(); carsRef = database.collection("cars"); getSupportActionBar().setTitle("Rent Car"); getSupportActionBar().setDisplayHomeAsUpEnabled(true); FirebaseFirestore.setLoggingEnabled(true); setupCarList(); }
2. 解决Adapter中Context未赋值的空指针
Adapter中声明了context但未赋值,Glide.with(context)会触发空指针,两种修复方案:
- 方案1:构造方法传入Context
修改Adapter构造方法:
public CarListAdapter(@NonNull FirestoreRecyclerOptions<CarRentModel> options, Context context) { super(options); this.context = context; }
在Activity中初始化Adapter时传入Context:
adapter = new CarListAdapter(options, this);
- 方案2:直接使用ViewHolder的View获取Context
修改onBindViewHolder中的Glide调用:
Glide.with(holder.itemView.getContext()) .load(model.getCarImage()) .into(holder.binding.imageCar);
二、获取Firestore文档ID并传递到预订页面
修复崩溃后,在onBindViewHolder中通过getSnapshots().getSnapshot(position).getId()获取文档ID,给按钮设置点击事件传递:
@Override protected void onBindViewHolder(@NonNull RentCarViewHolder holder, int position, @NonNull CarRentModel model) { // 原有绑定代码... // 获取当前车辆的Firestore文档ID String carDocId = getSnapshots().getSnapshot(position).getId(); // 给预订按钮设置点击事件,传递文档ID到预订页面 holder.binding.buttonRental.setOnClickListener(v -> { Intent bookingIntent = new Intent(holder.itemView.getContext(), BookingActivity.class); bookingIntent.putExtra("CAR_DOCUMENT_ID", carDocId); // 可额外传递车辆其他信息 bookingIntent.putExtra("CAR_NAME", model.getCarName()); bookingIntent.putExtra("CAR_PRICE", model.getCarPrice()); holder.itemView.getContext().startActivity(bookingIntent); }); }
三、替代方案:使用普通Adapter配合Firestore快照监听
如果FirestoreRecyclerAdapter仍有问题,可改用普通RecyclerView.Adapter,手动管理数据和文档ID:
// 在CarlistActivity中维护数据列表和文档ID列表 private List<CarRentModel> carList = new ArrayList<>(); private List<String> carDocIds = new ArrayList<>(); private CarListNormalAdapter adapter; // 自定义普通Adapter private void setupCarList() { // 初始化普通Adapter adapter = new CarListNormalAdapter(carList, carDocIds, this); binding.carList.setAdapter(adapter); binding.carList.setLayoutManager(new LinearLayoutManager(this)); // 监听Firestore集合变化 carsRef.orderBy("carName", Query.Direction.ASCENDING) .addSnapshotListener((value, error) -> { if (error != null) { Log.e("FirestoreError", "获取数据失败", error); return; } carList.clear(); carDocIds.clear(); for (QueryDocumentSnapshot doc : value) { CarRentModel car = doc.toObject(CarRentModel.class); carList.add(car); carDocIds.add(doc.getId()); } adapter.notifyDataSetChanged(); }); }
在普通Adapter的onBindViewHolder中,通过position从carDocIds列表获取对应文档ID,再传递到预订页面。
内容的提问来源于stack exchange,提问作者Tayyba Rani
相关产品推荐
相关产品推荐

