1

First of all please correct me if my ideology is incorrect, it is my first time working with fragments and not that good at ListView adapters.

I am currently using DrawerLayout which consist of fragments as you'd expect, I have a FAB which upon clicking will add a new entry to the SQLite db entry and will refresh the ListView (data pulled from the db).

My thinking was that I could get the ListView adapter (which is in Profiles fragment class) in the ActivityMain (as the FAB is not part of the fragment and will have different actions depending on current fragment) and then call .notifyDataSetChanged()

The Profiles fragment class

public class Profiles extends Fragment{

    public ProfileListAdapter adapter;

    (...)

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

        DBHandler db = new DBHandler(getActivity().getBaseContext());

        adapter = new ProfileListAdapter(getActivity().getBaseContext(), db.getAllProfiles());
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {

        ListView profileListView = (ListView)view.findViewById(R.id.profileListView);
        profileListView.setAdapter(adapter);
    }

ProfilesListAdapter (from here)

public class ProfileListAdapter extends ArrayAdapter<Profile> {

    private static class ViewHolder {
        TextView name;
    }

    public ProfileListAdapter(Context context, ArrayList<Profile> profileList) {
        super(context, R.layout.profile_row, profileList);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // Get the data item for this position
        Profile profile = getItem(position);
        // Check if an existing view is being reused, otherwise inflate the view
        ViewHolder viewHolder; // view lookup cache stored in tag
        if (convertView == null) {
            // If there's no view to re-use, inflate a brand new view for row
            viewHolder = new ViewHolder();
            LayoutInflater inflater = LayoutInflater.from(getContext());
            convertView = inflater.inflate(R.layout.profile_row, parent, false);
            viewHolder.name = (TextView) convertView.findViewById(R.id.profileListRowValue);
            // Cache the viewHolder object inside the fresh view
            convertView.setTag(viewHolder);
        } else {
            // View is being recycled, retrieve the viewHolder object from tag
            viewHolder = (ViewHolder) convertView.getTag();
        }
        // Populate the data into the template view using the data object
        viewHolder.name.setText(profile.name);
        // Return the completed view to render on screen
        return convertView;
    }
}

Inside the DBHelper class

// Getting All Profiles
public ArrayList<Profile> getAllProfiles() {
    ArrayList<Profile> profileListItems = new ArrayList<Profile>();
    // Select All Query
    String selectQuery = "SELECT * FROM " + TABLE_PROFILE;
    SQLiteDatabase db = this.getWritableDatabase();
    Cursor cursor = db.rawQuery(selectQuery, new String[] {});
    // looping through all rows and adding to list
    if (cursor.moveToLast()) {
        do {
            Profile profile = new Profile();
            profile.setId(Integer.parseInt(cursor.getString(0)));
            profile.setName(cursor.getString(1));
            // Adding contact to list
            profileListItems.add(profile);
        } while (cursor.moveToPrevious());
    }
    // return contact list
    cursor.close();
    return profileListItems;
}

And this is what I am trying to do upon FAB click controlled in MainActivity, magic number is just an int which starts at 0 and increments by one for me to test the db / ListView easier.

db.addProfile(new Profile("Test Profile " + magicNumber));
                magicNumber++;
                FragmentManager fm = getSupportFragmentManager();
                Profiles fragment = (Profiles) fm.findFragmentById(R.id.fragmentProfiles); 
                //I gave the fragment xml main FrameLayout an ID
                fragment.updateListView();

Inside the Fragment class

public void updateListView(){
    adapter.notifyDataSetChanged();
}

I also tried returning the adapter from the Profiles fragment class which I feel is the wrong way to tackle this problem.

public ProfileListAdapter getAdapter(){
    return adapter;
}

I always end up with

java.lang.NullPointerException: Attempt to invoke virtual method 'void layout.Profiles.updateListView()' on a null object reference

or

java.lang.NullPointerException: Attempt to invoke virtual method 'com.xxxxx.xxxxx.appName.ProfileListAdapter layout.Profiles.getAdapter()' on a null object reference

To my noobish eye it seems that the adapter cannot be access from outside the fragment Profiles class, not sure if that's what it is - even if so not sure how to work around this. Let me know if any other code / logcat is required. Thank you!

eeffoc
  • 468
  • 6
  • 19
  • If you want to have a FAB action depend on the fragment, then why can't you add a FAB to each fragment layout? – CodeCody Jul 28 '16 at 22:31
  • @CodeCody I did not think of that to be honest, as the FAB was automatically added to ActivityMain and is visible on all the fragments. I used a switch statement to differentiate which fragment is being used and set the onClick action accordingly. If adding the FAB to each fragment is a better way I will give it a go! – eeffoc Jul 28 '16 at 22:39

1 Answers1

0

For anyone coming across this question, the solution I found was here: notifyDataSetChange not working from custom adapter (top answer worked well).

Although I did implement CodeCody's idea of putting the FABs in individual fragments I can safely revert to as it was earlier, not sure which option is better.

Community
  • 1
  • 1
eeffoc
  • 468
  • 6
  • 19