我有一个活动,它有一个从Fireabase数据库获取对象列表的RecclerView.在此之前,一切都按预期进行. 在适配器上,我有一个确实删除一个对象的按钮.该按钮可同时从列表和数据库中删除对象.

当点击它时,该对象确实从这两个位置被删除.问题是它复制了RecclerView上的列表.

我如何才能纠正这种行为?

回收视图

public class ApiariosListActivity extends AppCompatActivity implements ApiarioOnList适配器.ApiarioClickListener {

    private ApiarioOnList适配器 apiarioOnList适配器;

    private ArrayList<Apiario> apiList;
    private static final int EDIT_APIARIO_REQUEST_CODE = 1;
    private static final int ADD_APIARIO_REQUEST_CODE = 2;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_apiarios_list);

        回收视图 recyclerView = findViewById(R.id.recyclerViewApiarios);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        this.apiList = new ArrayList<>();

        DatabaseReference mDatabaseQuery = FirebaseDatabase.getInstance().getReference("apiario");

        Query query = mDatabaseQuery;

        query.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                for(DataSnapshot dataSnapshot : snapshot.getChildren()){

                    Apiario apiario = dataSnapshot.getValue(Apiario.class);
                    apiList.add(apiario);
                }

                apiarioOnList适配器 = new ApiarioOnList适配器(apiList, ApiariosListActivity.this);
                recyclerView.set适配器(apiarioOnList适配器);
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {

            }
        });


        // Add Apiario button
        ImageButton btnAddApiario = findViewById(R.id.btnAddApiario);
        btnAddApiario.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(ApiariosListActivity.this, SelectDistrictActivity.class);
                startActivityForResult(intent, ADD_APIARIO_REQUEST_CODE);
            }
        });
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d("AnualDeclarationActivity", "JV: onRestart");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d("AnualDeclarationActivity", "JV: onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("AnualDeclarationActivity", "JV: onResume");
    }

    @Override
    public void onEditClick(Apiario apiario) {
        Log.d("AnualDeclarationActivity", "JV: onEditClick");
        Intent intent = new Intent(this, EditApiarioActivity.class);
        intent.putExtra("apiario", apiario);
        startActivityForResult(intent, EDIT_APIARIO_REQUEST_CODE);
    }

    @Override
    public void onDeleteClick(Apiario apiario) {
        // Implement delete functionality, e.g., show a confirmation dialog
        showDeleteConfirmationDialog(apiario);
    }

    private void showDeleteConfirmationDialog(final Apiario apiario) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Delete Apiario");
        builder.setMessage("Are you sure you want to delete this Apiario?");

        builder.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                // Perform the delete operation
                deleteApiario(apiario);
            }
        });

        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                // Cancel the delete operation
                dialogInterface.dismiss();
            }
        });

        builder.create().show();
    }

    private void deleteApiario(Apiario apiario) {
        // Remove the apiario from the list
        apiList.remove(apiario);
        // Notify the adapter of the change
        apiarioOnList适配器.notifyDataSetChanged();
        // Inform the user
        Toast.makeText(this, "Apiario deleted: " + apiario.getNomeApiario(), Toast.LENGTH_SHORT).show();
    }

    private class PostDataTask extends AsyncTask<List<Apiario>, Void, String> {

        @Override
        protected void onPreExecute() {
            Log.d("AsyncTask", "Executing onPreExecute");
        }

        @Override
        protected String doInBackground(List<Apiario>... apiariosList) {
            Log.d("AsyncTask", "Execute doInBackground");

            // Create a JSON array to hold multiple Apiario objects
            JSONArray apiarioArray = new JSONArray();

            // Convert each Apiario object to a JSON object and add it to the array
            for (Apiario apiario : apiariosList[0]) {
                try {
                    JSONObject apiarioObject = new JSONObject();
                    apiarioObject.put("nomeApiario", apiario.getNomeApiario());
                    apiarioObject.put("apiarioDeTransumancia", apiario.isApiarioDeTransumancia()); // Example value, modify as needed
                    apiarioObject.put("numColmeias", apiario.getNumColmeias());
                    apiarioObject.put("numNucleos", apiario.getNumNucleos());
                    apiarioObject.put("coordenadaX", apiario.getCoordenadaX());
                    apiarioObject.put("coordenadaY", apiario.getCoordenadaY());
                    apiarioObject.put("freguesia", apiario.getFreguesia());

                    apiarioArray.put(apiarioObject);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

            // Create the main JSON object with the array
            JSONObject mainJsonObject = new JSONObject();
            try {
                mainJsonObject.put("declarationModel", apiarioArray);
            } catch (JSONException e) {
                e.printStackTrace();
            }

            ApiCaller apiCaller = new ApiCaller();
            String apiUrl = "http://10.0.2.2:5176/api/DeclarationController/SubmitAnualDeclaration";
            String jsonInputString = mainJsonObject.toString();

            Log.d("AsyncTask", "doInBackground: Making install request with JSON: " + jsonInputString);

            String result = apiCaller.makePost(apiUrl, jsonInputString);

            if (result != null) {
                Log.d("AsyncTask", "doInBackground: Submission successful. Response: " + result);
                return result;
            } else {
                Log.d("AsyncTask", "doInBackground: Submission request failed.");
                return null;
            }
        }

        @Override
        protected void onPostExecute(String result) {
            Log.d("AsyncTask", "FP : Executing onPostExecute");
            if (result != null) {
                Toast.makeText(ApiariosListActivity.this, "Success", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(ApiariosListActivity.this, "Error", Toast.LENGTH_LONG).show();
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Log.d("TEST", "JV: onActivityResult - requestCode: " + requestCode + ", resultCode: " + resultCode);
        Log.d("TEST", "JV: ON ACTIVITY");

        if (requestCode == ADD_APIARIO_REQUEST_CODE && resultCode == RESULT_OK && data != null) {
            // Retrieve the newly added Apiario object
            Apiario newApiario = data.getParcelableExtra("newApiario");

            // Add the new Apiario to the list
            apiList.add(newApiario);

            // Notify the adapter of the change
            apiarioOnList适配器.notifyDataSetChanged();
        }

        if (requestCode == EDIT_APIARIO_REQUEST_CODE && resultCode == RESULT_OK && data != null) {
            Apiario modifiedApiario = data.getParcelableExtra("modifiedApiario");
            int position = findPositionOfApiarioInList(modifiedApiario);
            if (position != -1) {
                apiList.set(position, modifiedApiario);
                apiarioOnList适配器.notifyItemChanged(position);
            }
        }
    }

    private int findPositionOfApiarioInList(Apiario apiario) {
        for (int i = 0; i < apiList.size(); i++) {
            if (apiList.get(i).getNomeApiario().equals(apiario.getNomeApiario())) {
                return i;
            }
        }
        return -1;
    }

}

适配器

public class ApiarioOnList适配器 extends 回收视图.适配器<ApiarioOnList适配器.ApiarioViewHolder> {

    private List<Apiario> apiarios;
    private ApiarioClickListener listener;

    public interface ApiarioClickListener {
        void onEditClick(Apiario apiario);
        void onDeleteClick(Apiario apiario);
    }

    public ApiarioOnList适配器(List<Apiario> apiarios, ApiarioClickListener listener) {
        this.apiarios = apiarios;
        this.listener = listener;
    }

    public class ApiarioViewHolder extends 回收视图.ViewHolder {
        TextView textName;
        TextView textEstado;

        Button btnEdit;
        Button btnDelete;
        LinearLayout buttonContainer; // Add this line

        public ApiarioViewHolder(@NonNull View itemView) {
            super(itemView);
            textName = itemView.findViewById(R.id.textName);
            textEstado = itemView.findViewById(R.id.textEstado);

            btnEdit = itemView.findViewById(R.id.btnEdit);
            btnDelete = itemView.findViewById(R.id.btnDelete);
            buttonContainer = itemView.findViewById(R.id.buttonContainer);
        }
    }

    @NonNull
    @Override
    public ApiarioViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.apiario_item_list, parent, false);
        return new ApiarioViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull ApiarioViewHolder holder, int position) {
        final Apiario apiario = apiarios.get(position);

        holder.textName.setText("Nome: " + apiario.getNomeApiario());
        holder.textEstado.setText("Estado: " + apiario.getEstado());

        holder.btnEdit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Apiario selectedApiario = apiarios.get(holder.get适配器Position());
                Log.d("TEST", "JV: SELECTED " + selectedApiario.getNomeApiario());
                listener.onEditClick(selectedApiario);
            }
        });

        holder.btnDelete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //listener.onDeleteClick(apiario);
                int apiarioId = apiario.getID();
                Log.d("TEST", "JV: ID A REMOVER " + apiarioId);

                DatabaseReference apiarioRef = FirebaseDatabase.getInstance().getReference("apiario");

                Query query = apiarioRef.orderByChild("id").equalTo(apiarioId);

                query.addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(@NonNull DataSnapshot snapshot) {
                        for (DataSnapshot data : snapshot.getChildren()) {
                            String apiarioId = data.getKey();
                            Log.d("TEST", "JV: ENTRA NO FOR DA REMOÇAO " + apiarioId);
                            // Obtém a referência do banco de dados para o nó 'apiario' usando o ID do apiário
                            DatabaseReference apiarioToRemoveRef = apiarioRef.child(apiarioId);

                            // Remove o nó 'apiario' da base de dados
                            apiarioToRemoveRef.removeValue();

                            // Opcional: Remover o APIário da lista local
                            apiarios.remove(apiario);

                            // Notificar o adapter sobre a mudança nos dados
                            notifyDataSetChanged();


                        }
                    }

                    @Override
                    public void onCancelled(@NonNull DatabaseError error) {

                    }
                });
            }
        });

        // Check if the state is "Pendente" and add a button dynamically
        if (apiario.getEstado().equalsIgnoreCase("Pendente")) {
            Button customButton = new Button(holder.itemView.getContext());
            customButton.setText("Confirmar");
            // Add the button to the layout
            holder.buttonContainer.addView(customButton);
            // Set a click listener for the custom button
            customButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // Handle button click
                    // You can perform specific actions based on the button click
                    DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference("apiario");
                    Query query = mDatabase.orderByChild("id").equalTo(apiario.getID());

                    query.addListenerForSingleValueEvent(new ValueEventListener() {
                        @Override
                        public void onDataChange(@NonNull DataSnapshot snapshot) {

                            for (DataSnapshot data : snapshot.getChildren()){

                                String confirmID = data.getKey();
                                mDatabase.child(confirmID).child("estado").setValue("Aceite");
                                holder.buttonContainer.removeAllViews();

                                // Atualizar o estado na lista local
                                apiario.setEstado("Aceite");

                                // Notificar o adapter sobre a mudança nos dados
                                notifyDataSetChanged();

                            }


                        }

                        @Override
                        public void onCancelled(@NonNull DatabaseError error) {

                        }
                    });


                }
            });
        } else {
            // If the state is not "Pendente", make sure to remove any previously added button
            holder.buttonContainer.removeAllViews();
        }
    }

    private void openEditApiarioActivity(Context context, Apiario apiario) {
        Intent intent = new Intent(context, EditApiarioActivity.class);
        intent.putExtra("apiario", apiario);
        context.startActivity(intent);
    }

    @Override
    public int getItemCount() {
        return apiarios.size();
    }
}

