简体   繁体   中英

ItemView may not be null

I'm trying to retrieve all the checkboxes from my RecyclerView in order to uncheck them. However, this error is shown. Below are the classes that LogCat points to.

java.lang.IllegalArgumentException: itemView may not be null
             at android.support.v7.widget.RecyclerView$ViewHolder.<init>(RecyclerView.java:10314)
             at br.com.ufrn.marceloaugusto.tasklist.adapter.ProdutoAdapter$ProdutosViewHolder.<init>(ProdutoAdapter.java:0)
             at br.com.ufrn.marceloaugusto.tasklist.MainActivity.onOptionsItemSelected(MainActivity.java:93)

MainActivity.java

public class MainActivity extends BaseActivity {

    //private SQLiteDatabase banco;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setUpToolbar();

        if (savedInstanceState == null) {
            FragmentProdutos frag = new FragmentProdutos();
            getSupportFragmentManager().beginTransaction().add(R.id.container, frag).commit();
        }

        //FAB
        findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                snack(view, "Adicionar produto");
            }
        });

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.action_desmarkAll) {
            RecyclerView recycler = (RecyclerView) findViewById(R.id.recyclerView);
            ProdutoAdapter.ProdutosViewHolder holder = null;
            int id = 0;
            for (int i = 0; i < recycler.getAdapter().getItemCount(); i++) {
                holder = new ProdutoAdapter.ProdutosViewHolder(recycler.getChildAt(i)); **//Line 93**
                if (holder.checkBox.isChecked()) {
                    holder.checkBox.setChecked(false);
                }
            }
            return true;
        }
        return super.onOptionsItemSelected(item);
    }} 

ProdutoAdapter.java

public class ProdutoAdapter extends RecyclerView.Adapter<ProdutoAdapter.ProdutosViewHolder> {
private final Context context;
private final List<Produto> produtos;
//Interface para expor os eventos de toque na lista
private ProdutoOnClickListener produtoOnClickListener;
private ProdutoOnCheckListener produtoOnCheckListener;

public ProdutoAdapter(Context context, List<Produto> produtos, ProdutoOnClickListener produtoOnClickListener, ProdutoOnCheckListener produtoOnCheckListener) {
    this.context = context;
    this.produtos = produtos;
    this.produtoOnClickListener = produtoOnClickListener;
    this.produtoOnCheckListener = produtoOnCheckListener;
}

@Override
public int getItemCount() {
    return this.produtos != null ? this.produtos.size() : 0;
}

@Override
public ProdutosViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(context).inflate(R.layout.adapter_produto, parent, false);
    ProdutosViewHolder holder = new ProdutosViewHolder(view);
    return holder;
}

@Override
public void onBindViewHolder(final ProdutosViewHolder holder, final int position) {
    Produto p = produtos.get(position);
    holder.tNome.setText(p.getNome());
    //holder.tPreco.setText(String.valueOf(p.getPreco()));
    if (produtoOnClickListener != null) {
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                produtoOnClickListener.onClickProduto(view, position);
            }
        });
    }
    if (produtoOnCheckListener != null) {
        holder.checkBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                produtoOnCheckListener.onCheckProduto(view, position);
            }
        });
    }
}

public interface ProdutoOnClickListener {
    public void onClickProduto(View view, int idx);
}

public interface ProdutoOnCheckListener {
    public void onCheckProduto(View view, int position);
}

public static class ProdutosViewHolder extends RecyclerView.ViewHolder {
    public TextView tNome;
    //public TextView tPreco;
    CardView cardView;
    public CheckBox checkBox;
    public ProdutosViewHolder(View view) {
        super(view);
        tNome = (TextView) view.findViewById(R.id.nomeProduto);
        //tPreco = (TextView) view.findViewById(R.id.precoProduto);
        cardView = (CardView) view.findViewById(R.id.card_view);
        checkBox = (CheckBox) view.findViewById(R.id.checkProduto);
    }
}

}

Method getChildAt is method of ViewGroup , so recycler.getChildAt(i) will be null for you. In your case you should use produtos list, iterate over it and set its field associated to "checked" state to "false", invoke notifyDataSetChanged() method of your adapter and then onBindViewHolder() will automatically change holder's checkBox values.

So instead of

for (int i = 0; i < recycler.getAdapter().getItemCount(); i++) {
                holder = new ProdutoAdapter.ProdutosViewHolder(recycler.getChildAt(i)); **//Line 93**
                if (holder.checkBox.isChecked()) {
                    holder.checkBox.setChecked(false);
                }
            }

use this one:

for (Product product : produtos){
     product.setChecked(false);
}
recycler.getAdapter().notifyDataSetChanged();

I supppose your class Project has such method.

In a RecyclerView the item views are recycled so you dont have as many itemviews as item in your List. Instead those itemviews are recycled and shows differents elements of your productos List.

Your problem is that you are in a for loop with the length of the List but inside you are using that index to access itemviews wich has not that much elements.

Instead, you should define a variable in Producto.class and update every time that check/uncheck the CheckBox of the item. And set this variable to false when you want to uncheck all and call

adapter.notifyDataSetChanged();

UPDATE:

ProdutoAdapter.java

Define a method to access list produtos and update onBindViewHolder like this:

if (produtoOnCheckListener != null) {
    holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
            produtos.get(position).setCheckBoxState(b);
            produtoOnCheckListener.onCheckProduto(view, position);
        }
    });
}

MainActivity.class Define a ProductoAdapter variable and access to list productos to update the boolean value of each producto

[...]
ProductoAdapter productoAdapter = new ProductoAdapter();
[...]

for (int i = 0; i < productoAdapter.getItemCount(); i++) {
    productoAdapter.getListProductos().get(i).setCheckBoxState(false);      
}
productoAdapter.notifyDataSetChanged();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM