Reputation: 3121
What's the best pattern to do it. I made some workaround but I feel this is a bad pattern.
My scenario.
I've got main Activity
MainActivity.java
In this activity I'm loading Fragment with RecyclerView.
ListFragment.java
I've got also DialogFragment and ItemAdapter
From the adapter I'm showing the DialogFragment
Full adapter code
public class TypeAdapter extends RecyclerView.Adapter<CostTypeAdapter.ViewHolder> {
private static final String TAG = "TypeAdapter";
private List<CostType> mCostsType;
private Context mContext;
public CostTypeAdapter(Context context, List<CostType> coststype) {
mContext = context;
mCostsType = coststype;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
// Create a new view.
View v = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.costtype_row, viewGroup, false);
return new ViewHolder(v);
}
// BEGIN_INCLUDE(recyclerViewOnBindViewHolder)
@Override
public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
//Log.d(TAG, "Element " + position + " set.");
String Name = mCostsType.get(position).getName();
viewHolder.tvName.setText(Name);
//mView click
viewHolder.cardView.setPreventCornerOverlap(false);
viewHolder.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Dialog here
FragmentActivity activity = (FragmentActivity)(mContext);
FragmentManager fm = activity.getSupportFragmentManager();
CostType costType = new CostType();
costType.setTypeID(mCostsType.get(position).getTypeID());
costType.setName(mType.get(position).getName());
costType.setPriority(0);
CostsTypeDialogFragment alertDialog = CostsTypeDialogFragment.newInstance(costType);
alertDialog.show(fm, "cost_type");
}
});
}
// END_INCLUDE(recyclerViewOnCreateViewHolder)
public void refreshList() {
this.notifyDataSetChanged();
System.out.println("refreshList");
}
@Override
public int getItemCount() {
return mType.size();
}
/**
* Provide a reference to the type of views that you are using (custom ViewHolder)
*/
public static class ViewHolder extends RecyclerView.ViewHolder {
private final TextView tvName;
private final CardView cardView;
public ViewHolder(View v) {
super(v);
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "Element " + getPosition() + " clicked.");
}
});
tvName = (TextView) v.findViewById(R.id.tvName);
cardView = (CardView) v.findViewById(R.id.card_view);
}
}
}
DialogFragment.java I have listener for this dialog to communicate with MainActivity
onDialogCloseListener mListener;
// Container Activity must implement this interface
public interface onDialogCloseListener {
public void onDialogClose();
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (onDialogCloseListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnDialogClose listener");
}
}
private List<MyType> mType;
...
onClick from the dialog:
mListener.onDialogClose();
This dialog has some button. One of the is for example to modify/delete item on the recycle list. In this dialog I have interface onDialogCloseListener. I'm using in on my MainActivity.
MainActivity.java
public class MainActivity extends BaseActivity implements DialogFragment.onDialogCloseListener {
...
@Override
public void onDialogClose() {
RecyclerView mRecyclerView;
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
//not working
mRecyclerView.getAdapter().notifyDataSetChanged();
}
I can use the mRecyclerView from the Activity this way. I can for example make it invisible. But the notifyDataSetChanged is not working.
My workaround is to create new adapter - new sql query, new list of objects and set it again for RecyclerView. But this is probably not a good way. Because I can't for example keep scroll position.
But how to make a connection with the adapter? I want to be able to add animation for example for deleting item.
Edit:
Running
mRecyclerView.getAdapter().notifyItemRemoved(0);
in the onDialogClose works great. The list is refreshed. But when I want to do the same with
mRecyclerView.getAdapter().notifyDataSetChanged();
or
mRecyclerView.getAdapter().notifyItemChanged(0);
The list is not refreshing.
Upvotes: 3
Views: 5480
Reputation: 19796
Advice 1: don't show dialog inside adapter class, make your onClick
trigger your own listener inside Activity
e.g. onItemClicked(CostType costType)
class MyAdapter extends RecyclerView.Adapter .. {
public interface OnItemClickListener {
void onItemClicked(CostType costType);
}
private OnItemClickListener mListener;
// setter and getter for OnitemClickListener
// inside onBindViewHolder
viewHolder.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CostType costType = new CostType();
costType.setTypeID(mCostsType.get(position).getTypeID());
costType.setName(mType.get(position).getName());
costType.setPriority(0);
mListener.onItemClicked(costType);
}
}
class MyActivity extends Activity {
// inside onCreate
adapter.setOnItemClickListener(new ...);
}
Advice 2: if you need to deliver result from Fragment B to Fragment A, you don't need to use activity, instead use setTargetFragment
/ getTargetFragment
methods.
// inside MyListFragment
MyDialogFragment frag = MyDialogFragment.newInstance();
frag.setTargetFragment(this, 0);
// commit transaction
// inside MyDialogFragment to trigger listener, make sure MyDialogFragment
// implement OnDialogCloseListener interface
((MyListFragment)getTargetFragment()).onDialogClose();
Upvotes: 5