androidactionbarsherlockandroid-tabhostonactivityresultandroid-nested-fragment

Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { dat=content://com.android.contacts/contacts/lookup...}}


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

Solution

  • 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!