推荐答案

问题就在这里:

protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_apiarios_list);

    RecyclerView recyclerView = findViewById(R.id.recyclerViewApiarios);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));

    this.apiList = new ArrayList<>(); // 👈

    DatabaseReference mDatabaseQuery = FirebaseDatabase.getInstance().getReference("apiario");

    Query query = mDatabaseQuery;

    query.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            for(DataSnapshot dataSnapshot : snapshot.getChildren()){
                Apiario apiario = dataSnapshot.getValue(Apiario.class);
                apiList.add(apiario); // 👈
            }

            apiarioOnListAdapter = new ApiarioOnListAdapter(apiList, ApiariosListActivity.this);
            recyclerView.setAdapter(apiarioOnListAdapter);
        }

由于您使用的是addValueEventListener,因此您的onDataChange将使用初始数据被"立即"调用,然后在query处的数据发生变化时再次被调用.但您只创建了一次新的、空的apiList(在onCreate中),因此每次调用onDataChange时,您都会向已填充的列表中添加项.

更好的实施方式应该是:

protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_apiarios_list);

    RecyclerView recyclerView = findViewById(R.id.recyclerViewApiarios);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));

    this.apiList = new ArrayList<>();

    DatabaseReference mDatabaseQuery = FirebaseDatabase.getInstance().getReference("apiario");

    Query query = mDatabaseQuery;

    query.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            apiList.clear(); // 👈 Clear previous results
            for(DataSnapshot dataSnapshot : snapshot.getChildren()){

                Apiario apiario = dataSnapshot.getValue(Apiario.class);
                apiList.add(apiario);
            }

            apiarioOnListAdapter = new ApiarioOnListAdapter(apiList, ApiariosListActivity.this);
            recyclerView.setAdapter(apiarioOnListAdapter);
        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {
            throw error.toException(); // 👈 Never ignore errors
        }
    });

