Search code examples
androidandroid-custom-viewandroid-recyclerviewroboguice

Roboguice view injection : Injecting custom view in RecyclerView Adapter fails


First of all I should mention I am using Roboguice.

I have an Activity with a RecyclerView. I am trying to inflate a custom view inside my RecyclerView's adapter. I am using Roboguice in my project.

MainActivity.java

@ContentView(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {

     @InjectView(R.id.recycler_view) RecyclerView recyclerView;
     private UserAdapter mAdapter;

     @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


        ArrayList<User> users = fetchUsers();

        mAdapter = new UserAdapter(this,users);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(mAdapter);
}

UserAdapter.java

    public class UserAdapter extends RecyclerView.Adapter<UserAdapter.CustomViewHolder> {
      @Inject CustomView.Provider myViewProvider;

        private List<User> userList;
        private Context mContext;

        public UserAdapter(Context context, List<User> userList) {
            this.userList = userList;
            this.mContext = context;
        }

        @Override
        public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
            View view = myViewProvider.get(parent);

            CustomViewHolder viewHolder = new CustomViewHolder(view);
            return viewHolder;
        }

        @Override
        public void onBindViewHolder(CustomViewHolder customViewHolder, int position) {
           ((CustomViewHolder) holder).init(userList.get(position));              

        }

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

    public class CustomViewHolder extends RecyclerView.ViewHolder {
        private final CustomView myView;

        public CustomViewHolder(View itemView) {
            super(itemView);
            myView = (CustomView) itemView;
        }



public void init(final User user) {
            myView.init(user);
        }

        }
        }

CustomView.java

@ProvidedBy(CustomView.Provider.class)
public class CustomView extends RelativeLayout {

    private View caret;
    private TextView questionText;

    public CustomView(Context context) {
        super(context);
    }

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        caret = findViewById(R.id.view_caret);
        questionText = (TextView) findViewById(R.id.view_question);

    }

    public CustomView init(final User user) {
        this.user = user;
       //Set view
        return this;
    }


    public static class Provider extends ViewProvider<CustomView> {
        @Inject
        public Provider(LayoutInflaterWithInjection<CustomView> inflater) {
            super(R.layout.module_user, inflater);
        }
    }
}

So when I run this, the app gets crashed . Logs -

java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View com.user.CustomView$Provider.get(android.view.ViewGroup)' on a null object reference
                                                                        at com.user.UserAdapter.onCreateViewHolder(UserAdapter.java:356)
                                                                        at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:5228)
                                                                        at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4453)
                                                                        at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4363)
                                                                        at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1961)
                                                                        at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1370)
                                                                        at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1333)
                                                                        at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:562)
                                                                        at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2900)
                                                                        at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3071)
                                                                        at android.view.View.layout(View.java:16678)

which I guess is because my CustomView is not initialized properly. Can somebody help ? Thanks !!


Solution

  • As far as I understand, you are injecting custom view inside your RecyclerView adapter which is UserAdapter. So if you want to inject custom view in your adapter then you must inject your adapter in your activity.

    You should make changes in your MainActivity.java -

    public class MainActivity extends AppCompatActivity {
    
     @Inject UserAdapter mAdapter;
      @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
    
    
                ArrayList<User> users = fetchUsers();
                mAdapter.setUp(this,users);
                recyclerView.setLayoutManager(new LinearLayoutManager(this));
                recyclerView.setAdapter(mAdapter);
        }
    
    
    }
    

    and your adapter should change -

    public class UserAdapter extends RecyclerView.Adapter<UserAdapter.CustomViewHolder> {
    @Inject CustomView.Provider myViewProvider;
    
            private List<User> userList;
            private Context mContext;
    
           @Inject
            public UserAdapter() {
            }
    
            public void setup(Context context, List<User> userList) {
                this.userList = userList;
                this.mContext = context;
            }
    ...
    }
    

    Hope this helps !!