如何在 RecyclerView 中正确更新数据以在从另一个 activity 插入或更新数据后查看更改

How to update data correctly in RecyclerView to see changes after insert or update data from another activity

我有一个问题,我正在尝试从 RecyclerView update data 加载信息 MySQLPHP 中查询。为此,通过 单击RecyclerView 中的 项目 我打开一个新的 Activity,在这个位置RecyclerView 项目的数据并更新它。在我的 DB 中,我看到了 update,但是当我 return 到带有列表的 Activity 时,它还没有改变。我知道要使它起作用,我应该使用 adapter.notifyItemChanged (position);我不明白的是如何在我的 Activity 中正确应用它。这是我的 Adapter:

public class RecyclerViewListaCartuchos extends RecyclerView.Adapter<RecyclerViewListaCartuchos.ViewHolder> {
    ArrayList<Cartuchos> mValues;
    Context mContext;

    public RecyclerViewListaCartuchos(Context context, ArrayList<Cartuchos> values) {
        mValues = values;
        mContext = context;
    }

    @NonNull
    @Override
    public RecyclerViewListaCartuchos.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.vista_diseno_cartucho, parent, false);
        return new RecyclerViewListaCartuchos.ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(RecyclerViewListaCartuchos.ViewHolder Vholder, int position) {
        Vholder.setData(mValues.get(position));

    }

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

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public CardView cardView;
        public TextView idCartucho;
        public TextView modeloColor;
        public TextView tv_fecha_mod_usuario_mod;
        public ImageView iv_cartucho_img;
        public View layout;
        Cartuchos item;

        public ViewHolder(View v) {
            super(v);
            layout = v;

            v.setOnClickListener(this);
            cardView = v.findViewById(R.id.cardView);
            idCartucho = v.findViewById(R.id.idCartucho);
            modeloColor = v.findViewById(R.id.tv_modelo_color);
            tv_fecha_mod_usuario_mod = v.findViewById(R.id.tv_fecha_mod_usuario_mod);
            iv_cartucho_img = v.findViewById(R.id.iv_cartucho_img);

            switch (mContext.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) {
                case Configuration.UI_MODE_NIGHT_YES:
                case Configuration.UI_MODE_NIGHT_NO:
                    cardView.setBackgroundColor(mContext.getResources().getColor(R.color.white));
                    idCartucho.setTextColor(mContext.getResources().getColor(R.color.black));
                    modeloColor.setTextColor(mContext.getResources().getColor(R.color.black));
                    tv_fecha_mod_usuario_mod.setTextColor(mContext.getResources().getColor(R.color.black));
                    break;
            }
        }

        public void setData(Cartuchos item) {
            this.item = item;
            String dato = item.getModelo() + " " + item.getColor();
            String idC = String.valueOf(item.getIdCartucho());
            String fec_us = "Última actualización: " + item.getFechaModificacion();
            idCartucho.setText(idC);
            modeloColor.setText(dato);
            tv_fecha_mod_usuario_mod.setText(fec_us);

            if(item.getModelo().contains("73")){
                iv_cartucho_img.setImageResource(R.drawable.sietetresn);
            }else if(item.getModelo().contains("90")){
                iv_cartucho_img.setImageResource(R.drawable.nueveceron);
            }
        }

        @Override
        public void onClick(View view) {
            int itemPosition = getLayoutPosition();
            String idC = String.valueOf(idCartucho.getText());
            String cantidad = String.valueOf(item.getCantidad());
            //String mensaje = itemPosition + " / " + idC + "/Canti:" + cantidad;
            Intent abrirEditar = new Intent(mContext, Editar.class);
            abrirEditar.putExtra("idcartucho", String.valueOf(item.getIdCartucho()));
            abrirEditar.putExtra("cantidad", String.valueOf(item.getCantidad()));
            abrirEditar.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            mContext.startActivity(abrirEditar);
            //Toast.makeText(mContext, mensaje, Toast.LENGTH_SHORT).show();
        }
    }
}

这是我的 activity:

public class MainActivity extends AppCompatActivity {
    RecyclerView recyclerView;
    ArrayList<Cartuchos> arrayList;

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

        arrayList = new ArrayList<>();

        recyclerView = findViewById(R.id.rvInicio);
        recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
        recyclerView.setHasFixedSize(true);

        listadoCartuchos();

    }

    public void listadoCartuchos() {
        StringRequest stringRequest = new StringRequest(Request.Method.POST, "url",
                response -> {
                    try {
                        JSONArray jsonArray = new JSONArray(response);
                        for (int i = 0; i < jsonArray.length(); i++) {
                            JSONObject jsonObject1 = jsonArray.getJSONObject(i);
                            int id = jsonObject1.getInt("dat");
                            String modelo = jsonObject1.getString("da");
                            String color = jsonObject1.getString("d");
                            String fec = jsonObject1.getString("data");
                            int cantidad = jsonObject1.getInt("cantidad");
                            arrayList.add(new Cartuchos(id, modelo, color, fec, cantidad));
                        }
                        RecyclerViewListaCartuchos adaptador = new RecyclerViewListaCartuchos(getApplicationContext(), arrayList);
                        recyclerView.setAdapter(adaptador);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }, Throwable::printStackTrace);
        RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
        requestQueue.add(stringRequest);
    }
}

编辑器Activity:

public class Editar extends AppCompatActivity {
    private EditText etEditarCantidad;
    private final String mensajeVacio = "No puede estar vacío ni el valor debe ser 0 (cero)";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_editar);
        String idC = getIntent().getStringExtra("idcartucho");
        int id = Integer.parseInt(idC);
        String cantidad = getIntent().getStringExtra("cantidad");

        etEditarCantidad = findViewById(R.id.etEditarCantidad);
        etEditarCantidad.setText(cantidad);
        Button btnEditar = findViewById(R.id.btnEditar);

        btnEditar.setOnClickListener(v -> {
            if(etEditarCantidad.getText().toString().length() == 0
                    || etEditarCantidad.getText().toString().equals("0")){
                Toast.makeText(Editar.this, mensajeVacio, Toast.LENGTH_SHORT).show();
            }else{
                try{
                    editarCantidad(id);
                }catch (Exception e){
                    Log.e("Error", "Editar error: " + e.getMessage());
                }
            }
        });
    }

    private void editarCantidad(int id){
        if(TextUtils.isEmpty(etEditarCantidad.getText().toString())){
            etEditarCantidad.setError("No puede estar vacío.");
            etEditarCantidad.requestFocus();
            return;
        }

        String url = "url";
        final int cant = Integer.parseInt(etEditarCantidad.getText().toString());
        StringRequest stringRequest = new StringRequest(Request.Method.POST, url, response -> {
            try {
                if (response.contains("Error")) {
                    Toast.makeText(Editar.this, "Lo sentimos, ha ocurrido un error.", Toast.LENGTH_SHORT).show();
                } else {
                    Intent data = getIntent();
                    //put necessary data if there's any and send it back
                    setResult(1, data);
                    Toast.makeText(Editar.this, "Modificado con éxito.", Toast.LENGTH_SHORT).show();
                    Editar.this.finish();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, error -> Log.e("onErrorEdit", "onErrorResponse: " + error.getMessage())){
            @Override
            protected Map<String, String> getParams(){
                Map<String, String> parametros = new HashMap<>();
                parametros.put("cantidad", String.valueOf(cant));
                parametros.put("id", String.valueOf(id));
                return parametros;
            }
        };
        RequestQueue requestQueue = Volley.newRequestQueue(Editar.this);
        requestQueue.add(stringRequest);
    }
}

你应该在你的主 activity 被触发时使用 startActivityForResult to launch this other activity, when the other activity is closed, onActivityResult,所以当这种情况发生时你知道另一个 activity 已经完成了它的工作,你应该从你的数据库

它是这样的:

  1. main activity 调用 startActivityForResult (Intent intent, int requestCode) 启动第二个 activity 的目的是包含要在第二个 activity 中使用的数据和一个请求代码,它是一个表示您要打开哪个 activity 的整数(我们稍后会用到)。
  2. second activity 提供主要 activity 的意图,完成所需的工作,就在它调用完成之前,它应该调用 setResult(int resultCode, Intent data)
    其中 result code :一个整数,表示它所做的工作是成功还是失败(它可以是您指定的任何整数,例如 1 表示成功,0 表示失败)
    数据:是一个意图,它携带了你的第二个 activity 的一些数据,为了我们这里的案例,只需发送你在第二个 activity 中收到的相同意图到第一个,因为它携带了必要的数据。
  3. 因为你开始你的第二个 activity with startActivityForResult, when it gets finished, onActivityResult (int requestCode, int resultCode, Intent data) 在 main activity 中调用 requestCode 你应该使用 if 语句来确保它是你开始的 requestCode第二个 activity 和(如果你有第三个 activity 做其他事情,当它 returns 时你会携带正确的操作流程),以及应该指示你正在做的项目的数据继续努力。
  4. 因为您有所需的数据,您可以在这里再次查询您的数据库以正确更新提到的项目,然后调用 adapter.notifyItemChanged

您的主要 activity 应该如下所示:

public class MainActivity extends AppCompatActivity {
    private final int MY_SECOND_ACTIVITY_REQUEST_CODE =2 , MY_THIRD_ACTIVITY_REQUEST_CODE =3 ;
    private final int RESULT_SUCCESS =1 , RESULT_FALIURE =0;

    ... 

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        if (requestCode == MY_SECOND_ACTIVITY_REQUEST_CODE){
            if (resultCode ==RESULT_SUCCESS)
                SecondActivityFinishedUpdateAdapterData(data);
            else somethingWrongHappenedInSecondActivity();
        }else if (requestCode == MY_THIRD_ACTIVITY_REQUEST_CODE){
            //do something else here in case if you have third activity
        }else  super.onActivityResult(requestCode, resultCode, data);
    }
    
    public void startMyActivity(Intent data)
    {
        startActivityForResult(data), MY_SECOND_ACTIVITY_REQUEST_CODE );
    }
}

