Butterknife is unable to bind inside my Adapter Class
Asked Answered
B

2

15

I have an Adapter that draws the layouts for my Navigation Drawer. My navigation drawer contains two inner xml files: One being the Header and the other being the Row. I draw these out in a single adapter, but when I'm trying to setText() on my header, I get failure to bind. Here is my adapter class:

public class DrawerAdapter extends RecyclerView.Adapter<DrawerAdapter.ViewHolder> {

private static final int HEADER_TYPE = 0;
private static final int ROW_TYPE = 1;
private static Context context;
private static DatabaseHelper databaseHelper;

private List<String> rows;
private List<Integer> icons;
private String driverName;

public DrawerAdapter(Context context, List<String> rows, List<Integer> icons, String driverName, DatabaseHelper databaseHelper) {
    this.icons = icons;
    this.rows = rows;
    this.context = context;
    this.driverName = driverName;
    this.databaseHelper = databaseHelper;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (viewType == HEADER_TYPE) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.drawer_header, parent, false);
        return new ViewHolder(view, viewType);

    } else if (viewType == ROW_TYPE) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.drawer_row, parent, false);
        return new ViewHolder(view, viewType);
    }
    return null;
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    if (holder.viewType == ROW_TYPE) {
        String rowText = rows.get(position - 1);
        int imageView = icons.get(position - 1);
        holder.textView.setText(rowText);
        holder.imageView.setImageResource(imageView);
    } else if (holder.viewType == HEADER_TYPE) {
        holder.driverNameText.setText(driverName);
    }
}

@Override
public int getItemCount() {
    return rows.size() + 1;
}

@Override
public int getItemViewType(int position) {
    if (position == 0)
        return HEADER_TYPE;
    return ROW_TYPE;
}

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    protected int viewType;
    @Bind(R.id.drawer_row_icon)
    ImageView imageView;
    @Bind(R.id.drawer_row_text)
    TextView textView;
    @Bind(R.id.drawer_row_id)
    FrameLayout listRow;
    @Bind(R.id.driverName)
    TextView driverNameText;

    public ViewHolder(View itemView, int viewType) {
        super(itemView);

        this.viewType = viewType;

        if (viewType == ROW_TYPE) {
            ButterKnife.bind(this, itemView);
            imageView.setOnClickListener(this);
            textView.setOnClickListener(this);
            listRow.setOnClickListener(this);
        } else {
            ButterKnife.bind(this, itemView);
        }
    }


 }

As you can see in my onCreateViewHolder method, I'm checking for both viewType's so I know which layout to draw. This in turn will create a new object for the ViewHolder class in which I "TRY" to bind the elements inside my xml depending on the viewType. Am I missing something, or doing something wrongly?

Burack answered 16/7, 2015 at 7:32 Comment(0)
B
24

I was able to solve this problem by doing the following:

First, the api docs stated the following

Be default, views are required to be present in the layout for both field and method bindings. If a view is optional add a @Nullable annotation such as the one in the support-annotations library.

@Nullable @Bind(R.id.title) TextView subtitleView;

http://jakewharton.github.io/butterknife/javadoc/

Now since I had different elements to bind coming from different xml files, I had to tag them as @Nullable because it's possible that they won't even be bindable to begin with. I changed my code to do the following :

@Nullable @Bind(R.id.drawer_row_icon)
ImageView imageView;
@Nullable @Bind(R.id.drawer_row_text)
TextView textView;
@Nullable @Bind(R.id.drawer_row_id)
FrameLayout listRow;
@Nullable @Bind(R.id.driverName)
TextView driverNameText;

While also moving the ButterKnife.bind() outside of my IF-ELSE Block.

Burack answered 16/7, 2015 at 8:32 Comment(1)
For me, there just was caches with wrong data, which got fixed by pressing cleanup button.Jezreel
L
6

You are binding twice. You cannot call bind twice on the same view. It is only doing your findviewbyid calls. Call bind once above your if block.

public ViewHolder(View itemView, int viewType) {
    super(itemView);

    this.viewType = viewType;

    ButterKnife.bind(this, itemView);
    if (viewType == ROW_TYPE) {
        imageView.setOnClickListener(this);
        textView.setOnClickListener(this);
        listRow.setOnClickListener(this);
    }
}
Lacerta answered 16/7, 2015 at 7:43 Comment(2)
I actually tried that, but it still threw me a RuntimeException saying it was unable to bind views for this adapter. Could it be that my TextView driverNameText belongs to my drawer_header xml while the other binds belong to drawer_row ?Burack
@Lacerta There is a if statement how can it bind twice? It can only execute first or second bind command according to the condition.It is absolutely not about your answer.Scandalmonger

© 2022 - 2024 — McMap. All rights reserved.