-2

I have a button placed inside a layout frag_contacts.xml that is intended for a fragment which is FragmentContacts.java . There is also row layout for the recyclerview which is items_contacts.xml . The button allows a user to save stuff after they are done picking recyclerview items. The app works without any errors on android Nougat . However When I run the app on android 9 it crushes giving exception java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference.
The line throwing exceptions is the one below

buttonCreateGroup.setOnClickListener(this);

the error message

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.ex_contactapp, PID: 3931
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
    at com.example.ex_contactapp.fragments.FragmentContacts.onCreateView(FragmentContacts.java:99)
    at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2439)
    at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460)
    at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
    at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
    at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:802)
    at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
    at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
    at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
    at androidx.fragment.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:2243)
    at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:654)
    at androidx.fragment.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:146)
    at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1244)
    at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1092)
    at androidx.viewpager.widget.ViewPager.onMeasure(ViewPager.java:1622)
    at android.view.View.measure(View.java:25056)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7745)
    at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1535)
    at android.widget.LinearLayout.measureVertical(LinearLayout.java:825)
    at android.widget.LinearLayout.onMeasure(LinearLayout.java:704)
    at android.view.View.measure(View.java:25056)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7745)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
    at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:143)
    at android.view.View.measure(View.java:25056)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7745)
    at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1535)
    at android.widget.LinearLayout.measureVertical(LinearLayout.java:825)
    at android.widget.LinearLayout.onMeasure(LinearLayout.java:704)
    at android.view.View.measure(View.java:25056)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7745)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
    at android.view.View.measure(View.java:25056)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7745)
    at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1535)
    at android.widget.LinearLayout.measureVertical(LinearLayout.java:825)
    at android.widget.LinearLayout.onMeasure(LinearLayout.java:704)
    at android.view.View.measure(View.java:25056)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7745)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
    at com.android.internal.policy.DecorView.onMeasure(DecorView.java:1051)
    at android.view.View.measure(View.java:25056)
    at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:3382)
    at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:2104)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2403)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1964)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8721)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:988)
    at android.view.Choreographer.doCallbacks(Choreographer.java:765)
    at android.view.Choreographer.doFrame(Choreographer.java:700)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:967)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:216)
    at android.app.ActivityThread.main(ActivityThread.java:7285)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)

layout for fragment - frag_contacts.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimaryDark">
<GridLayout
    android:layout_width="wrap_content"
    android:layout_height="100dp">

    <EditText
        android:id="@+id/group_name"
        android:layout_width="263dp"
        android:layout_height="70dp"/>
    <Button
        android:id="@+id/buttonCreateGroup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/create_group"/>
</GridLayout>
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rv_contacts"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>

Row layout -> items_contacts.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:layout_margin="10dp"
android:weightSum="10">

<Button
    android:layout_gravity="center"
    android:background="@drawable/ic_person"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="32dp"/>

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

    <TextView
        android:id="@+id/contact_name"
        android:text="name"
        android:textSize="20sp"
        android:textColor="@android:color/white"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/contact_number"
        android:text="number"
        android:textSize="16sp"
        android:textColor="@android:color/white"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>



<CheckBox
    android:id="@+id/contact_checkbox"
    android:layout_width="wrap_content"
    android:layout_gravity="center"
    android:layout_height="32dp"
    android:layout_weight="1"/>

</LinearLayout>

Recycler View Adapter class -ContactsRvAdapter.java

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

private Context mContext;
private LayoutInflater inflater;
private List<ModelContacts> mlistContacts;
private CheckedStatusListener mcheckedStatusListener;


public interface CheckedStatusListener{
    //String firstName, String lastName, String middleName, @NonNull String phoneNumber,@NonNull int groupid
    void onItemChecked(String name, String phonenumber);
    void onItemUnchecked(String name, String phonenumber);
}

public ContactsRvAdapter(Context context, List<ModelContacts> listContacts,CheckedStatusListener checkedStatusListener){

    mlistContacts = listContacts;

    mContext = context;
    mcheckedStatusListener = checkedStatusListener;
}

@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    inflater = LayoutInflater.from(mContext);

    View view = inflater.inflate(R.layout.items_contacts,parent,false);
    ViewHolder viewHolder = new ViewHolder(view);

    return viewHolder;
}

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {

    final TextView contact_name,contact_number;
    final CheckBox contact_checkbox;

    contact_name = holder.contact_name;
    contact_number = holder.contact_number;

    contact_name.setText(mlistContacts.get(position).getName());
    contact_number.setText(mlistContacts.get(position).getNumber());

    contact_checkbox = holder.contactSelectedCheckBox;


    contact_checkbox.setOnClickListener(v -> {
        if (contact_checkbox.isChecked()){

            mcheckedStatusListener.onItemChecked(mlistContacts.get(position).getName(),mlistContacts.get(position).getNumber());
        }else{
              mcheckedStatusListener.onItemUnchecked(mlistContacts.get(position).getName(),mlistContacts.get(position).getNumber());
        }
    });

}

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

public class ViewHolder extends RecyclerView.ViewHolder{

    TextView contact_name,contact_number;
    CheckBox contactSelectedCheckBox;

