2017-02-14 7 views
2

мне нужно вызвать метод Fragment внутри моего адаптера, но я получаю сообщение об ошибке:Вызов методы фрагмента из адаптера

ClassCastException: Main(MainActivity) cannot be cast to PlayPauseClick(Interface)

Я реализовал свой интерфейс в моем фрагменте, но я все еще получаю эту ошибку вызвать друг уже сказал мне, что mContext (мой контекст адаптера) не может быть Fragment.

Так как я могу решить эту проблему?

Мой метод Фрагмент:

private FunDapter<Product> adapter; 
private ArrayList<Product> productList; 
private ListView lvProduct; 

adapter = new FunDapter<>(getActivity(), productList, R.layout.d_layout_list_d, dict); 
lvProduct.setAdapter(adapter); 

// My method 
@Override 
public void imageButtonOnClick(View v, int position){ 
    playPause=(ImageView)v.findViewById(R.id.playPause); 
    Product m = productList.get(position); 
    playPause.setImageResource(m.getPlayPauseId()); 
    playPause.setTag(position); 
    playPause.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View v) { 
      int pos = (Integer) v.getTag(); 
      Product m =(Product) productList.get(pos); 
      if (paused) { 
      m.setPlayPauseId(R.drawable.ic_pause); 
      paused=false; 
      }else { 
      m.setPlayPauseId(R.drawable.ic_play); 
      paused = true; 
      } 
     } 

    }); 
} 

Интерфейс:

public interface PlayPauseClick{ 
void imageButtonOnClick(View v, int position); 
} 

И мой адаптер:

public class FunDapter<T> extends BaseAdapter implements Filterable { 

protected List<T> mDataItems; 
protected LongExtractor<T> idExtractor; 
protected final Context mContext; 
private final int mLayoutResource; 
private final BindDictionary<T> mBindDictionary; 
private FunDapterFilter<T> funDapterFilter; 


public FunDapter(Context context, List<T> dataItems, int layoutResource, 
       BindDictionary<T> dictionary) { 
    this(context, dataItems, layoutResource, null, dictionary); 
} 

public FunDapter(Context context, List<T> dataItems, int layoutResource, 
       LongExtractor<T> idExtractor, BindDictionary<T> dictionary) { 
    this.mContext = context; 
    this.mDataItems = dataItems; 
    this.mOrigDataItems = dataItems; 
    this.mLayoutResource = layoutResource; 
    this.idExtractor = idExtractor; 
    this.mBindDictionary = dictionary; 

} 

@Override 
public View getView(final int position, View convertView, ViewGroup parent) { 

    View v = convertView; 
    final GenericViewHolder holder; 
    if (null == v) { 
     LayoutInflater vi = 
       (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     v = vi.inflate(mLayoutResource, null); 
     holder = new GenericViewHolder(); 
     holder.root = v; 



    holder.playPause=(ImageView)v.findViewById(R.id.playPause); 
    holder.playPause.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      ((PlayPauseClick)mContext).imageButtonOnClick(v, position);   
     } 
    }); 


    return v; 
} 
+0

ли вы реализовали интерфейс в своей деятельности? – rafsanahmad007

ответ

3

Если вы хотите определить свой интерфейс на фрагменте, вам нужно явно установить его на адаптер, а не полагаться на контекст, чтобы обрабатывать его для вас, потому что Activity - это mContext, а не ваш фрагмент.

Итак, вот ваш адаптер с определенным интерфейсом. Он активируется при нажатии кнопки.

public class FunDapter<T> extends BaseAdapter implements Filterable { 

    public interface PlayPauseClick { 
    void imageButtonOnClick(View v, int position); 
    } 

    private PlayPauseClick callback; 

    ... 

    public void setPlayPauseClickListener(PlayPauseClick listener) { 
     this.callback = listener; 
    } 

    ... 

    @Override 
    public View getView(final int position, View convertView, ViewGroup parent) { 
     ... 
     holder.playPause.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 

       if (callback != null) { 
        callback.imageButtonOnClick(v, position); 
       } 

И в фрагменте, вы можете реализовать этот интерфейс (так называемый обратного вызова)

public class YourFragment extends Fragment 
    implements YourAdapter.PlayPauseClick // see here 

    // private ... adapter; 
    private List<Product> data = new ArrayList<Product>(); 

    @Override 
    public View onCreateView(...) { 
     // Set your adapter 
     // Pass the listener here 
     this.adapter = new FunDapter<Product>(...); 
     this.adapter.setPlayPauseClickListener(this); 
    } 

    @Override 
    public void imageButtonOnClick(View v, int position) { 
     // TODO: Implement this 
    } 

И вы должны удалить реализацию интерфейса на классе Activity.

+0

Можете ли вы отредактировать свой ответ на основе моего отредактированного вопроса? – Mehran

+0

Немного изменилось. 'SomeType' ==' Product', и вы используете 'BaseAdapter' вместо' ArrayAdapter', так что? Существенный ответ - то же самое. –

0

Ошибка вы видите происходит потому, что mContext является активность, а не ваш PlayPauseClick , Я предлагаю следующее:

1) При создании фрагмента дать ему метку и сохранить его в своей деятельности:

MyFragment fragment = new MyFragment(); 
    final FragmentManager fm = getFragmentManager(); 
    FragmentTransaction ft = fm.beginTransaction(); 
    View containerView = getContainerView(); 
    ft.add(containerView.getId(), fragment, tag); 

2) Внутри адаптера выполните следующие действия:

holder.playPause.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     FragmentManager fm = ((MyActivity)mContext).getFragmentManager(); 
     final MyFragment dismissedFragment = (MyFragment)fm.findFragmentByTag(((MyActivity)mContext).getMyFragmentTag()); 
     dismissedFragment.imageButtonOnClick(v, position);   
    } 
} 
+1

Как вы назвали 'getFragmentManager' из адаптера? –

+0

@ cricket_007 вы правы, getFragmentManager() нуждается в активности. Я исправил код, чтобы отразить это. –

+1

Кастинг для 'MyActivity' связывает адаптер с Activity. Наверное, не лучший дизайн –