【问题标题】:implementing interface in android LinearLayout class - RecycleViewGenericAdapter [duplicate]在android LinearLayout 类中实现接口-RecycleViewGenericAdapter [重复]
【发布时间】:2021-03-31 11:30:25
【问题描述】:

我有一个通用的RecycleView,我有不同的行类,在这个行类中我想实现一个接口,我的目标是将文本从OnQueryTextListener 传递到接口所在的活动或片段实施。

public class PlantDocHeader extends LinearLayout implements RecycleViewGenericAdapter.RecyclerViewRowHeader<PlantDocViewModel> {

    private Button buttonQuestion;
    private Button buttonPosts;
    private TextView searchTxtField;
    private ImageView imageViewExpandSearch;
    private SearchView searchView;
    private boolean expand = true;

    SearchView.OnQueryTextListener onQueryTextListener;
    private onTextChange onTextChange;

    Resources res;

    public PlantDocHeader(Context context) {
        super(context);
    }

    public PlantDocHeader(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public PlantDocHeader(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        searchTxtField = findViewById(R.id.textView_plant_doc_header_search);
        imageViewExpandSearch = findViewById(R.id.imageView_plant_doc_header_expand_button);
        searchView = findViewById(R.id.searchView_plant_doc_header);
        buttonQuestion = findViewById(R.id.button_plant_doc_header_filter_my_posts);
        buttonPosts = findViewById(R.id.button_plant_doc_header_filter_question);
    }

    @Override
    public void showData(PlantDocViewModel item) {
        res = getResources();

        buttonQuestion.setText(res.getString(R.string.question));
        buttonQuestion.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                AskQuestionFragment askQuestionFragment = new AskQuestionFragment();
                ChangeFragment(askQuestionFragment, (Activity) getContext(), false);
            }
        });


        buttonPosts.setText(res.getString(R.string.my_posts));
        buttonPosts.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                PlantDocMyPostsFragment myPostsFragment = new PlantDocMyPostsFragment();
                ChangeFragment(myPostsFragment, (Activity) getContext(), false);
            }
        });

        searchTxtField.setText(res.getString(R.string.search));
        imageViewExpandSearch.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if(expand){
                    searchView.setVisibility(VISIBLE);
                    imageViewExpandSearch.setImageResource(R.drawable.collapse);
                    expand = false;
                }else{
                    searchView.setVisibility(GONE);
                    imageViewExpandSearch.setImageResource(R.drawable.expand);
                    expand = true;
                }
            }
        });

        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                Toast.makeText(getContext(), ""+newText, Toast.LENGTH_SHORT).show();
                onTextChange.textSearch(newText);
                return true;
            }
        });
    }

    public interface onTextChange {
        void textSearch(String searchText);
    }

}

这是我遇到的错误

尝试调用接口方法'void com.gardify.android.UI.PlantDoc.PlantDocHeader$onTextChange.textSearch(java.lang.String)' 在空对象引用上

RecycleViewGenericAdapter

/**
 * @param <T> is generic parameter type provided to List, OnRecyclerViewItemClickListener and RecyclerViewRow
 * @param <V> generic type for header view Model
 * @param <E> generic type for footer view Model
 */