    public ViewHolder(View itemView){
        super(itemView);

        contact_name = itemView.findViewById(R.id.contact_name);
        contact_number = itemView.findViewById(R.id.contact_number);
        contactSelectedCheckBox = itemView.findViewById(R.id.contact_checkbox);

    }

}
}

Fragment class - FragmentContacts.java

    public class FragmentContacts extends Fragment implements ContactsRvAdapter.CheckedStatusListener, View.OnClickListener{

private  View v;

private RecyclerView recyclerView;

private List<ModelContactsBuffer> currentSelectedContacts = new ArrayList<>();

ContactsRvAdapter adapter;

private EditText editTextGroupName;

private ContactGroupViewModel contactGroupViewModel;

private ModelContactsBuffer modelContactsBuffer;

private GroupListViewModel groupListViewModel;


public FragmentContacts() {

}

@RequiresApi(api = Build.VERSION_CODES.N)
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    v = inflater.inflate(R.layout.frag_contacts,container,false);

    recyclerView = v.findViewById(R.id.rv_contacts);



    editTextGroupName = v.findViewById(R.id.group_name);
    Button buttonCreateGroup = v.findViewById(R.id.buttonCreateGroup);


    buttonCreateGroup.setOnClickListener(this);


    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());

    RecyclerView.LayoutManager layoutManager= linearLayoutManager;

    recyclerView.setLayoutManager(layoutManager);
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M &&
            ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED){

        ActivityCompat.requestPermissions(getActivity(),new String[]{Manifest.permission.READ_CONTACTS},1);
    }else {

        adapter = new ContactsRvAdapter(getContext(), getContacts(),this);
        recyclerView.setItemViewCacheSize(getContacts().size());

        recyclerView.setAdapter(adapter);
        //  adapter.notifyDataSetChanged();

    }
    contactGroupViewModel = ViewModelProviders.of(this, new ContactGroupViewModel.Factory(Objects.requireNonNull(getActivity()).getApplicationContext())).get(ContactGroupViewModel.class);
    groupListViewModel = ViewModelProviders.of(this,new GroupListViewModel.Factory(getActivity().getApplicationContext())).get(GroupListViewModel.class);




    return v;
}



@Override
public void onClick(View v) {
    Log.i("editTextGroupNamelength", String.valueOf(editTextGroupName.getText().toString().length()));
    if (editTextGroupName.getText().toString().length() > 2) {
        if(currentSelectedContacts.size() > 4){
            contactGroupViewModel.createGroup(editTextGroupName.getText().toString(),String.valueOf(currentSelectedContacts.size()));
            Integer groupId = contactGroupViewModel.readGroupId(editTextGroupName.getText().toString());

            insertGrouplist(groupId);
            //clearFields();
        }else{
            new AlertDialog.Builder(Objects.requireNonNull(this.getActivity()))
                    .setIcon(R.drawable.ic_error)
                    .setTitle("Insufficient group members")
                    .setMessage("A group should have at least 5 members")
                    .setNeutralButton("Ok",null)
                    .show();
        }
    }else{
        new AlertDialog.Builder(Objects.requireNonNull(this.getActivity()))
                .setIcon(R.drawable.ic_error)
                .setTitle("Group name is too short")
                .setMessage("A group should have atleast be 3 characters long")
                .setNeutralButton("Ok",null)
                .show();

    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

    if(requestCode == 1){
        if(grantResults[0] == PackageManager.PERMISSION_GRANTED){

            //now permission is granted call function again

             adapter = new ContactsRvAdapter(getContext(), getContacts(),this);

            recyclerView.setItemViewCacheSize(getContacts().size());
            recyclerView.setAdapter(adapter);
            adapter.notifyDataSetChanged();

        }
    }
}

private List<ModelContacts> getContacts(){

    List<ModelContacts> list = new ArrayList<>();

    try{
        String[] PROJECTION = new String[] {
                ContactsContract.Contacts.DISPLAY_NAME,
                ContactsContract.CommonDataKinds.Phone.NUMBER,
                ContactsContract.CommonDataKinds.Photo.CONTACT_ID };

        String selectionFields =  ""+ ContactsContract.Contacts.HAS_PHONE_NUMBER + " > 0 and " + ContactsContract.CommonDataKinds.Phone.TYPE +"=" + ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE;
        String[] selectionArgs = new String[]{"com.google"};

        Cursor cursor = getContext().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                PROJECTION,selectionFields,null,ContactsContract.Contacts.DISPLAY_NAME + " ASC");
        cursor.moveToFirst();

        while(cursor.moveToNext()){

            list.add(new ModelContacts(cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID)),
                    cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)),
                    cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))));
        }



    }catch (Exception e){
        Toast.makeText(getContext(),e.getMessage(),Toast.LENGTH_SHORT).show();
    }
    return list;
}

@Override
public void onItemChecked(String name, String phonenumber) {
    String firstName = " ";
    String lastName = " ";

    if(name.split("\\w+").length>1){
        lastName = name.substring(name.lastIndexOf(" ")+1);
        firstName = name.substring(0,name.lastIndexOf(' '));
    }else{
        firstName = name;
        lastName = " ";
    }

    modelContactsBuffer = new ModelContactsBuffer(firstName,lastName,phonenumber);
    currentSelectedContacts.add(modelContactsBuffer);

}

