In a simple app project at GitHub I have only 2 custom Java-files:
- MainActivity.java contains Bluetooth- and UI-related source code
- DeviceListAdapter.java contains an
Adapter
andViewHolder
for displaying Bluetooth devices in aRecyclerView
The MainActivity.java contains a method to be called, when user taps on a Bluetooth device in the 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();
}
And in the ViewHolder
class (in the DeviceListAdapter.java) the click listener is defined:
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:
How to call confirmConnection(address)
method from ViewHolder
s onClick
method?
I keep moving ViewHolder
class declaration between the 2 Java files and also tried putting it into its own file - and just can't find the right way.
Should I maybe add a field to ViewHolder
class and (when?) store a reference to MainActivity
instance there?
UPDATE:
This works for me, but seems to be a workaround (and also I was thinking of using LocalBroadcastReceiver
- which would be an even more hackish workaround) -
@Override
public void onClick(View v) {
String address = deviceAddress.getText().toString();
try {
((MainActivity) v.getContext()).confirmConnection(address);
} catch (Exception e) {
// ignore
}
}
To keep your classes decoupled, I'd suggest defining an interface on your adapter, something like:
Then add a setter for this in your adapter:
Then internally, in your
ViewHolder
'sonClick()
:Then just have your
MainActivity
pass in a listener to theAdapter
:This way you can reuse the adapter later without it being tied to that particular behavior.
You could pass the MainActivity as a constructor-parameter for the Adapter and store it in a field. Or you use a event-bus - there are multiple ways to do it - I would go for the field
For those who are looking for invoking a callback from a static ViewHolder do the following. Let you have an adapter:
Then you should add a setCallback method and call it from activity/fragment. Also you shouldn't make a callback static (it may lead to problems when you use the same adapter in many classes). You should create a field inside the ViewHolder. So:
After you have made the adapter you can invoke it so:
You can call Activity method by using instance of Activity like this, inside MainActivity write below code
Inside Adapter
Inside your onClick method
In your adapter create an interface that will provide a callback to the main activity
have your main activity implement it
then omplement the callback
then just set the callback from the adapter