0

I am having issues converting my previously working FragmentActivity and Customlistadapter to a ListFragment to be used with my navigation drawer. Currently, the navigation drawer is working correctly.

Below is the modified code for GetContacts

public class GetContacts extends android.support.v4.app.ListFragment {

// Log tag
private static final String TAG = MainActivity.class.getSimpleName();

// json URL
private static final String url = "http://url.json.php";
private ProgressDialog pDialog;
private List<Contacts> contactList = new ArrayList<Contacts>();
private ListView listView;
private ContactListAdapter adapter;


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

    View rootview = inflater.inflate(R.layout.fragment_contacts, container, false);
    return rootview;

}


@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    //See the second issue about wotking with ListFragment's list.
    adapter = new ContactListAdapter(this, contactList);
    setListAdapter(adapter);

    // pDialog = new ProgressDialog(this);
    // Showing progress dialog before making http request
    // pDialog.setMessage("Loading...");
    //pDialog.show();


    // Creating volley request obj
    JsonArrayRequest contactReq = new JsonArrayRequest(url,
            new Response.Listener<JSONArray>() {
                @Override
                public void onResponse(JSONArray response) {
                    Log.d(TAG, response.toString());
                    hidePDialog();

                    // Parsing json
                    for (int i = 0; i < response.length(); i++) {
                        try {

                            JSONObject obj = response.getJSONObject(i);
                            Contacts contacts = new Contacts();
                            contacts.setDivision(obj.getString("Division"));
                            contacts.setName(obj.getString("name"));
                            contacts.setNumber(obj.getString("number"));


                            // adding contacts to contacts array
                            contactList.add(contacts);

                        } catch (JSONException e) {
                            e.printStackTrace();
                        }

                    }

                    // notifying list adapter about data changes
                    // so that it renders the list view with updated data
                    adapter.notifyDataSetChanged();
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            VolleyLog.d(TAG, "Error: " + error.getMessage());
            hidePDialog();

        }
    });

    // Adding request to request queue
    AppController.getInstance().addToRequestQueue(contactReq);
    //end volley code paste
}


public void onDestroy() {
    super.onDestroy();
    hidePDialog();
}

private void hidePDialog() {
    if (pDialog != null) {
        pDialog.dismiss();
        pDialog = null;
    }
}

}

Additionally, I have modified the code for ContactListAdapter. Currently I am getting the following compile error. "Error:(49, 56) error: cannot find symbol method getContext()". I checked this SO question and tried to understand what is causing this issue with no luck.

public class ContactListAdapter extends BaseAdapter {
private Activity activity;
private Fragment fragment;
private LayoutInflater inflater;
private List<Contacts> contactItems;


public ContactListAdapter(Fragment fragment, List<Contacts> contactItems) {
    this.fragment = fragment;
    this.contactItems = contactItems;
}

@Override
public int getCount() {
    return contactItems.size();
}

@Override
public Object getItem(int location) {
    return contactItems.get(location);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {


    if (convertView == null){
        LayoutInflater inflater = (LayoutInflater)    getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.list_rowcontacts, null);
    }

    TextView division = (TextView) convertView.findViewById(R.id.division);
    TextView name = (TextView) convertView.findViewById(R.id.name);
    TextView number = (TextView) convertView.findViewById(R.id.number);


    // getting contact data for the row
    Contacts m = contactItems.get(position);


    // Division
    division.setText(m.getDivision());

    // Name
    name.setText("Name: " + m.getName());

    // number
    number.setText("Number: " + m.getNumber());


    return convertView;
}

}

Community
  • 1
  • 1
bears22
  • 3
  • 3

1 Answers1

1

The main problem is that a FragmentActivity isn't a Fragment, is an Activity (see the reference here). You can't instantiate it as a Fragment like you do in selectItem().

If you want contacts to be loaded in your main activity (the one with the navigation drawer) then GetContacts should inherit from Fragment instead of FragmentActivity.

UPDATE

There are three issues with your code.

Null pointer exception (setting the adapter in the right place)

First you should move everything related to setting up the adapter to a method that is called after the Fragment is attached to its Activity (more info about the Fragment's lifecycle here). In onCreateView the Activity hasn't attached the Fragment yet so the Context of the adapter won't be available (see the third issue). Override onAttach() and place it there:

public class GetContacts extends ListFragment {

// Log tag
private static final String TAG = MainActivity.class.getSimpleName();

// json URL
private static final String url = "http://url.json.php";
private ProgressDialog pDialog;
private List<Contacts> contactList = new ArrayList<Contacts>();
private ListView listView;
public ContactListAdapter adapter;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_contacts, container, false);
    return rootView;
}

