2

I am trying to select a contact from contact list and add it to database. But, whenever i select the contact and process data in onActivityResult it throws this exception :

 java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { dat=content://com.android.contacts/contacts/lookup/80i23a826b40e879ef2/314 flg=0x1 }} to activity {com.example.MyApplication/com.example.MyApplication.MainActivity}: java.lang.NullPointerException
Caused by: java.lang.NullPointerException at com.example.myapplication.ChildTab1.onActivityResult(ChildTab1.java:92)

On click on "Add Contacts" Button (in ChildTab2 class) :

Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
getActivity().startActivityForResult(intent, PICK_CONTACT);

The onActivityResult method (in ChildTab2 Class):

@Override
public void onActivityResult(int reqCode, int resultCode, Intent data) {
    super.onActivityResult(reqCode, resultCode, data);

    switch (reqCode) {
    case (PICK_CONTACT) :
        if (resultCode == Activity.RESULT_OK) {
            Uri contactData = data.getData();
            Cursor c =  getActivity().getContentResolver().query(contactData, null, null, null, null);
            if (c.moveToFirst()) {

                String contactId = c.getString(c.getColumnIndex(ContactsContract.Contacts._ID));
                String name = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                String phoneNumber = null;

                String hasPhone = c.getString(c.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));

                if (hasPhone.equalsIgnoreCase("1")) 
                {
                    Cursor phones = getActivity().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ contactId,null, null);
                    while (phones.moveToNext()) 
                    {
                        phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                    }
                    phones.close();

                    ContentValues values = new ContentValues();
                    values.put(ProfilesProvider.NAME,name);
                    values.put(ProfilesProvider.NUMBER,phoneNumber);
                    getActivity().getContentResolver().insert(ProfilesProvider.PROFILES_CONTENT_URI, values);

                }
                else {
                    Toast.makeText(getActivity().getBaseContext(), "Phone Number Not Found", Toast.LENGTH_SHORT).show();
                }


            }
        }
    break;
    }
}

In my app, i have implemented ActionBarShelock. So, there's three tabs (extending SherlockFragment), and in that second tab contains two more tabs (which also extends SherlockFragment). So, i am passing the onActivityResult values from MainActivity to FragmentTab2 to ChildTab1's methods onActivityResult like this :

public void onActivityResult(int requestCode, int resultCode, Intent intent) {
      super.onActivityResult(requestCode, resultCode, intent);
      new FragmentTab2().onActivityResult(requestCode, resultCode, intent);
 }

The code for creating the first three tabs (in MainActivity class):

// Activate Navigation Mode Tabs
    mActionBar = getSupportActionBar();
    mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    // Locate ViewPager in activity_main.xml
    mPager = (ViewPager) findViewById(R.id.pager);

    // Activate Fragment Manager
    FragmentManager fm = getSupportFragmentManager();

    // Capture ViewPager page swipes
    ViewPager.SimpleOnPageChangeListener ViewPagerListener = new ViewPager.SimpleOnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {
            super.onPageSelected(position);
            // Find the ViewPager Position
            mActionBar.setSelectedNavigationItem(position);
        }
    };

    mPager.setOnPageChangeListener(ViewPagerListener);
    // Locate the adapter class called ViewPagerAdapter.java
    ViewPagerAdapter viewpageradapter = new ViewPagerAdapter(fm);
    // Set the View Pager Adapter into ViewPager
    mPager.setAdapter(viewpageradapter);

// Create first Tab
    tab = mActionBar.newTab().setText("Tab 1").setTabListener(tabListener);
    mActionBar.addTab(tab);

    // Create second Tab
    tab = mActionBar.newTab().setText("Tab 2").setTabListener(tabListener);
    mActionBar.addTab(tab);

    // Create third Tab
    tab = mActionBar.newTab().setText("Tab 3").setTabListener(tabListener);
    mActionBar.addTab(tab);

And the code for creating the child tabs (in FragmentTab2 class):

tabHost = new FragmentTabHost(getSherlockActivity());
    tabHost.setup(getSherlockActivity(), getChildFragmentManager(), R.layout.fragmenttab2);

    // Create Child Tab1
    tabHost.addTab(tabHost.newTabSpec("childTab1").setIndicator("Child Tab 1"), ChildTab1.class, null);

    // Create Child Tab2
    tabHost.addTab(tabHost.newTabSpec("childTab2").setIndicator("Child Tab 2"), ChildTab2.class, null);
Blo
  • 11,903
  • 5
  • 45
  • 99