如果您不需要onDataChange以外的apiList(我推荐这样做),您可以/可能应该将它移到onDataChange中作为局部变量.这将避免这个问题,还将防止在加载/更新数据之前try 访问数据时出现的问题.

Java相关问答推荐

使用ExecutorService时在ThreadFactory中触发自定义newThread函数

具有额外列的Hibert多对多关系在添加关系时返回NonUniqueHealthExcellent

JPackaged应用程序启动MSI调试,然后启动System. exit()

需要一个找不到的jakarta.sistence.EntityManager类型的Bean

对Java中的通配符参数的混淆

自定义批注的外推属性值

与不同顺序的组进行匹配,不重复组但分开

MySQL数据库中未应用具有Spring数据的唯一约束

SonarLint:只能有条件地调用方法(S)

支持MySQL 5.6的最新Hibernate版本

使用正则表达式从字符串中提取多个值

在settings.gradle.kts和Build.gradle.kts中使用公共变量

无法播放音频:从资源加载库GStreamer-Lite失败

具有多个模式的DateTimeForMatter的LocalDate.parse失败

何时调用密封层次 struct 的switch 中的默认情况

在Oracle中调用输出参数在索引处缺少IN或OUT参数的函数

Win32函数的JNA绑定DwmGetColorizationColor返回E_INVALIDARG错误

活泼的一次判断成语,结果中等

如何在Java上为循环数组从synchronized迁移到ReentrantLock

ChromeDriver 版本 117+ 强制另存为对话框 - 如何绕过? (selenium/Java)