Tecksky Android
Tecksky Android

Reputation: 133

RecyclerView getChildAt(position) returns null

E/Item Pos: 29

E/Item Rv: 15

E/Child Adapter: 30

MainActivity.java

public class MainActivity extends Activity {
RecyclerView reView;
ArrayList<RvModel> rvModels;
revAdapter adapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    reView = (RecyclerView) findViewById(R.id.reView);
    reView.setLayoutManager(new GridLayoutManager(MainActivity.this, 3));

    rvModels = new ArrayList<>();
    adapter = new revAdapter(MainActivity.this, rvModels);
    reView.setAdapter(adapter);
    prepareData();
    reView.addOnItemTouchListener(new RecyclerItemClickListener(MainActivity.this, reView, new RecyclerItemClickListener.OnItemClickListener() {
        @Override
        public void onItemClick(View view, int position) {
            Log.e("Item Pos", "" + position);
            Log.e("Item Rv", "" + reView.getChildCount());
            Log.e("Child Adapter", "" + reView.getAdapter().getItemCount());

            for (int i = 0; i < reView.getChildCount(); i++) {
                View v = reView.getChildAt(i);
                TextView txtText = (TextView) v.findViewById(R.id.txtText);

                txtText.setBackgroundColor(Color.WHITE);
                txtText.setTextColor(Color.BLUE);
            }
            TextView txtText = (TextView) view.findViewById(R.id.txtText);
            txtText.setBackgroundColor(Color.BLUE);
            txtText.setTextColor(Color.WHITE);
        }

        @Override
        public void onLongItemClick(View view, int position) {

        }
    }));
}

private void prepareData() {
    rvModels.clear();
    for (int i = 0; i < 30; i++) {
        RvModel rvModel = new RvModel();
        rvModel.setTitle("Item : " + i);
        rvModels.add(rvModel);
    }
    adapter.notifyDataSetChanged();
  }
}

revAdapter.java

public class revAdapter extends RecyclerView.Adapter<revAdapter.ViewHolder> {
Context context;
ArrayList<RvModel> rvModels;
LayoutInflater inflater;

public revAdapter(Context context, ArrayList<RvModel> rvModels) {
    this.context = context;
    this.rvModels = rvModels;
    inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

public class ViewHolder extends RecyclerView.ViewHolder {
    ImageView ivIcon;
    TextView txtText;

    public ViewHolder(View itemView) {
        super(itemView);
        ivIcon = (ImageView) itemView.findViewById(R.id.ivIcon);
        txtText = (TextView) itemView.findViewById(R.id.txtText);
    }
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = inflater.inflate(R.layout.rv_raw, parent, false);
    return new ViewHolder(itemView);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    RvModel rvModel = rvModels.get(position);
    holder.txtText.setText(rvModel.getTitle());
}

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

@Override
public int getItemViewType(int position) {
    return position;
  }
}

rv_raw.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="10dp">

    <ImageView
        android:id="@+id/ivIcon"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/txtText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Medium Text"
        android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>

Upvotes: 3

Views: 5330

Answers (1)

Mikhail Spitsin
Mikhail Spitsin

Reputation: 2608

The problem is that recyclerView like a list view have number of child views (items) depends on your screen size, not on how many items do you have. It prevents app from OOM exception. For example, if you had 1M items, then, from your logic, recycler view had to create 1M subviews and that is bad. You can read more about list view here (recycler view works in same manner)

So in your case in onClick event you don't need to find view and change it. You need to change some so-called "setting" and write notifyDataSetChanged or notifyItemChanged for more optimization.

Also I've checked your code and I'm begging you. Please, please, remove this overriden function:

@Override
public int getItemViewType(int position) {
    return position;
}

You are using same holder for all items, thus there is only one type of views in your recycler view. Overriding this method in such manner you telling to your recycler view, that every item use different layout, which decrease performance.

So, according to your question, you will have some sort of:

reView.addOnItemTouchListener(new RecyclerItemClickListener(MainActivity.this, reView, new RecyclerItemClickListener.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
        Log.e("Item Pos", "" + position);
        Log.e("Item Rv", "" + reView.getChildCount());
        Log.e("Child Adapter", "" + reView.getAdapter().getItemCount());

        if (!adapter.isChecked(position)) {
            adapter.setChecked(position);
        }
    }

    @Override
    public void onLongItemClick(View view, int position) {

    }
}));

In Adapter:

private int checkedPosition = -1;

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    RvModel rvModel = rvModels.get(position);
    holder.txtText.setText(rvModel.getTitle());

    if (position == checkedPosition) {
        txtText.setBackgroundColor(Color.BLUE);
        txtText.setTextColor(Color.WHITE);
    } else {
        txtText.setBackgroundColor(Color.WHITE);
        txtText.setTextColor(Color.BLUE);
    }
}

public boolean isChecked(int position) {
    return checkedPosition == position;
}

public void setChecked(int position) {
    int prevChecked = checkedPosition;
    checkedPosition = position;

    if (prevChecked != -1) {
        notifyItemChanged(prevChecked);
    }
    notifyItemChanged(checkedPosition)
}

Upvotes: 7

Related Questions