1

I'm trying to inflate an ExpandableListView in a Fragment and use a setAdapter. I succeed properly when I don't use it in a fragment, but in Fragment, I either get errors (NullPointerException) or the ExpandableListView won't be populated.

package com.stylingandroid.basicactionbar;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListView;

public class Friends extends Fragment
{
    private static List<Country> Countries;
    private ExpandableListView expandableListView;
    private CountryAdapter adapter;
    private View V;


    @Override
    public View onCreateView( LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState )
    {

        V = inflater.inflate( R.layout.frag2, container, false );
        LoadCountries();
        expandableListView = (ExpandableListView) V.findViewById(R.id.expandableListView);
        expandableListView.setAdapter(adapter);
        adapter = new CountryAdapter(this, Countries);

        return V;
    }


    private void LoadCountries() {
        Countries = new ArrayList<Country>();

        ArrayList<String> citiesAustralia = new ArrayList<String>(
                Arrays.asList("Brisbane", "Hobart", "Melbourne", "Sydney"));
        Countries.add(new Country("Australia", citiesAustralia));

        ArrayList<String> citiesChina = new ArrayList<String>(
                Arrays.asList("Beijing", "Chuzhou", "Dongguan", "Shangzhou"));
        Countries.add(new Country("China", citiesChina));
    }
    }

frag2.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent">
    <ExpandableListView
            android:id="@+id/expandableListView"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"/>
</LinearLayout>

package com.stylingandroid.basicactionbar;



import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity
{
    private class MyTabListener implements ActionBar.TabListener
    {
        private Fragment mFragment;
        private final Activity mActivity;
        private final String mFragName;

        public MyTabListener( Activity activity, String fragName )
        {
            mActivity = activity;
            mFragName = fragName;
        }

        @Override
        public void onTabReselected( Tab tab, FragmentTransaction ft )
        {
            // TODO Auto-generated method stub

        }

        @Override
        public void onTabSelected( Tab tab, FragmentTransaction ft )
        {
            mFragment = Fragment.instantiate( mActivity, mFragName );
            ft.add( android.R.id.content, mFragment );
        }

        @Override
        public void onTabUnselected( Tab tab, FragmentTransaction ft )
        {
            ft.remove( mFragment );
            mFragment = null;
        }
    }

    @Override
    public void onCreate( Bundle savedInstanceState )
    {
        super.onCreate( savedInstanceState );       
        Intent intent;

        ActionBar ab = getActionBar();
        ab.setNavigationMode( ActionBar.NAVIGATION_MODE_TABS );

        Tab tab = ab.newTab()
                .setText( R.string.title_param )
                .setTabListener( 
                        new MyTabListener( this, 
                                Param.class.getName() ) );
        ab.addTab( tab );

        intent = new Intent().setClass(this, Friends.class);
        tab = ab.newTab()
                .setText( R.string.title_friends )


                .setTabListener( 
                        new MyTabListener( this, 
                                Friends.class.getName() ) );
        ab.addTab( tab );

        tab = ab.newTab()
                .setText( R.string.title_maps )
                .setTabListener( 
                        new MyTabListener( this, 
                                Maps.class.getName() ) );
        ab.addTab( tab );
    }

    @Override
    public boolean onCreateOptionsMenu( Menu menu )
    {
        getMenuInflater().inflate( R.menu.main, menu );
        return true;
    }

    @Override
    public boolean onOptionsItemSelected( MenuItem item )
    {
        boolean ret;
        if (item.getItemId() == R.id.menu_settings)
        {
            // Handle Settings
            ret = true;
        } else
        {
            ret = super.onOptionsItemSelected( item );
        }
        return ret;
    }
}

CountryAdapter:

package com.stylingandroid.basicactionbar;

import android.R;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;

import java.util.List;

public class CountryAdapter extends BaseExpandableListAdapter {
    private List<Country> countries;
    private LayoutInflater inflater;

    public CountryAdapter(Context context) {
        this.countries = countries;
        inflater = LayoutInflater.from(context);
    }

    public CountryAdapter(Friends friends, List<Country> countries2) {
        // TODO Auto-generated constructor stub
    }

    @Override
    public int getGroupCount() {
        return countries.size();
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return countries.get(groupPosition).getCities().size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return countries.get(groupPosition).getName();
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return countries.get(groupPosition).getCities().get(childPosition);
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.simple_expandable_list_item_1, parent, false);
        }

        ((TextView) convertView).setText(getGroup(groupPosition).toString());
        return convertView;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        if(convertView == null) {
            convertView = inflater.inflate(R.layout.simple_list_item_1, parent, false);
        }

        ((TextView)convertView).setText(getChild(groupPosition,childPosition).toString());
        return convertView;
    }

    @Override
    public boolean isChildSelectable(int i, int i2) {
        return false;
    }
}

The part, I guess, that is wrong is there:

public CountryAdapter(Context context) {
    this.countries = countries;
    inflater = LayoutInflater.from(context);
}

The problem is that I don't understand how to use the (Context, context) for the fragment Friends. Any idea?

Thank you in advance! :)

EDIT:

I used the code of Gaurav Vashisth and I can a NullPointerException. Here is the stack trace.

