You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 06:52:04