RecyclerView getChildAt(position) returns null

Tecksky Android
  • I implement Recyclerview in my app and I need on its item click update another listview that's why I've implemented onClick event in activity. It works fine.
  • But I also needed to High Light RecyclerView selected view and other are remain normal.
  • For that I used RecyclerView getChild method for making all view normal and then selected view Highlight.
  • I realize that it works for only Visible views of RecyclerView. But I needed to make normal all views of Recyclerview and if i used getChildAt with larger position then total visible count it returns Null Pointer exception.
    • Log that I get

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>

Michael Spitsin

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)
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Android recyclerView findViewHolderForAdapterPosition returns null

From Dev

why findviewbyposition( ) of recyclerView returns null only sometimes

From Dev

why findviewbyposition( ) of recyclerView returns null only sometimes

From Dev

RecyclerView - findViewHolderForPosition always returns null when onBindViewHolder is not called

From Dev

Passing data from RecyclerView adapter to activity returns null

From Dev

RecyclerView Null Pointer Exception

From Dev

findFirstVisibleItemPosition() of the recyclerview always returns -1

From Dev

Moq Returns method returns null

From Dev

Null RecyclerView when calling it from another RecyclerView

From Dev

findViewById returns null for WebView

From Dev

DOMXpath query returns null

From Dev

Regular Expression returns null

From Dev

getEngineByName("nashorn") returns null

From Dev

Why function returns null?

From Dev

LLVMCreateDisasm returns NULL

From Java

GetManifestResourceStream returns NULL

From Dev

Uri getHost() returns null

From Dev

Android - GsonRequest returns null

From Dev

getParseObject() returns null

From Dev

ClassLoader getResourceAsStream returns null

From Dev

Why getAttribute returns null?

From Java

getLastKnownLocation returns null

From Dev

JavaScript getElementById returns null

From Dev

FindFirst returns null

From Dev

DataGridView SelectedRows returns null

From Dev

NASM malloc returns NULL

From Dev

getSupportFragmentManager returns null

From Dev

getApplicationContext() returns null in a Service

From Dev

findLoadedClass() returns null