Как создать интерфейс между фрагментом и адаптером?
У меня есть фрагмент с ListView
, сказать MyListFragment
и обычай CursorAdapter
, Я устанавливаю onClickListener
в этом адаптере для кнопки в строке списка.
public class MyListAdapter extends CursorAdapter {
public interface AdapterInterface {
public void buttonPressed();
}
...
@Override
public void bindView(final View view, final Context context, final Cursor cursor) {
ViewHolder holder = (ViewHolder) view.getTag();
...
holder.button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// some action
// need to notify MyListFragment
}
});
}
}
public MyListFragment extends Fragment implements AdapterInterface {
@Override
public void buttonPressed() {
// some action
}
}
Мне нужно уведомить фрагмент, когда кнопка нажата. Как вызвать этот интерфейс?
Помогите, пожалуйста.
6 ответов
Создайте новый конструктор и переменную экземпляра:
AdapterInterface buttonListener;
public MyListAdapter (Context context, Cursor c, int flags, AdapterInterface buttonListener)
{
super(context,c,flags);
this.buttonListener = buttonListener;
}
Когда адаптер будет создан, переменной экземпляра будет дана правильная ссылка для хранения.
Чтобы позвонить на фрагмент от щелчка:
public void onClick(View v) {
buttonListener.buttonPressed();
}
При создании Adapter
Вам также придется передать свой фрагмент адаптеру. Например
MyListAdapter adapter = new MyListAdapter (getActivity(), myCursor, myFlags, this);
поскольку this
будет ссылаться на ваш фрагмент, который сейчас AdapterInterface
,
Имейте в виду, что при изменении ориентации фрагмента он, скорее всего, будет воссоздан. Если ваш адаптер не воссоздан, он может потенциально содержать ссылку на несуществующий объект, вызывая ошибки.
Использование Eventbus:
Примеры:
или же
https://github.com/greenrobot/EventBus
Использование интерфейсов:
Я понимаю текущий ответ, но мне нужен более четкий пример. Вот пример того, что я использовал с Adapter
(RecyclerView.Adapter) и Fragment
,
Создайте Callback
Интерфейс:
public interface AdapterCallback {
void onMethodCallback();
}
Проходя в Callback
/ Fragment
:
Это будет реализовывать interface
что мы имеем в нашем Adapter
, В этом примере он будет вызываться, когда пользователь нажимает на элемент в RecyclerView
,
В вашем Fragment
:
public class MyFragment extends Fragment implements AdapterCallback {
private MyAdapter mMyAdapter;
@Override
public void onMethodCallback() {
// do something
}
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.mMyAdapter = new MyAdapter(this); // this class implements callback
}
}
Использовать Callback
в вашем адаптере:
в Fragment
мы начали Adapter
и передал это в качестве аргумента конструктору. Это будет инициировать наш interface
для нашего метода обратного вызова. Вы можете видеть, что мы используем наш метод обратного вызова для кликов пользователей.
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private AdapterCallback mAdapterCallback;
public MyAdapter(AdapterCallback callback) {
this.mAdapterCallback = callback;
}
@Override
public void onBindViewHolder(final MyAdapter.ViewHolder viewHolder, final int i) {
// simple example, call interface here
// not complete
viewHolder.itemView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mAdapterCallback.onMethodCallback();
}
});
}
}
или используйте Fragment
в вашем адаптере:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private AdapterCallback mAdapterCallback;
public MyAdapter(Fragment fragment) {
try {
this.mAdapterCallback = ((AdapterCallback) fragment);
} catch (ClassCastException e) {
throw new ClassCastException("Fragment must implement AdapterCallback.");
}
}
@Override
public void onBindViewHolder(final MyAdapter.ViewHolder viewHolder, final int i) {
// simple example, call interface here
// not complete
viewHolder.itemView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
try {
mAdapterCallback.onMethodCallback();
} catch (ClassCastException exception) {
// do something
}
}
});
}
}
Выполните 2 шага ниже для получения обратного вызова от Adapter
в Fragment (or Activity)
Во-первых: в вашем Adapter
public class ListAdapter extends RecyclerView.Adapter < RecyclerListAdapter.ItemViewHolder > {
...
private ListAdapterListener mListener;
public interface ListAdapterListener { // create an interface
void onClickAtOKButton(int position); // create callback function
}
public RecyclerListAdapter(Context mContext, ArrayList < Items > listItems, ListAdapterListener mListener) { // add the interface to your adapter constructor
...
this.mListener = mListener; // receive mListener from Fragment (or Activity)
}
...
public void onBindViewHolder(final ItemViewHolder holder, final int position) {
holder.btnOK.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// use callback function in the place you want
mListener.onClickAtOKButton(position);
}
});
...
}
...
}
Второе: в вашем Fragment (or Activity)
Есть 2 способа для реализации метода обратного вызова
Способ 1
public MyListFragment extends Fragment {
...
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
...
ListAdapter adapter = new ListAdapter(getActivity(), listItems, new ListAdapter.ListAdapterListener() {
@Override
public void onClickAtOKButton(int position) {
Toast.makeText(getActivity(), "click ok button at" + position, Toast.LENGTH_SHORT).show();
}
});
...
}
}
Способ 2
public MyListFragment extends Fragment implements ListAdapter.ListAdapterListener {
...
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
ListAdapter adapter = new ListAdapter (getActivity(), listItems, this);
...
}
@Override
public void onClickAtOKButton(int position) {
Toast.makeText(getActivity(), "click ok button at" + position, Toast.LENGTH_SHORT).show();
}
}
Это очень похоже на способ взаимодействия деятельности и фрагмента. В конструкторе вашего адаптера передайте ссылку на ваш фрагмент, приведите ее к своему интерфейсу и просто вызовите yourReference.buttonPressed() в вашем методе onClick.
Сделайте конструктор так:
public MyAdapter(Activity activity,AlertMessageBoxOk alertMessageBoxOk) {
this.mActivity = activity;
mAlertMessageBoxOk = alertMessageBoxOk;
}
вызвать интерфейс из адаптера использовать любое событие
mAlertMessageBoxOk.onOkClick(5);
после этого реализуйте интерфейс AlertMessageBoxOk для своего фрагмента следующим образом:
class MyFragment extends Fragment implements AlertMessageBoxOk {
@Override
public void onOkClick(int resultCode) {
if(resultCode==5){
enter code here
}
}
}
Решение для NPE - сначала сделать так, чтобы подрядчик в вашем Фрагменте
public MyFragment MyFragment(){
return this;
}
затем инициализируйте ваш слушатель адаптер так
Lisener lisener = new MyFragment();