10-12 19:11:52.105: D/dalvikvm(2203): GC_FOR_ALLOC freed 41K, 6% free 2553K/2716K, paused 62ms, total 66ms
10-12 19:11:52.116: I/dalvikvm-heap(2203): Grow heap (frag case) to 3.215MB for 635812-byte allocation
10-12 19:11:52.265: D/dalvikvm(2203): GC_FOR_ALLOC freed 1K, 6% free 3172K/3340K, paused 141ms, total 141ms
10-12 19:11:52.525: D/dalvikvm(2203): GC_CONCURRENT freed <1K, 5% free 3178K/3340K, paused 8ms+176ms, total 264ms
10-12 19:11:53.405: D/libEGL(2203): loaded /system/lib/egl/libEGL_emulation.so
10-12 19:11:53.495: D/(2203): HostConnection::get() New Host Connection established 0x2a155620, tid 2203
10-12 19:11:53.616: D/libEGL(2203): loaded /system/lib/egl/libGLESv1_CM_emulation.so
10-12 19:11:53.625: D/libEGL(2203): loaded /system/lib/egl/libGLESv2_emulation.so
10-12 19:11:53.725: W/EGL_emulation(2203): eglSurfaceAttrib not implemented
10-12 19:11:53.766: D/OpenGLRenderer(2203): Enabling debug mode 0
10-12 19:12:11.858: D/AndroidRuntime(2203): Shutting down VM
10-12 19:12:11.858: W/dalvikvm(2203): threadid=1: thread exiting with uncaught exception (group=0x40a71930)
10-12 19:12:11.906: E/AndroidRuntime(2203): FATAL EXCEPTION: main
10-12 19:12:11.906: E/AndroidRuntime(2203): java.lang.NullPointerException
10-12 19:12:11.906: E/AndroidRuntime(2203):     at com.stylingandroid.basicactionbar.CountryAdapter.getGroupCount(CountryAdapter.java:26)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at android.widget.ExpandableListConnector.getCount(ExpandableListConnector.java:397)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at android.widget.ListView.setAdapter(ListView.java:462)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at android.widget.ExpandableListView.setAdapter(ExpandableListView.java:470)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at com.stylingandroid.basicactionbar.Friends.onCreateView(Friends.java:32)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at android.app.Fragment.performCreateView(Fragment.java:1695)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:885)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1057)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at android.app.BackStackRecord.run(BackStackRecord.java:682)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1435)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at android.app.FragmentManagerImpl$1.run(FragmentManager.java:441)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at android.os.Handler.handleCallback(Handler.java:725)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at android.os.Handler.dispatchMessage(Handler.java:92)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at android.os.Looper.loop(Looper.java:137)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at android.app.ActivityThread.main(ActivityThread.java:5041)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at java.lang.reflect.Method.invokeNative(Native Method)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at java.lang.reflect.Method.invoke(Method.java:511)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
10-12 19:12:11.906: E/AndroidRuntime(2203):     at dalvik.system.NativeStart.main(Native Method)
10-12 19:17:12.528: I/Process(2203): Sending signal. PID: 2203 SIG: 9

EDIT 2: With the following code, I get the NullPointerException, stack trace above modified.

@Override
public View onCreateView( LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState )
{

    LoadCountries();
    V = inflater.inflate( R.layout.frag2, container, false );
    expandableListView = (ExpandableListView) V.findViewById(R.id.expandableListView);

    adapter = new CountryAdapter(getActivity(), Countries);
    expandableListView.setAdapter(adapter);
    return V;
}

CountryAdapter:

private List<Country> countries;
private LayoutInflater inflater;

public CountryAdapter(Context context, List<Country> contries) {
    this.countries = countries;
    inflater = LayoutInflater.from(context);
}
Gaurav Vashisth
  • 7,547
  • 8
  • 35
  • 56
Synor
  • 333
  • 1
  • 4
  • 13

2 Answers2

0

Use getActivity()

public final Activity getActivity ()

Added in API level 11
Return the Activity this fragment is currently associated with.

Replace

  adapter = new CountryAdapter(this, Countries);

By

  adapter = new CountryAdapter(getActivity(), Countries);

Also you need to reverse

 expandableListView.setAdapter(adapter);
 adapter = new CountryAdapter(this, Countries);

to

 adapter = new CountryAdapter(getActivity(), Countries);
 expandableListView.setAdapter(adapter);

Edit:

Also it would be better to change to

  private void LoadCountries() {
    Countries = new ArrayList<Country>();

    ArrayList<String> citiesAustralia = new ArrayList<String>(
            Arrays.asList("Brisbane", "Hobart", "Melbourne", "Sydney"));
    Countries.add(new Country("Australia", citiesAustralia));

    ArrayList<String> citiesChina = new ArrayList<String>(
            Arrays.asList("Beijing", "Chuzhou", "Dongguan", "Shangzhou"));
    Countries.add(new Country("China", citiesChina));
    adapter = new CountryAdapter(getActivity(), Countries);
    expandableListView.setAdapter(adapter);

   }
Raghunandan
  • 132,755
  • 26
  • 225
  • 256
0

I see that in your onCreateView method you are using the adapter method before initializing it. Use it this way

@Override
public View onCreateView( LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState )
{

    V = inflater.inflate( R.layout.frag2, container, false );
    LoadCountries();
    expandableListView = (ExpandableListView) V.findViewById(R.id.expandableListView);

    adapter = new CountryAdapter(getActivity(), Countries);
    expandableListView.setAdapter(adapter);
    return V;
}

To get reference of activity in a fragment use getActivity()

Besides it

So that your Adapter's constructor becomes

public CountryAdapter(Context context, List<Country> countries) {
    this.countries = countries;
    inflater = LayoutInflater.from(context);
}

I would also like to point out that according to java conventions method names start with lower case letters. So It would we great if you rename LoadCountries() to loadCountries()

Gaurav Vashisth
  • 7,547
  • 8
  • 35
  • 56