android - RecyclerView.Adapter में ViewHolder से मुख्य गतिविधि को कैसे कॉल करें?




android-recyclerview android-bluetooth (4)

GitHub में एक साधारण ऐप प्रोजेक्ट में मेरे पास केवल 2 कस्टम जावा-फाइल हैं:

  1. MainActivity.java में ब्लूटूथ- और UI- संबंधित स्रोत कोड शामिल हैं I
  2. DeviceListAdapter.java में रिसाइकिलरिव्यू में ब्लूटूथ डिवाइस प्रदर्शित करने के लिए एक Adapter और व्यूहाल्डर है

मेनएक्टिविटी.जावा में कॉल करने के लिए एक विधि है, जब उपयोगकर्ता 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();
}

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

मेरी समस्या:

ViewHolder s onClick विधि से confirmConnection(address) विधि कैसे कॉल करें?

मैं 2 जावा फाइलों के बीच ViewHolder वर्ग की घोषणा को आगे ViewHolder हूं और इसे अपनी फाइल में डालने का भी प्रयास करता हूं- और सही तरीके से नहीं मिल सकता है।

क्या मुझे संभवतः ViewHolder वर्ग में फ़ील्ड जोड़ना चाहिए और (जब?) MainActivity इंस्टेंस के संदर्भ को MainActivity संग्रहीत करते हैं?

अद्यतन करें:

यह मेरे लिए काम करता है, लेकिन एक वैकल्पिक हल लगता है (और मैं भी LocalBroadcastReceiver का उपयोग करने की सोच रहा था - जो कि एक और भी LocalBroadcastReceiver वर्कअराउंड होगा) -

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

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

अपनी कक्षाएं decoupled रखने के लिए, मैं अपने एडाप्टर पर एक अंतरफलक को परिभाषित करने का सुझाव देता हूं, जैसे कुछ:

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

उसके बाद अपने एडाप्टर में इसके लिए एक सेटर जोड़ें:

private OnBluetoothDeviceClickedListener mBluetoothClickListener;

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

फिर आंतरिक रूप से, आपके ViewHolder के onClick() :

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

उसके बाद MainActivity लिए श्रोता में आपका MainActivity पास है:

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

इस तरह आप बाद में एडेप्टर का फिर से इस्तेमाल कर सकते हैं बिना उस विशिष्ट व्यवहार से जुड़ा हो।


आप इस तरह की गतिविधि का उदाहरण का उपयोग कर गतिविधि पद्धति को कॉल कर सकते हैं, MainActivity के अंदर कोड नीचे लिखें

mDeviceListAdapter = new DeviceListAdapter(MainActivity.this);

अंदर एडाप्टर

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

आपके ऑनक्लिक विधि के अंदर

 _mainActivity.yourActivityMethod(address);

आपके एडेप्टर में एक इंटरफ़ेस बनाएं जो मुख्य गतिविधि को कॉलबैक प्रदान करेगा

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

उन लोगों के लिए जो एक स्थिर 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);
    }
}

फिर आपको एक सेट कॉलबैक विधि जोड़नी चाहिए और उसे गतिविधि / टुकड़ा से कॉल करना चाहिए। इसके अलावा आपको एक कॉलबैक स्थिर नहीं करना चाहिए (जब आप कई वर्गों में समान एडाप्टर का उपयोग करते हैं तो यह समस्याएं पैदा कर सकता है)। आपको व्यूहाल्डर के अंदर एक फ़ील्ड बनाना चाहिए। इसलिए:

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