你的 view holder 应该引用你的 main activity 以便能够调用 startActivityForResult (我不确定这是正确的方法但目前我想不出任何其他方法) ,所以它可能看起来像这样:

public class RecyclerViewListaCartuchos extends RecyclerView.Adapter<RecyclerViewListaCartuchos.ViewHolder> {
    ArrayList<Cartuchos> mValues;
    Context mContext;
    MainActivity myMainActivity
    public RecyclerViewListaCartuchos(MainActivity mainActivity, Context context, ArrayList<Cartuchos> values) {
        mValues = values;
        mContext = context;
        this.myMainActivity = mainActivity ;
    }
    ...
        public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public CardView cardView;
        public TextView idCartucho;
        public TextView modeloColor;
        public TextView tv_fecha_mod_usuario_mod;
        public ImageView iv_cartucho_img;
        public View layout;
        Cartuchos item;
        MainActivity myMainActivity ;
        public ViewHolder(View v, MainActivity mainActivity) {
            super(v);
            this.myMainActivity = mainActivity ;
            ...
        }

        @Override
        public void onClick(View view) {
            int itemPosition = getLayoutPosition();
            String idC = String.valueOf(idCartucho.getText());
            String cantidad = String.valueOf(item.getCantidad());
            //String mensaje = itemPosition + " / " + idC + "/Canti:" + cantidad;
            Intent abrirEditar = new Intent(mContext, Editar.class);
            abrirEditar.putExtra("idcartucho", String.valueOf(item.getIdCartucho()));
            abrirEditar.putExtra("cantidad", String.valueOf(item.getCantidad()));
            abrirEditar.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

            myMainActivity.startMyActivity(abrirEditar);

            //mContext.startActivity(abrirEditar); //commented this
            //Toast.makeText(mContext, mensaje, Toast.LENGTH_SHORT).show();
        }
    }
}

在你的第二个 activity 中,就在完成之前,你应该像这样调用 setResult :

Intent data = getIntent();
//put necessary data if there's any and send it back
setResult(1,data);
finish()

其中 intent data 应该包含必要的数据,以便在您返回时能够更新适配器(如果有的话)。 例如,您可以在您的视图持有者 onclick 中使用 holder.getAbsoulteAdapterPosition 来获取被单击的位置并将其存储在稍后将发送到主要 activity onActivityResult 的意图中。