@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onItemUnchecked(String name, String phonenumber) {
    String firstName = " ";
    String lastName = " ";

    if(name.split("\\w+").length>1){
        lastName = name.substring(name.lastIndexOf(" ")+1);
        firstName = name.substring(0,name.lastIndexOf(' '));
    }else{
        firstName = name;
        lastName =  " ";
    }

        currentSelectedContacts.removeIf( currentSelectedContact -> currentSelectedContact.getPhoneNumber().equals(phonenumber));

}


public void insertGrouplist(int groupId){

    for (ModelContactsBuffer currentSelectedContact : currentSelectedContacts) {
        groupListViewModel.createGroupList(currentSelectedContact.getFirstName(), currentSelectedContact.getLastName(), " ", currentSelectedContact.getPhoneNumber(), groupId);
    }

    clearFields();

}


}
  • I commented the line throwing an exception and the app runs pretty well. Hence the problem is from buttonCreateGroup.setOnClickListener(this);
  • I have tried many solutions here in stack overflow which didnt work.
  • I have checked the id of the button and it is correct
  • I don't think it is possible initializing the onclicklistener inside ContactsRvAdapter because its not even in the row layout. It is in the other layout wwhich is intended for the fragment
  • I tried passing the normal new OnViewClicklistener to the button instead of passing the whole activity but nothong changed. Still getting an error
  • I later on moved the clicklistener call from public View onCreateView() to public void onViewCreated() but there was no change. I am stil getting the same error.
  • I tried removing @RequiresApi(api = Build.VERSION_CODES.N) Nothing changed

Kindly note I am not a professional on android. I added some things like @RequiresApi(api = Build.VERSION_CODES.N) because android lint would show an error and that was the only way I could deal with it at that time. I apprectiate any help offered on solving this

  • Your code does not match the stack trace in the log. It's difficult to debug this without them matching. – Ryan M Mar 31 '20 at 19:23
  • 2
    Does this answer your question? [What is a NullPointerException, and how do I fix it?](https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – Tyler V Mar 31 '20 at 19:44
  • @RyanM let me update – Brian M. Wachira Mar 31 '20 at 19:57
  • @RyanM kindly note I have copy pasted the stack trace exactly as it is showing on my android studio – Brian M. Wachira Mar 31 '20 at 20:03
  • Either the stack trace or the code is wrong, or you're experiencing some sort of caching issue. The code has the line in question in `onViewCreated`, but the stack trace says it's in `onCreateView`. – Ryan M Mar 31 '20 at 20:38
  • Or to put it another way: it looks to me like you're setting up `buttonCreateGroup` correctly in the code. If the issue persists, perhaps try uninstalling the app from your test device, invalidate caches/restart in Studio, and doing a clean build. – Ryan M Mar 31 '20 at 20:43
  • Just tried this. Still experiencing the same problem – Brian M. Wachira Mar 31 '20 at 21:42
  • What if android 9 has a bug? Coz when I run this app on android 7 I dont encounter this problem at all – Brian M. Wachira Mar 31 '20 at 21:50
  • Now your code in the question doesn't have _any_ calls on `buttonCreateGroup`, and the only `setOnClickListener` is in the `Adapter`. There's zero chance this is the code that threw this exception. – Ryan M Apr 01 '20 at 01:26
  • Apologies I have edited the code sample and added the button onclicklistener call. However I found the solution to the problem and I typed it down on an answer (just look at the answers). I have seen that the question has been marked as duplicate. In consideration of the solution I found , should I delete the question? – Brian M. Wachira Apr 01 '20 at 11:40

2 Answers2

0

You probably get this error(null object reference) because you didn't define the button. You have to define like this:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.frag_contacts, container, false);
    Button buttonCreateGroup = view.findViewById(R.id.buttonCreateGroup);
    buttonCreateGroup.setOnClickListener(this);
    return view;
}

Or this func:

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle    savedInstanceState) {
   super.onViewCreated(view, savedInstanceState);
   Button buttonCreateGroup = view.findViewById(R.id.buttonCreateGroup);
   buttonCreateGroup.setOnClickListener(this);
}

edit func.

Kasım Özdemir
  • 5,414
  • 3
  • 18
  • 35
0

So for some apparent reason I didn't think about the fact that I had two xml files for frag_contacts, one in res/layouts and another in res/layout-v26 I admit I am not a pro on android and I kinda auto generated the latter xml file without knowing its use but I still continued working on the on in res/layouts & fully abandoned the one in res/layout-v26 because I didn't know it's use. However it did have a button and a couple of other widgets but with no ID. Since it was in res/layout-v26 meaning it would show for devices compatible with v-26 and totally ignore the one on res/layouts, that's the layout file that would show on android 9 device. & since the button didn't have an ID, a null pointer exception would be thrown.
I have deleted the layout-v-26 file so that devices will fallback to the default layout. The app now works fine.