【问题标题】:How to create interface between Fragment and adapter?如何在 Fragment 和适配器之间创建接口?
【发布时间】:2013-03-04 20:58:40
【问题描述】:

我有带有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
    }
}

我需要在按下按钮时通知片段。如何调用这个接口?

请帮忙。

【问题讨论】:

    标签: java android interface


    【解决方案1】:

    创建一个新的构造函数和一个实例变量:

    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

    请记住,在 Fragment 的方向发生变化时,它很可能会被重新创建。如果您的适配器未重新创建,它可能会保留对不存在对象的引用,从而导致错误。

    【讨论】:

    • 第一部分的代码应该放在哪里?适配器接口按钮监听器;我尝试将它粘贴在我的适配器中,但这引发了错误。谢谢
    • 太棒了! +1 用于构造函数中的 AdapterInterface buttonListener。谢谢。
    【解决方案2】:

    使用事件总线:

    例子:

    https://github.com/kaushikgopal/RxJava-Android-Samples/tree/master/app/src/main/java/com/morihacky/android/rxjava/rxbus

    https://github.com/greenrobot/EventBus

    使用接口:

    我理解当前的答案,但需要一个更清晰的示例。这是我使用 Adapter(RecyclerView.Adapter) 和 Fragment 的示例。

    创建Callback接口:

    public interface AdapterCallback {
        void onMethodCallback();
    }
    

    传入Callback/Fragment

    这将实现我们在Adapter 中的interface。在这个例子中,当用户点击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
                    }
                }
            });
        }
    }
    

    【讨论】:

    • 我为 FragmentActivity 尝试了以下操作.. 但我得到了 NPE:pastebin.com/wc2ByiFz - 如果我不使用回调并且只记录值一切都很好。
    • @TheDevMan NPE 在哪里?我在我的应用程序中使用这种接口方法。
    • 是的,请阅读我的示例。你必须在你的片段中implements AdapterCallback {
    • @Skizo 谢谢!我认为这是可靠的先到先得哈。我很高兴我的回答有所帮助。
    • EventBus 需要死掉。
    【解决方案3】:

    按照以下 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)中,实现回调方法有两种方式

    方式 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();     
        }          
    }
    

    【讨论】:

    • 在方式 1 中,如果片段被销毁并且 onClickAtOkButton() 从某个线程调用,则使用匿名类实现。内存泄漏的可能性有多大
    【解决方案4】:

    这与 Activity 和 Fragment 的通信方式非常相似。在适配器的构造函数中,传递片段的引用,将其转换为接口,然后在 onClick 方法上调用 yourReference.buttonPressed()。

    【讨论】:

      【解决方案5】:

      NPE 的解决方案是首先在你的 Fragment 中像这样制作承包商

      public MyFragment MyFragment(){
              return this;
          }
      

      然后初始化你的监听器就是这样的适配器

      Lisener lisener = new MyFragment();
      

      【讨论】:

        【解决方案6】:

        制作一个这样的构造函数:

          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 
        
              }
            } 
         }
        

        【讨论】:

          猜你喜欢
          • 2020-06-06
          • 1970-01-01
          • 1970-01-01
          • 2018-02-14
          • 1970-01-01
          • 1970-01-01
          • 2016-05-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多