usar tutorial support studio recyclerview make how create como card and android android-recyclerview android-bluetooth android-viewholder

tutorial - recyclerview android 3



¿Cómo llamar a un método MainActivity desde ViewHolder en RecyclerView.Adapter? (5)

En su adaptador, cree una interfaz que proporcionará una devolución de llamada a la actividad principal

public interface MyCallback{ void onItemClicked(); } private MyCallback listener; public setOnItemClickListener(MyCallback callback){ listener = callback; }

haz que tu actividad principal lo implemente

public class MainActivity extends AppCompatActivity implements MyCallback

luego complete la devolución de llamada

@Override public void onItemClick(){ //do work }

luego simplemente configura la devolución de llamada desde el adaptador

mDeviceListAdapter.setOnItemClickListener(this);

En un proyecto de aplicación simple en GitHub tengo solo 2 archivos personalizados de Java:

  1. MainActivity.java contiene código fuente relacionado con Bluetooth y UI
  2. DeviceListAdapter.java contiene un Adapter y ViewHolder para mostrar dispositivos Bluetooth en un RecyclerView

MainActivity.java contiene un método para llamar, cuando el usuario toca un dispositivo Bluetooth en RecyclerView :

public void confirmConnection(String address) { final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("Do you want to pair to " + device + "?"); builder.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { device.createBond(); } }); builder.setNegativeButton(R.string.button_cancel, null); builder.show(); }

Y en la clase ViewHolder (en DeviceListAdapter.java ) se define el oyente click:

public class DeviceListAdapter extends RecyclerView.Adapter<DeviceListAdapter.ViewHolder> { private ArrayList<BluetoothDevice> mDevices = new ArrayList<BluetoothDevice>(); protected static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { private TextView deviceAddress; public ViewHolder(View v) { super(v); v.setOnClickListener(this); } @Override public void onClick(View v) { String address = deviceAddress.getText().toString(); Toast.makeText(v.getContext(), "How to call MainActivity.confirmConnection(address)?", Toast.LENGTH_SHORT).show(); } }

Mi problema:

¿Cómo llamar al método confirmConnection(address) método ViewHolder s onClick ?

Sigo moviendo la declaración de la clase ViewHolder entre los 2 archivos Java y también intenté ponerla en su propio archivo, y simplemente no puedo encontrar el camino correcto.

¿Debo quizás agregar un campo a la clase ViewHolder y (cuando?) Almacenar una referencia a la instancia MainActivity allí?

ACTUALIZAR:

Esto funciona para mí, pero parece ser una solución alternativa (y también estaba pensando en utilizar LocalBroadcastReceiver , lo que sería una solución aún más hackish) -

@Override public void onClick(View v) { String address = deviceAddress.getText().toString(); try { ((MainActivity) v.getContext()).confirmConnection(address); } catch (Exception e) { // ignore } }


Para mantener sus clases desacopladas, sugiero que defina una interfaz en su adaptador, algo como:

public interface OnBluetoothDeviceClickedListener { void onBluetoothDeviceClicked(String deviceAddress); }

Luego agrega un setter para esto en tu adaptador:

private OnBluetoothDeviceClickedListener mBluetoothClickListener; public void setOnBluetoothDeviceClickedListener(OnBluetoothDeviceClickedListener l) { mBluetoothClickListener = l; }

Luego internamente, en ViewHolder onClick() :

if (mBluetoothClickListener != null) { final String addresss = deviceAddress.getText().toString(); mBluetoothClickListener.onBluetoothDeviceClicked(address); }

Luego solo pase su MainActivity en un detector del Adapter :

mDeviceListAdapter.setOnBluetoothDeviceClickedListener(new OnBluetoothDeviceClickedListener() { @Override public void onBluetoothDeviceClicked(String deviceAddress) { confirmConnection(deviceAddress); } });

De esta forma, puede reutilizar el adaptador más tarde sin que esté vinculado a ese comportamiento en particular.


Puede llamar al método de Actividad usando una instancia de Actividad como esta, dentro de MainActivity escriba debajo del código

mDeviceListAdapter = new DeviceListAdapter(MainActivity.this);

Adaptador interior

private MainActivity _mainActivity; public DeviceListAdapter(MainActivity activity){ this._mainActivity=activity; }

Dentro de tu método onClick

_mainActivity.yourActivityMethod(address);


Puede pasar la actividad principal como un parámetro constructor para el adaptador y almacenarlo en un campo. O utiliza un bus de eventos, hay múltiples formas de hacerlo, yo iría por el campo


Para aquellos que buscan invocar una devolución de llamada desde un ViewHolder estático, hagan lo siguiente. Dejarte tener un adaptador:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private final int resource; private final List<Item> items; private final LayoutInflater inflater; ... private Callback callback; private static class ViewHolder extends RecyclerView.ViewHolder { ... } public interface Callback { void onImageClick(int position); void onRemoveItem(int position); } }

Luego debe agregar un método setCallback y llamarlo desde activity / fragment. Además, no debe hacer una devolución de llamada estática (puede causar problemas cuando utiliza el mismo adaptador en muchas clases). Debe crear un campo dentro de ViewHolder. Asi que:

public MyAdapter(Context context, int resource, List<Item> items, Callback callback) { super(); this.resource = resource; this.items = items; this.inflater = LayoutInflater.from(context); this.callback = callback; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { final ViewHolder viewHolder = (ViewHolder) holder; final Item item = this.items.get(position); viewHolder.caption.setText(item.caption); viewHolder.callback = callback; } // A method to set a callback from activity/fragment. public void setCallback(Callback callback) { this.callback = callback; } public static class Item { public long id; public String number; public String caption; ... } private static class ViewHolder extends RecyclerView.ViewHolder { protected final TextView caption; // A reference to an adapter''s callback. protected Callback callback; public ViewHolder(View view) { super(view); this.caption = (TextView) view.findViewById(R.id.caption); } private View.OnClickListener onClickListener = new View.OnClickListener() { @Override public void onClick(View v) { int id = v.getId(); if (id == R.id.image) { // Invoke the callback here. if (callback != null) { callback.onImageClick(getLayoutPosition()); } } } }; } }

Después de que haya hecho el adaptador, puede invocarlo así:

adapter = new MyAdapter(getActivity(), R.layout.item, new ArrayList<MyAdapter.Item>(), null); adapterListener = new MyAdapter.Callback() { @Override public void onImageClick(int position) { // Some actions. } @Override public void onRemoveItem(int position) { // Some actions. } }; adapter.setCallback(adapterListener);