I have RecyclerView with very complex item, multiple buttons/images/texts. To access each button/image I set my click Listeners inside my Adapter class.
But now I a
You cannot have this in any Adapter class, this is only a method inside Activity
, each class that extends Activity
will be able to Override this method but certainly not an Adapter.
Please see Overrides in java
And for onActivityResult
please see Activity#onActivityResult(int, int, Intent)
For something like a RecyclerView.Adapter
you are going to want to define an interface in your adapter and implement that interface in your Activity.
For example here is code for an application that sends a String of the Item clicked and its position to a new Activity which displays it:
MainActivity:
public class MainActivity extends AppCompatActivity implements MyAdapter.CallbackInterface {
private static final int MY_REQUEST = 1001;
private static final String [] ITEMS = {"Item 1", "Item 2", "Item 3" ,"Item 4", "Item 5", "Item 6"};
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ... Adapter setup, simple LinearLayoutManager and String [] used
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rec_view);
myAdapter = new MyAdapter(this, ITEMS);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(myAdapter);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(resultCode){
case RESULT_OK:
// ... Check for some data from the intent
if(requestCode == MY_REQUEST){
// .. lets toast again
int position = -1;
if(data != null){
position = data.getIntExtra("Position", 0);
}
if(position != -1) {
Toast.makeText(this, "Handled the result successfully at position " + position, Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "Failed to get data from intent" , Toast.LENGTH_SHORT).show();
}
}
break;
case RESULT_CANCELED:
// ... Handle this situation
break;
}
}
/**
* Interface Method which communicates to the Acitivty here from the {@link MyAdapter}
* @param position - the position
* @param text - the text to pass back
*/
@Override
public void onHandleSelection(int position, String text) {
Toast.makeText(this, "Selected item in list "+ position + " with text "+ text, Toast.LENGTH_SHORT).show();
// ... Start a new Activity here and pass the values
Intent secondActivity = new Intent(MainActivity.this, DetailActivity.class);
secondActivity.putExtra("Text",text);
secondActivity.putExtra("Position", position);
startActivityForResult(secondActivity, MY_REQUEST);
}
}
xml for MainActivity:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.divshark.recyclerviewsimpledemo.MainActivity">
<android.support.v7.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/rec_view" />
</RelativeLayout>
MyAdapter:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder>{
private CallbackInterface mCallback;
private String [] mMyItems;
private Context mContext;
public interface CallbackInterface{
/**
* Callback invoked when clicked
* @param position - the position
* @param text - the text to pass back
*/
void onHandleSelection(int position, String text);
}
public MyAdapter(Context context, String [] myItems){
mContext = context;
mMyItems = myItems;
// .. Attach the interface
try{
mCallback = (CallbackInterface) context;
}catch(ClassCastException ex){
//.. should log the error or throw and exception
Log.e("MyAdapter","Must implement the CallbackInterface in the Activity", ex);
}
}
@Override
public int getItemCount() {
return mMyItems.length;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public void onBindViewHolder(MyHolder holder, final int position) {
// Set the text for the View
holder.mTextView.setText(mMyItems[position]);
// Use your listener to pass back the data
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mCallback != null){
mCallback.onHandleSelection(position, mMyItems[position]);
}
}
});
}
@Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.list_item, parent, false);
return new MyHolder(view);
}
static class MyHolder extends RecyclerView.ViewHolder{
TextView mTextView;
public MyHolder(View itemView) {
super(itemView);
mTextView = (TextView) itemView.findViewById(R.id.tv_list_item);
}
}
}
layout for the Adapter:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="?listPreferredItemHeight">
<TextView
android:id="@+id/tv_list_item"
android:textColor="@android:color/black"
tools:text="Some Text Holder"
android:layout_marginLeft="16dp"
android:textSize="18sp"
android:layout_centerVertical="true"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
and the DetailActivity:
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.detail_activity);
TextView textView = (TextView) findViewById(R.id.tv_detail_text);
if(getIntent() != null && getIntent().getExtras() != null) {
Bundle extras = getIntent().getExtras();
String text = extras.getString("Text");
int position = extras.getInt("Position");
textView.setText(String.format("%s at position %d", text, position));
// .. For this purpose set result okay and use position as part of data when Activity finishes
// Which will in turn invoke the onActivityResult method in the calling activity
Intent resultIntent = new Intent();
resultIntent.putExtra("Position", position);
setResult(RESULT_OK, resultIntent);
}
}
}
layout for Detail activity:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:id="@+id/tv_detail_text"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
Good luck and happy coding!
Another solution is to set onActivityResult method in activity class where you initiate your RecyclerView/ListView. That works too, except for some reason I got NPE errors when I tried to pass data using intents, so work-arround for that is create static String/Int and change it's value on clicks and access. That works just fine. But the answer above is also great, and it works just as fine, perhaps even better, performance wise.