You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义RecyclerView库中Adapter依赖findViewById的适配方案问询

Great question—this is a super common pain point when building flexible RecyclerView libraries! Let’s break down your options clearly, since you need your library to work with any layout users throw at it.

核心问题:为什么findViewById不适合你的库

The problem with relying on findViewById in your library’s Adapter is twofold:

  1. No control over user layouts: Since your library needs to support arbitrary item layouts, you have no way of knowing which view IDs will exist in the user’s XML. Hardcoding or even expecting specific IDs would break flexibility.
  2. Boilerplate and error risk: Even if you tried to let users pass in IDs, it would lead to messy, repetitive integration code for your library’s consumers, with a high chance of ID typos or mismatches.

So yes, you absolutely should replace findViewById with a more flexible approach that delegates view handling to the library’s users. Here are the best options:

View Binding is Android Jetpack’s type-safe replacement for findViewById, and it’s perfect for your use case. You can design your library’s Adapter as an abstract generic class that lets users provide their own auto-generated Binding classes.

Example Library Adapter

import androidx.recyclerview.widget.RecyclerView;
import androidx.viewbinding.ViewBinding;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import java.util.List;

public abstract class BaseFlexibleAdapter<T, VB extends ViewBinding> extends RecyclerView.Adapter<BaseFlexibleAdapter.BaseViewHolder<VB>> {

    protected List<T> mDataset;

    public BaseFlexibleAdapter(List<T> dataset) {
        this.mDataset = dataset;
    }

    @NonNull
    @Override
    public BaseViewHolder<VB> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        VB binding = createBinding(inflater, parent);
        return new BaseViewHolder<>(binding);
    }

    // Users implement this to inflate their specific ViewBinding
    protected abstract VB createBinding(LayoutInflater inflater, ViewGroup parent);

    @Override
    public void onBindViewHolder(@NonNull BaseViewHolder<VB> holder, int position) {
        bindItem(holder.binding, mDataset.get(position), position);
    }

    // Users implement this to bind data to their views via the Binding class
    protected abstract void bindItem(VB binding, T item, int position);

    @Override
    public int getItemCount() {
        return mDataset.size();
    }

    public static class BaseViewHolder<VB extends ViewBinding> extends RecyclerView.ViewHolder {
        public final VB binding;

        public BaseViewHolder(VB binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }
}

How Users Integrate It

When users use your library, they extend your abstract adapter and use their auto-generated ViewBinding class (no findViewById needed):

import com.yourlibrary.BaseFlexibleAdapter;
import com.yourapp.databinding.ItemUserBinding;
import java.util.List;

public class UserAdapter extends BaseFlexibleAdapter<User, ItemUserBinding> {

    public UserAdapter(List<User> userList) {
        super(userList);
    }

    @Override
    protected ItemUserBinding createBinding(LayoutInflater inflater, ViewGroup parent) {
        return ItemUserBinding.inflate(inflater, parent, false);
    }

    @Override
    protected void bindItem(ItemUserBinding binding, User user, int position) {
        // Type-safe access to views—no risk of wrong ID errors!
        binding.userName.setText(user.getName());
        binding.userEmail.setText(user.getEmail());
        binding.userAvatar.setImageResource(user.getAvatarResId());
    }
}

This approach is type-safe, eliminates boilerplate, and gives users full control over their layouts without your library needing to know anything about their views.

2. Use a Custom ItemBinder Interface (No Jetpack Dependency)

If you want to avoid forcing Jetpack on your users, you can define a simple interface that delegates all view creation and binding logic to the consumer. This keeps your library lightweight while still being flexible.

Example Library Code

import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;

public interface ItemBinder<T> {
    // Users create their item view here
    View createItemView(ViewGroup parent);
    // Users handle view lookup and data binding here
    void bindItem(View itemView, T data, int position);
}

public class GenericAdapter<T> extends RecyclerView.Adapter<GenericAdapter.ViewHolder> {

    private List<T> mDataset;
    private ItemBinder<T> mItemBinder;

    public GenericAdapter(List<T> dataset, ItemBinder<T> itemBinder) {
        this.mDataset = dataset;
        this.mItemBinder = itemBinder;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = mItemBinder.createItemView(parent);
        return new ViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        mItemBinder.bindItem(holder.itemView, mDataset.get(position), position);
    }

    @Override
    public int getItemCount() {
        return mDataset.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(View itemView) {
            super(itemView);
        }
    }
}

How Users Integrate It

Users implement the ItemBinder interface, handling findViewById themselves in their own code:

import com.yourlibrary.GenericAdapter;
import com.yourlibrary.ItemBinder;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import java.util.List;

List<User> userList = ...;
GenericAdapter<User> adapter = new GenericAdapter<>(userList, new ItemBinder<User>() {
    @Override
    public View createItemView(ViewGroup parent) {
        return LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_user, parent, false);
    }

    @Override
    public void bindItem(View itemView, User user, int position) {
        TextView userName = itemView.findViewById(R.id.user_name);
        TextView userEmail = itemView.findViewById(R.id.user_email);
        userName.setText(user.getName());
        userEmail.setText(user.getEmail());
    }
});

This approach is great for maintaining compatibility with older projects or users who prefer not to use Jetpack components.

3. Honorable Mention: Data Binding

If you want to go a step further, you can support Data Binding, which lets users bind data directly in their XML layouts. Your library would just pass data objects to the views, and Data Binding handles the rest. This is more powerful but requires users to enable Data Binding in their project.

Final Recommendation

Prioritize View Binding first—it’s the modern, official solution that’s type-safe and reduces boilerplate. Offer the ItemBinder interface as a fallback for users who can’t or don’t want to use Jetpack. Both approaches let your library stay completely agnostic to user layouts while eliminating the need for findViewById in your core code.

内容的提问来源于stack exchange,提问作者C. Skjerdal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:14:36