@Override
public void onAttach(Activity activity) {
    //See the third issue about the Context passed to the adapter.
    adapter = new ContactListAdapter(activity, contactList);
    //See the second issue about working with ListFragment's list.
    setListAdapter(adapter);

   // pDialog = new ProgressDialog(this);

    // Showing progress dialog before making http request
  // pDialog.setMessage("Loading...");
   //pDialog.show();


    // Creating volley request obj
    JsonArrayRequest contactReq = new JsonArrayRequest(url,
            new Response.Listener<JSONArray>() {
                @Override
                public void onResponse(JSONArray response) {
                    Log.d(TAG, response.toString());
                    hidePDialog();

                    // Parsing json
                    for (int i = 0; i < response.length(); i++) {
                        try {

                            JSONObject obj = response.getJSONObject(i);
                            Contacts contacts = new Contacts();
                            contacts.setDivision(obj.getString("Division"));
                            contacts.setName(obj.getString("name"));
                            contacts.setNumber(obj.getString("number"));


                            // adding contacts to contacts array
                            contactList.add(contacts);

                        } catch (JSONException e) {
                            e.printStackTrace();
                        }

                    }

                    // notifying list adapter about data changes
                    // so that it renders the list view with updated data
                    adapter.notifyDataSetChanged();
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            VolleyLog.d(TAG, "Error: " + error.getMessage());
            hidePDialog();

        }
    });

    // Adding request to request queue
    AppController.getInstance().addToRequestQueue(mcontactReq);
    //end volley code paste
}


public void onDestroy() {
    super.onDestroy();
    hidePDialog();
}

private void hidePDialog() {
    if (pDialog != null) {
        pDialog.dismiss();
        pDialog = null;
    }
}
}

Null pointer exception (working with ListFragment's list

ListFragments provide some methods like setListAdapter() to work with the inner ListView without having to get it first with findViewById(), but they work with their "default" ListView. For identifying this ListView they look in the layout for a ListView with the id @id/android:list. You're using a custom id for your ListView so setListAdapter() cannot find the default ListView (more info about ListFragment here). You have three posible solutions:

First: If your layout doesn't contain more than a ListView you don't have to use a custom layout. Don't override onCreateView, removing everything about inflating a custom view.

Second: Change the id of your ListView to @id/android:list in the xml layout file.

Third: Maintain your custom layout and id, but always use the ListView getting it first with findViewById(), not with the ListFragment's methods for dealing with lists (like when GetContacts was a FragmentActivity). So this:

listView  = (ListView) rootView.findViewById(android.R.id.list);
adapter = new ContactListAdapter(this, contactList);
setListAdapter(adapter);

would become this:

listView  = (ListView) getView().findViewById(android.R.id.list);
adapter = new ContactListAdapter(this, contactList);
listView.setListAdapter(adapter);

The first two allow you to work with the default list. I don't recomend you to go for the third, since ListFragments are designed for helping you in dealing with lists faster and you wouldn't be using their helper methods, and therefore using a ListFragment like any other Fragment.

P.S. The code for GetContacts I posted before use the second solution.

LayoutInflater in Adapter

With BaseAdapter you have to keep a reference of the Context in wich the adapter will work. Since Fragment isn't a Context, fragments have to use the Activity they're attached to as the Context. Look a this line in the GetContact's code I just updated (in GetContact's onAttached()):

adapter = new ContactListAdapter(activity, contactList);

Then in the adapter you use that as the Context to get the LayoutInflater:

public class ContactListAdapter extends BaseAdapter {
//There is no need for this two
//private Activity activity;
//private Fragment fragment;

//We use this instead
private Context context

private LayoutInflater inflater;
private List<Contacts> contactItems;

//Now the constructor receives a Context
public ContactListAdapter(Context context, List<Contacts> contactItems) {
    this.context = context;
    this.contactItems = contactItems;
}

//Every other method remains the same
...

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    //Now we use context to get the LayoutInflater
    if (convertView == null){
        LayoutInflater inflater = (LayoutInflater)    context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.list_rowcontacts, null);
    }

    //The rest of the code is the same
    ...
}
}

EDIT

Added the changed code for the "set up the adapter in the right place".

Changed the third issue for using a BaseAdapter (I got confused).

  • Thanks for the help. When I change that class and extend a Fragment instead of a FragmentActivity, I get some compile errors with the listview. Is there a general guide on converting activities to fragments that would help? – bears22 Oct 27 '14 at 17:44
  • @bears22 I think I should have extended my answer addressing those issues. You can see a SO question about the same subject [here](http://stackoverflow.com/q/21205732/4165582). But actually I'd advise you to learn about fragments and their lifecycle from scratch and you'd automatically understand what you have to change in your code (tutorials [here](http://developer.android.com/guide/components/fragments.html) and [here](http://www.vogella.com/tutorials/AndroidFragments/article.html)). – Alberto Casares Oct 27 '14 at 18:53
  • @bears22 In the meantime if you want to fix those problems ASAP please update your question and I'll try to help in everything I can. – Alberto Casares Oct 27 '14 at 18:56
  • Thanks for the help @Alberto Casares . I have updated the question to reflect my current issue. If you could help out I would greatly appreciate it! I appreciate the links, but am still having trouble fixing the code. I am reading some intro to android programming books and trying to work through some real life examples to help expand my knowledge. Any help is appreciated! – bears22 Oct 27 '14 at 20:18
  • Thanks for the help, I appreciate your attention to detail an the way you explained the different options! I modified my code and updated my question as I am getting an error with the getContext() method in the ContactListAdapter. I am marking your question as correct as I work out my last issue! – bears22 Oct 28 '14 at 15:45
  • @bears22 I edited the third issue. The thing is I got confused between BaseAdapter and ArrayAdapter. The second one has method to access its Context (getContext()), but the first one doesn't, and that's why you get the new error. – Alberto Casares Oct 28 '14 at 17:37