Обновить RecyclerView из DialogFragment и основного действия

По какой схеме лучше всего это сделать. Я сделал обходной путь, но я чувствую, что это плохой шаблон.

Мой сценарий.

У меня есть основная активность

MainActivity.java

В этом упражнении я загружаю Fragment с помощью RecyclerView.

ListFragment.java

У меня также есть DialogFragment и ItemAdapter.

Из адаптера я показываю DialogFragment

Полный код адаптера

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 У меня есть прослушиватель этого диалога для связи с 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 из диалогового окна:

mListener.onDialogClose();

В этом диалоге есть какая-то кнопка. Одним из них является, например, изменение/удаление элемента в списке повторного использования. В этом диалоге у меня есть интерфейс onDialogCloseListener. Я использую в своей 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();
    }

Таким образом я могу использовать mRecyclerView из Activity. Я могу, например, сделать его невидимым. Но notifyDataSetChanged не работает.

Мой обходной путь - создать новый адаптер - новый SQL-запрос, новый список объектов и снова установить его для RecyclerView. Но это, наверное, не лучший способ. Потому что я не могу, например, сохранить положение прокрутки.

Но как сделать соединение с адаптером? Я хочу иметь возможность добавить анимацию, например, для удаления элемента.

Изменить:

Бег

mRecyclerView.getAdapter().notifyItemRemoved(0);

в onDialogClose отлично работает. Список обновляется. Но когда я хочу сделать то же самое с

mRecyclerView.getAdapter().notifyDataSetChanged();

or

mRecyclerView.getAdapter().notifyItemChanged(0);

Список не обновляется.


person adek    schedule 30.06.2015    source источник
comment
вам просто нужно уведомить об изменении набора данных на адаптере?   -  person Onheiron    schedule 30.06.2015
comment
@Onheiron, это был бы самый простой способ, но я читал, что с RecyclerView это не так просто. Если есть возможность использовать только notifyDataSetChanged, то да. Но мне нужно иметь возможность получить элемент из адаптера. Например, удаляя анимацию, сохраняйте положение прокрутки.   -  person adek    schedule 30.06.2015
comment
не могли бы вы опубликовать свой полный код адаптера?   -  person Onheiron    schedule 30.06.2015
comment
@Онхейрон конечно. Отредактировано.   -  person adek    schedule 30.06.2015
comment
Еще одна вещь. Это работает: mRecyclerView.getAdapter().notifyItemRemoved(0) Удаление работает отлично. Я вижу анимацию. Таким образом, проблема заключается в том, чтобы добиться чего-то подобного для редактирования записи. Например: mRecyclerView.getAdapter().notifyItemChanged(16) не обновлять список.   -  person adek    schedule 30.06.2015


Ответы (1)


Совет 1: не показывайте диалог внутри класса адаптера, сделайте так, чтобы ваш onClick запускал собственный слушатель внутри Activity, например. 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 ...);

}

Совет 2: если вам нужно доставить результат из фрагмента B во фрагмент A, вам не нужно использовать активность, вместо этого используйте методы setTargetFragment/getTargetFragment.

// 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();
person Dmytro Danylyk    schedule 30.06.2015
comment
Спасибо. Вот почему я просил хороший образец. Поэтому я должен переместить свой onClick в MainActivity (а не в активность фрагмента). Но как это сделать. Так же, как я сделал с слушателем DialogFragment? - person adek; 30.06.2015
comment
Вы получили +1 от меня. Но это, вероятно, не решает мою проблему с обновлением списка recyclerview. Где я должен добавить notifyDataSetChanged(). В MyActivity это не работает. Вероятно, перенос этого кода сюда ничего не изменит, но я попробую. - person adek; 30.06.2015
comment
@adek попробуйте сделать следующее: 1) Убедитесь, что вызывается метод onDialogClose. 2) После вызова notifyDataSetChanged вызывается метод onBindViewHolder? 3) При создании адаптера сохраняйте ссылку на адаптер как на переменную класса в действии. Например. заменить mRecyclerView.getAdapter().notifyDataSetChanged() на mAdapter.notifyDataSetChanged() - person Dmytro Danylyk; 30.06.2015
comment
Хорошо, но mAdapter находится в FragmentList. OnDialog вызывается в классе MyActivity. OnAttach подключается к основному действию. Но из основного действия я могу получить ссылку на mRecyclerView - например, работает изменение видимости mRecyclerView. Так что getAdapter() должен работать, на мой взгляд. - person adek; 30.06.2015
comment
@adek ты прав, твой код все равно должен работать. Я добавил еще один совет 2. - person Dmytro Danylyk; 30.06.2015
comment
Уверены, что шаблон с OnItemClickListener правильный. Я понятия не имею, как заставить его работать. Я не могу добиться работы адаптера.setOnItemClickListener. - person adek; 30.06.2015
comment
Давайте продолжим обсуждение в чате. - person Dmytro Danylyk; 30.06.2015