Ashish Tanna
  • 645
  • 1
  • 10
  • 25
  • What are you trying to do here: `new FragmentTab2().onActivityResult(requestCode, resultCode, intent);`? Also please post more of your logcat. This one line doesn't help much, we need to see more to pinpoint the source of the error. – Xaver Kapeller May 04 '14 at 14:18
  • the `onActivityResult` method was not getting called in `ChildTab1`, but it was calling `MainActivity`'s onActivityResult method, so i passed the values from `MainActivity` to it's child `FragmentTab2` to it's child `ChildTab1` . I am calling `new ChildTab1().onActivityResult(requestCode, resultCode, intent);` in `FragmentTab2`'s `onActivityResult` method. – Ashish Tanna May 04 '14 at 14:21
  • 1
    But you don't pass any value to the `FragmentTab2` you just create a new instance of `FragmentTab2` call a method on it and after that this new instance will immediately be garbage collected and destroyed again. If you want to pass a value to an existing instance than you have to call this method on the existing instance. Still please post more relevant code and more of your logcat. Without that we can only guess what the problem might be. – Xaver Kapeller May 04 '14 at 14:26
  • Oops, didn't notice i was creating new instance every time. Silly mistake. :) And, the log has one more thing, i forgot to add. Now, i have added it. It throws the NullPointerException on line : `Cursor c = getActivity().getContentResolver().query(contactData, null, null, null, null);` – Ashish Tanna May 04 '14 at 14:36
  • Well that is most likely because you created a new instance every time. If you create a new instance of a `Fragment` it is not immediately attached to any `Activity` as such `getActivity()` will return null and cause this `NullPointerException`. – Xaver Kapeller May 04 '14 at 14:38
  • I will write a proper answer in the mean time. – Xaver Kapeller May 04 '14 at 14:52
  • Thank you for your Help Xaver. :) I am right now searching to get the current instance of the Fragment. The solutions suggest to get it using fragment's id or tag. But, i am creating fragment using code not xml, and i am not able to find where to set tag/id in code. – Ashish Tanna May 04 '14 at 14:59
  • Well if you create it by code just save the instance in a member variable. You don't need to concern yourself with tags or ids. See my answer. – Xaver Kapeller May 04 '14 at 15:01
  • I have added the code which i am using for creating tabs. I have copied it from a tutorial blog in my app. But, i don't know how to get the instance of fragment from this. – Ashish Tanna May 04 '14 at 15:07
  • Ok I understand, of the top of my head I know of one solution to solve this. I will edit my answer. – Xaver Kapeller May 04 '14 at 15:11

1 Answers1

0

The problem most likely is here:

new FragmentTab2().onActivityResult(requestCode, resultCode, intent);

You are creating a new instance instead of calling the method on the existing instance. Save the Fragment instance in a member variable and after a null check call the method on this instance instead.

Your second error - the NullPointerException - which occurs here:

Cursor c =  getActivity().getContentResolver().query(contactData, null, null, null, null);

Is most likely caused by the same thing. Since you create a new Fragment instance which is not attached to any Activity the method getActivity will return null.

So basically to fix both your errors just call the onActivityResult(...) method on the existing Fragment instance which is attached to the Activity. It should look something like this:

private FragmentTab2 fragmentTab2;  // Save the instance in this variable   

public void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);

    if(fragmentTab2 != null) {
        fragmentTab2.onActivityResult(requestCode, resultCode, intent);
    }
}

EDIT:

To get the Fragment instances you have to override onAttachFragment() in your Activity like this:

private FragmentTab2 fragmentTab2;
private SomeOtherFragment someOtherFragment;

@Override
public void onAttachFragment(Fragment fragment) {
    super.onAttachFragment(fragment);

    // For each of your Fragments add an if statement here checking for 
    // the class of the Fragment and assign if it to the member variables 
    // if a match is found
    if (fragment instanceof FragmentTab2) {

        this.fragmentTab2 = (FragmentTab2) fragment;

    } else if(fragment instanceof SomeOtherFragment) {

        this.someOtherFragment = (SomeOtherFragment) fragment;

    } else ...
}

With this approach null checks are even more important everytime you want to call a method on the instances, so don't forget to always check that the Fragments are not null!

Xaver Kapeller
  • 49,491
  • 11
  • 98
  • 86
  • Thanks for your answer. But, with this i am only able to get instance of `FragmentTab2` not of `ChildTab2` which contains the `onActivityResult` method i want to run. And, the `onAttachFragment` method is not available in `FragmentTab2` class (which extends SherlockFragment), so i can't get the instance of `ChildTab2` even in `FragmentTab2` class. – Ashish Tanna May 04 '14 at 15:30
  • Why would you want the instance of `ChildTab2`? You haven't really posted a lot of code so I can't really tell what your architecture is, but this most certainly looks like bad design. If its a child tag of `FragmentTab2` then it should haven NOTHING to do with the `Activity`. Calling a method on `FragmentTab2` and passing it on to the child is the right way to do it. – Xaver Kapeller May 04 '14 at 16:06
  • The architecture is like this : `MainActivity` creates three tabs `FragmentTab1,2,3` and they extends `SherlockFragment`. In `FragmentTab2` class i create two child tabs `ChildTab1,2` which also extends `SherlockFragment`. I have already added the code i used for creating all these tabs. Plus, now I have edited the code to show which code is in which class to avoid any confusion. And, The `onActivityResult` method i want to call is in `ChildTab2`. But, whenever the result comes it calls the `onActivityResult` method of `MainActivity` not of `ChildTab2`. – Ashish Tanna May 04 '14 at 16:46
  • 1
    The problem is solved now, thanks for your help. :) To get ChildTab2 i had to use `getChildFragmentManager` method of `FragmentTab2`. So, the final code in `onActivityResult` method of `MainActivity` : `Fragment childTab2 = fragmentTab2.getChildFragmentManager().findFragmentByTag("childTab2"); childTab2.onActivityResult(requestCode, resultCode, intent);` – Ashish Tanna May 04 '14 at 17:04