8

W a simple app project at GitHub mam tylko 2 niestandardowe java-pliki:Jak wywołać metodę MainActivity z ViewHolder w RecyclerView.Adapter?

  1. MainActivity.java i Bluetooth, zawiera kod źródłowy związanych z UI-
  2. DeviceListAdapter.java zawiera Adapter i ViewHolder do wyświetlania urządzeń Bluetooth w RecyclerView

app screenshot

The MainActivity.java zawiera metodę, która będzie wywoływana, gdy użytkownik kliknie na urządzeniu Bluetooth w 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(); 
} 

A w klasie ViewHolder (w DeviceListAdapter.java) click słuchacz jest zdefiniowana:

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(); 
    } 
    } 

My problem:

Jak wywołać confirmConnection(address) metoda z ViewHolder s onClick metody?

Wciąż przenosimy ViewHolder deklarację klasy między 2 plikami Java, a także próbowałem umieścić ją we własnym pliku - i po prostu nie można znaleźć właściwej drogi.

Czy powinienem dodać pole do klasy ViewHolder i (kiedy?) Przechowywać odwołanie do instancji MainActivity tam?

UPDATE:

Działa to dla mnie, ale wydaje się, że obejście (i też myślałem o użyciu LocalBroadcastReceiver - co byłoby jeszcze bardziej hackish obejście) -

@Override 
    public void onClick(View v) { 
     String address = deviceAddress.getText().toString(); 

     try { 
      ((MainActivity) v.getContext()).confirmConnection(address); 
     } catch (Exception e) { 
      // ignore 
     } 
    } 
+3

Twój ViewHolder zawiera View. Ten widok ma kontekst. Ten kontekst to najprawdopodobniej Twoja aktywność. Przerzuć Kontekst do MainActivity i powinieneś być w porządku. Korzystanie z interfejsów jest jednak lepszym rozwiązaniem. ((MainActivity) v.getContext()). ConfirmConnection() powinno to być. – ElDuderino

Odpowiedz

18

Aby zachować swoje zajęcia oddzielone, sugeruję zdefiniowanie interfejsu na karty, coś jak:

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

Następnie dodać setter za to w karty:

private OnBluetoothDeviceClickedListener mBluetoothClickListener; 

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

Then wewnętrznie, w swoich ViewHolder „s onClick():

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

Następnie wystarczy mieć swoją kartę MainActivity w słuchacza do Adapter:

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

ten sposób można ponownie wykorzystać adapter później bez niego przywiązanie do danego zachowania.

+2

Co się stanie, jeśli otrzymam komunikat "Nie statyczna metoda nie może być odwoływana z kontekstu statycznego"? – user3484582

+0

@ user3484582 Prawdopodobnie oznacza to, że próbujesz wywołać metodę w klasie otaczającej ze statycznej klasy wewnętrznej (np. Jeśli masz statyczną wewnętrzną klasę w swojej Aktywności i próbujesz wywołać metodę z Twojej Aktywności). – kcoppock

+2

W jaki sposób Pole niestatyczne mBluetoothClickListener może być używane w statycznej klasie ViewHolder? – MBDevelop

1

Można przekazać MainActivity jako parametr-konstruktora adaptera i zapisać go w polu. Lub użyć Event-BUS - istnieje wiele sposobów, aby to zrobić - Chciałbym pójść na polu

1

W adaptera utworzyć interfejs, który zapewni oddzwanianie do głównej działalności

public interface MyCallback{ 
    void onItemClicked(); 
} 

private MyCallback listener; 

public setOnItemClickListener(MyCallback callback){ 
    listener = callback; 
} 

mają swoją główną działalność wdrożyć

public class MainActivity extends AppCompatActivity implements MyCallback 

następnie omplement callback

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

następnie ustaw wywołanie zwrotne z adaptera

mDeviceListAdapter.setOnItemClickListener(this); 
1

można wywołać metodę Activity za pomocą instancji aktywności jak ten, wewnątrz główną działalność napisać poniżej kod

mDeviceListAdapter = new DeviceListAdapter(MainActivity.this); 

Wewnątrz zasilacza

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

Wewnątrz metody onClick

_mainActivity.yourActivityMethod(address); 
3

Dla tych, którzy szukają Aby wywołać wywołanie zwrotne ze statycznego obiektu ViewHolder, wykonaj następujące czynności. Niech masz adaptera:

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); 
    } 
} 

Następnie należy dodać metodę setCallback i wywołać ją z działalności/fragmentu. Również nie powinieneś wywoływać wywołań zwrotnych statycznych (może to prowadzić do problemów, gdy używasz tego samego adaptera w wielu klasach). Powinieneś utworzyć pole wewnątrz ViewHolder. Więc:

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()); 
        } 
       } 
      } 
     }; 
    } 
} 

Po dokonaniu adaptera można powołać się go tak:

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); 
Powiązane problemy