adek
adek

Reputation: 3121

Update RecyclerView from DialogFragment and main Activity

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

Answers (1)

Dmytro Danylyk
Dmytro Danylyk

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

Related Questions