簡體   English   中英

如何從RecyclerView.Adapter中的ViewHolder調用MainActivity方法?

[英]How to call a MainActivity method from ViewHolder in RecyclerView.Adapter?

GitHub的一個簡單的應用程序項目中,我只有2個自定義Java文件:

  1. MainActivity.java包含與藍牙和UI相關的源代碼
  2. DeviceListAdapter.java包含一個AdapterViewHolder用於在RecyclerView顯示藍牙設備

應用截圖

當用戶點擊RecyclerView的藍牙設備時, MainActivity.java包含一個要調用的方法:

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

ViewHolder類(在DeviceListAdapter.java中 )中定義了單擊偵聽器:

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

我的問題:

如何從ViewHolderonClick方法調用confirmConnection(address)方法?

我繼續在2個Java文件之間移動ViewHolder類聲明,並嘗試將其放入自己的文件中 - 並且找不到正確的方法。

我是否應該向ViewHolder類添加一個字段,並且(當?)存儲對MainActivity實例的引用?

更新:

這對我LocalBroadcastReceiver ,但似乎是一種解決方法(我也在考慮使用LocalBroadcastReceiver - 這將是一個更加黑客的解決方法) -

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

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

為了保持類的解耦,我建議在適配器上定義一個接口,例如:

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

然后在適配器中為此添加一個setter:

private OnBluetoothDeviceClickedListener mBluetoothClickListener;

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

然后在內部,在ViewHolderonClick()

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

然后讓您的MainActivityAdapter的監聽Adapter傳遞:

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

這樣,您可以稍后重用適配器,而不必將其綁定到該特定行為。

對於那些正在尋找從靜態ViewHolder調用回調的人,請執行以下操作。 讓你有一個適配器:

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

然后你應該添加一個setCallback方法並從activity / fragment中調用它。 此外,您不應該使回調靜態(當您在許多類中使用相同的適配器時,它可能會導致問題)。 您應該在ViewHolder中創建一個字段。 所以:

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

制作適配器后,您可以調用它:

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

您可以將MainActivity作為Adapter的構造函數參數傳遞,並將其存儲在字段中。 或者你使用事件總線 - 有多種方法可以做到 - 我會去現場

在適配器中,創建一個接口,該接口將提供對主活動的回調

public interface MyCallback{
    void onItemClicked();
}

private MyCallback listener;

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

讓您的主要活動實現它。

public class MainActivity extends AppCompatActivity implements MyCallback

然后實現回調

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

然后只需從適配器設置回調

mDeviceListAdapter.setOnItemClickListener(this);

您可以使用Activity這樣的實例調用Activity方法,在MainActivity中編寫下面的代碼

mDeviceListAdapter = new DeviceListAdapter(MainActivity.this);

內部適配器

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

在你的onClick方法中

 _mainActivity.yourActivityMethod(address);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM