Search code examples
androidjsonlistviewadaptersearchview

Populate ListView from data fetched by JSON using Volley & triggered on SearchView Submit


Currently, I am making my first android app and have run into a bit of a problem that I can't seem to fix.
I am currently developing a search fragment for 1 page of my app,
This contains a SearchView, a Spinner and a ListView. The Spinner and SearchView are used to filter previous search results (not yet implemented) inside the ListView, this filtering works for hardcoded values perfectly.

However, when I fetch the data using JSON (Logs show that it is successfully fetched) and try to populate the listview using an adapter it doesn't get populated. I presume the reason the hardcoded values show up inside the ListView is down to them being provided before the ListViewAdapter is created/instantiated. However with the JSONAdapter this isn't really possible as it is only fetched from the server on submission of the search, so the ArrayList is null when given to the ListViewAdapter but updating the ArrayList doesnt cause the ListView to be populated.

In my project I use the User class for hardcoded values as it only has 2 fields, platform and username, whereas the GeneralObject class is used for the JSONAdapter to store all the JSON Data.

Search Fragment (Search.java)

SearchView searchView;
ListView listView;
ListViewAdapter listViewAdapter;
String[] platformList;
String[] userNameList;
ArrayList<User> userList = new ArrayList<User>();
ArrayList<GeneralObject> searchResults = new ArrayList<>();
ArrayList<GeneralObject> filteredSearchResults = new ArrayList<>();
ArrayAdapter<CharSequence> spinnerAdapter;

private RequestQueue mQueue;

String currPlatformSelected = "";
String currUserNameSelected = "";
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.search_fragment, container, false);

    Spinner spinner = (Spinner) view.findViewById(R.id.spinner);
    spinnerAdapter = ArrayAdapter.createFromResource(getContext(), R.array.platform_array, android.R.layout.simple_spinner_item);
    spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    //spinner.setPrompt("Platform");
    spinner.setAdapter(spinnerAdapter);
    spinner.setOnItemSelectedListener(this);

    SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
    searchView = (SearchView) view.findViewById(R.id.searchView);
    searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName()));
    setupSearchView();

    userNameList = new String[]{"sallad_", "fork__", "KonoAma", "Darksubi_", "XboxTest", "PlaystationTest"};
    platformList = new String[]{"PC", "PC", "PC", "PC", "Xbox", "PS4"};

    listView = (ListView) view.findViewById(R.id.listview);
    mQueue = Volley.newRequestQueue(getContext());

    // just for populating the arrays before implementing previous history
    if (userNameList.length == 0 || platformList.length == 0)  // if no hardcoded values given
    {
        User previousSearches = new User("No Results", "Please Search Usernames to populate");
        userList.add(previousSearches);
        currUserNameSelected = "Please Search Usernames to populate";
        currPlatformSelected = "No Results";
    }
    else if (userNameList.length == platformList.length) // if there are equal matching pairs in the hardcoded string arrays
    {
        for (int i = 0; i < userNameList.length; i++) {
            User user = new User(platformList[i], userNameList[i]);
            userList.add(user);
        }
    }

    //if i replace the below userList with searchResults it doesn't work as it isnt populated yet
    listViewAdapter = new ListViewAdapter(getContext(), userList);
    listView.setAdapter(listViewAdapter);

    return view;
}

private void setupSearchView()
{
    searchView.setIconified(false);
    searchView.setIconifiedByDefault(false);
    searchView.setOnQueryTextListener(this);
    searchView.setOnSearchClickListener(this);
    searchView.setOnCloseListener(this);
    searchView.setQueryHint("Enter Username...");
}

@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) // Spinner Select
{
    currPlatformSelected = (String) adapterView.getItemAtPosition(i);
    listViewAdapter.filter(currUserNameSelected, currPlatformSelected);
    Log.v("item", (String) currPlatformSelected);
}

@Override
public boolean onQueryTextSubmit(String query) // on SearchView text submit
{
    //searchView.setIconified(true);
    currUserNameSelected = query;

    Log.v("JSON", "starting json import with username = " + currUserNameSelected + " and platform = " + currPlatformSelected);
    //R6StatsJSONAdapter r6StatsJsonAdapter = new R6StatsJSONAdapter(currUserNameSelected, currPlatformSelected, mQueue);
    R6DBJSONAdapter r6DBJsonAdapter = new R6DBJSONAdapter(currUserNameSelected, currPlatformSelected, mQueue);
    r6DBJsonAdapter.ParseGeneral();
    searchResults = r6DBJsonAdapter.getSearchResults();
    Log.v("JSON", "finished json import");
    return true;
}

@Override
public boolean onQueryTextChange(String newText) // on SearchView text change
{
    //searchView.setIconified(false);
    //searchView.setIconifiedByDefault(false);
    currUserNameSelected = newText;
    listViewAdapter.filter(currUserNameSelected, currPlatformSelected);
    return false;
}

ListViewAdapter

public class ListViewAdapter extends BaseAdapter {

// Declare Variables

Context mContext;
LayoutInflater inflater;
private List<User> userList = null;
private ArrayList<User> arraylist;

public ListViewAdapter(Context context, List<User> userList) {
    mContext = context;
    this.userList = userList;
    inflater = LayoutInflater.from(mContext);
    this.arraylist = new ArrayList<User>();
    this.arraylist.addAll(userList);
}

public class ViewHolder {
    TextView userName;
    TextView platformName;
}

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

@Override
public User getItem(int position) {
    return userList.get(position);
}

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

public View getView(final int position, View view, ViewGroup parent) {
    final ViewHolder holder;
    if (view == null) {
        holder = new ViewHolder();
        view = inflater.inflate(R.layout.list_view_items, null);

        holder.userName = (TextView) view.findViewById(R.id.userName);
        holder.platformName = (TextView) view.findViewById(R.id.platformName);
        view.setTag(holder);
    }
    else
    {
        holder = (ViewHolder) view.getTag();
    }
    holder.userName.setText(userList.get(position).getPlayerName());
    holder.platformName.setText(userList.get(position).getPlatform());
    return view;
}

// Filter Class
public void filter(String userName, String platformName)
{
    userName = userName.toLowerCase(Locale.getDefault());
    platformName = platformName.toLowerCase(Locale.getDefault());
    userList.clear();
    for (User currPrevSearch : arraylist)
    {
        if (userName.length() == 0 && currPrevSearch.getPlatform().toLowerCase(Locale.getDefault()).contains(platformName))
        {
            userList.add(currPrevSearch);
        }
        else if (currPrevSearch.getPlayerName().toLowerCase(Locale.getDefault()).contains(userName) && currPrevSearch.getPlatform().toLowerCase(Locale.getDefault()).contains(platformName))
        {
            userList.add(currPrevSearch);
        }
    }
    notifyDataSetChanged();
}

}

Any help would be greatly appreciated and I can clear up any confusion.


Solution

  • Fixed it, Using the adapter onDataSetChanged() method, it updated the data but didn't immediately display it, this is because onSubmit the data was being asynchronously fetched using Volley, so it wasn't available to be displayed (although closing the keyboard made it show up).

    Remedied by updating the data only when the JSONAdapter had finished parsing.