public class RecycleViewGenericAdapter<T, V, E> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private List<T> mDataset;
    private V mHeaderData;
    private E mFooterData;

    private static final int TYPE_HEADER = 000;
    private static final int TYPE_ITEM = 111;
    private static final int TYPE_FOOTER = 222;

    private OnItemClickListener<T> onItemClickListener;
    private OnItemClickListenerHeader<V> onItemClickListenerHeader;
    private OnItemClickListenerFooter<E> onItemClickListenerFooter;

    private int layoutId, layoutIdHeader, layoutIdFooter;

    public RecycleViewGenericAdapter(List<T> mDataset, int layoutId, V mHeaderData, int layoutIdHeader,
                                     E mFooterData, int layoutIdFooter, OnItemClickListener<T> onItemClickListener,
                                     OnItemClickListenerHeader onItemClickListenerHeader, OnItemClickListenerFooter onItemClickListenerFooter) {
        this.onItemClickListener = onItemClickListener;
        this.onItemClickListenerHeader = onItemClickListenerHeader;
        this.onItemClickListenerFooter = onItemClickListenerFooter;
        this.mDataset = mDataset;
        this.mHeaderData = mHeaderData;
        this.mFooterData = mFooterData;
        this.layoutId = layoutId;
        this.layoutIdHeader = layoutIdHeader;
        this.layoutIdFooter = layoutIdFooter;

    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder vh = null;
        if (viewType == TYPE_ITEM) {
            RecyclerViewRow<T> row = (RecyclerViewRow<T>) LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
            vh = new ItemViewHolder(row);
        }else if (viewType == TYPE_HEADER) {
            RecyclerViewRowHeader<V> rowHeader = (RecyclerViewRowHeader<V>) LayoutInflater.from(parent.getContext()).inflate(layoutIdHeader, parent, false);
            vh = new HeaderViewHolder(rowHeader);
        } else if(viewType == TYPE_FOOTER) {
            RecyclerViewRowFooter<E> footerRow = (RecyclerViewRowFooter<E>) LayoutInflater.from(parent.getContext()).inflate(layoutIdFooter, parent, false);
            vh = new FooterViewHolder(footerRow);
        }
        return vh;
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
        if (holder instanceof RecycleViewGenericAdapter.ItemViewHolder) {
            ItemViewHolder itemViewHolder = (ItemViewHolder) holder;
            itemViewHolder.onBind((mHeaderData!=null? position-1 : position), itemViewHolder);
        } else if (holder instanceof RecycleViewGenericAdapter.HeaderViewHolder) {
            HeaderViewHolder headerViewHolder = (HeaderViewHolder) holder;
            headerViewHolder.onBind(headerViewHolder);
        } else if (holder instanceof RecycleViewGenericAdapter.FooterViewHolder) {
            FooterViewHolder footerViewHolder = (FooterViewHolder) holder;
            footerViewHolder.onBind(footerViewHolder);
        }
    }

    @Override
    public int getItemCount() {
        if (mHeaderData != null && mFooterData != null) {
            return mDataset.size() + 2;
        } else if (mHeaderData != null || mFooterData != null) {
            return mDataset.size() + 1;
        }
        return mDataset.size();
    }

    private int getLastPosition() {
        return getItemCount() - 1;
    }

    private boolean isLastPosition(int position) {
        return position == getLastPosition();
    }

    @Override
    public int getItemViewType(int position) {
        if (position == 0 && mHeaderData!=null) {
            return TYPE_HEADER;
        } else if (isLastPosition(position) && mFooterData!=null) {
            return TYPE_FOOTER;
        } else {
            return TYPE_ITEM;
        }
    }

    /**
     * Item ViewHolder
     **/
    public class ItemViewHolder extends RecyclerView.ViewHolder {
        public RecyclerViewRow<T> mRow;

        public ItemViewHolder(RecyclerViewRow<T> itemView) {
            super((View) itemView);
            mRow = itemView;
        }

        private void onBind(final int position, ItemViewHolder viewHolder) {

            viewHolder.mRow.showData(mDataset.get(position));
            ((View) viewHolder.mRow).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (onItemClickListener != null) {
                        onItemClickListener.onItemClick(mDataset.get(position));
                    }
                }
            });
        }
    }

    public interface RecyclerViewRow<T> {
        void showData(T item);
    }

    public interface OnItemClickListener<T> {
        void onItemClick(T position);
    }

    public void updateList(List<T> _mDataset){
        this.mDataset= _mDataset;
        notifyDataSetChanged();
    }

    /**
     * Header ViewHolder
     **/
    public class HeaderViewHolder extends RecyclerView.ViewHolder {
        public RecyclerViewRowHeader<V> mRowHeader;

        public HeaderViewHolder(RecyclerViewRowHeader<V> itemView) {
            super((View) itemView);
            mRowHeader = itemView;
        }

        private void onBind(HeaderViewHolder viewHolder) {
            viewHolder.mRowHeader.showData(mHeaderData);
            ((View) viewHolder.mRowHeader).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (onItemClickListenerHeader != null) {
                        onItemClickListenerHeader.onItemClickHeader(mHeaderData);
                    }
                }
            });
        }
    }

    public interface RecyclerViewRowHeader<V> {
        void showData(V item);
    }

    public interface OnItemClickListenerHeader<V> {
        void onItemClickHeader(V position);
    }

    /**
     * Footer ViewHolder
     **/
    public class FooterViewHolder extends RecyclerView.ViewHolder {
        public RecyclerViewRowFooter<E> mRowFooter;

        public FooterViewHolder(RecyclerViewRowFooter<E> itemView) {
            super((View) itemView);
            mRowFooter = itemView;
        }

        private void onBind(FooterViewHolder viewHolder) {
            viewHolder.mRowFooter.showData(mFooterData);
            ((View) viewHolder.mRowFooter).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (onItemClickListenerFooter != null) {
                        onItemClickListenerFooter.onItemClickFooter(mFooterData);
                    }
                }
            });
        }
    }

    public interface RecyclerViewRowFooter<E> {
        void showData(E item);
    }

    public interface OnItemClickListenerFooter<E> {
        void onItemClickFooter(E position);
    }
}

片段中的使用

public class PlantDocFragment extends Fragment implements RecycleViewGenericAdapter.OnItemClickListener<PlantDocViewModel>, PlantDocHeader.OnTextChangeListener {

//...

    RecycleViewGenericAdapter<PlantDocViewModel, PlantDocViewModel, Nullable> adapter = new RecycleViewGenericAdapter<>(plantDocList, R.layout.recycler_view_plant_doc_row_item, plantDocHeader, R.layout.recycler_view_plant_doc_header,
                    null, 0, this, null, null);

//...

@Override
public void textSearch(String searchText) {
    Toast.makeText(getContext(), "searched text : "+searchText, Toast.LENGTH_SHORT).show();
}

我使用的通用recycleview可以在here找到

【问题讨论】:

  • 我不确定我是否理解;没有类没有构造函数。它可能是隐藏的(例如,单例),但除非你有实例,否则你不能调用实例方法。这个实例应该来自哪里?
  • 实例来自 RecycleView Adapter。我已经更新了代码。 @DaveNewton
  • 证据表明并非如此。
  • 如何调用fragment中的onTextChange?你能从这个片段中添加更多相关的代码吗?您的 implements 和您初始化 onTextChange 的方式会有所帮助
  • @PrinceAli 我在片段 PlantDocHeader.OnTextChangeListener 上实现它。我已经更新了代码。我的问题是关于初始化,不太确定在哪里初始化,因为我正在使用 LinearLayout 并且布局正在用于 recycleview。

标签: java android interface


【解决方案1】:

基本上你需要将片段引用传递给HeaderView
首先,您必须在PlantDocHeader 中有一个二传手,如下所示。接口我也去掉了,好像也没啥用。

public class PlantDocHeader<T> extends LinearLayout {
    private OnTextChangeListener onTextChangeListener;
    public void setOnTextChangeListener(OnTextChangeListener onTextChangeListener) {
        this.onTextChangeListener = onTextChangeListener;
    }
    public void setData(T data) {

    }
}

稍微改写一下您的 Adapters 构造函数,它接受大量参数,Builder 可能会有所帮助,或者您可以为可选属性创建单独的设置器。

public class RecycleViewGenericAdapter<T, V, E> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private OnItemClickListener<T> onItemClickListener;
    private OnItemClickListenerHeader<V> onItemClickListenerHeader;
    private OnItemClickListenerFooter<E> onItemClickListenerFooter;
    private PlantDocHeader.OnTextChangeListener onTextChangeListener;
    private int layoutId, layoutIdHeader, layoutIdFooter;

    public RecycleViewGenericAdapter(List<T> mDataset, int layoutId, V mHeaderData, int layoutIdHeader,
                                     E mFooterData, int layoutIdFooter) {
        this.mDataset = mDataset;
        this.mHeaderData = mHeaderData;
        this.mFooterData = mFooterData;
        this.layoutId = layoutId;
        this.layoutIdHeader = layoutIdHeader;
        this.layoutIdFooter = layoutIdFooter;
    }
}

为所有侦听器创建单独的设置器,并根据调用组件的需要设置它们。现在,当您完成设置后,您需要将onTextChangeListener 传递给标题视图。

public class HeaderViewHolder extends RecyclerView.ViewHolder {
    public RecyclerViewRowHeader<V> mRowHeader;
    public HeaderViewHolder(RecyclerViewRowHeader<V> itemView) {
        super((View) itemView);
        mRowHeader = itemView;
    }
    private void onBind(HeaderViewHolder viewHolder) {
        viewHolder.mRowHeader.setOnTextChangeListener(onTextChangeListener);
        viewHolder.mRowHeader.showData(mHeaderData);
        ((View) viewHolder.mRowHeader).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (onItemClickListenerHeader != null) {
                    onItemClickListenerHeader.onItemClickHeader(mHeaderData);
                }
            }
        });
    }
}

现在应该可以了。您也可能想考虑在侦听器之间传递位置,因为如果没有,也可以有多个标题,那么它将始终为 0。

PS- 如果您正在尝试创建一个通用适配器,您现在应该考虑创建一个抽象适配器类,因为您在构造函数中传递了太多参数,而这些参数应该在子类只是它根本不灵活。您可能想检查一些开源通用适配器以查看。

【讨论】:

  • 感谢您的回答,根据您的回答,我明白了,尽管我必须进行一些小的修改。我将更新答案的更改。 :) 再次感谢您的宝贵时间。
【解决方案2】:

当我调用textSearch() 方法时,你还没有告诉我该怎么做。

您必须在某些类中实现onTextChange 接口(声明接口/类/变量时请遵循Java naming convention),您将覆盖textSearch() 方法,然后将引用(实现的类)传递给变量@987654325 @ (您给了接口和实例变量的相同名称,因此为避免混淆,您可以给变量取另一个名称)。 然后,当您在此行中调用 textSearch() onTextChange.textSearch(newText); 时,您将获得实施。你的代码就可以工作了。

【讨论】:

  • 为了更清晰,我更新了代码。我在片段中实现接口。
【解决方案3】:

在您的适配器中创建一个公共方法:

public void setOnTextChange(onTextChange onTextChange) {
        this.onTextChange = onTextChange;
    }

在您的片段中,更改您的implements 以实现您的 接口:

implements PlantDocHeader.OnTextChange

然后设置onTextChange:

adapter.setOnTextChange(this);

【讨论】:

  • searchview 来自自定义 LinearLayout 类,我无法从 Recycleview 适配器类本身访问 onTextChange。这在我的情况下似乎不起作用。
猜你喜欢
  • 2019-07-25
  • 1970-01-01
  • 2012-03-01
  • 2012-05-17
  • 2021-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-30
相关资源
最近更新 更多