I'm using this recyclerView with searchView app from this Github Repository
The only changes that I made is instead of getting results from the string array, I am using volley to retrieve data from a web server. I have added a singleton class as well for volley needs it. The only problem that I'm getting is that upon application start, the list won't show up not until I click on the search icon and type some text/characters on it. I'm pretty sure that I'm able to retrieve data from the web server since it will show up upon typing something on the search view. Try to test it guys and please tell me if you're able to resolve it.
On the repo, the MainFragment looks the same as the code below, only adding my codes for fetching data from a server. Take a look at my code:
public class MainFragment extends Fragment implements SearchView.OnQueryTextListener {
public static MainFragment newInstance() {
return new MainFragment();
}
private static String url = "http://www.psite7.org/portal/webservices/get_members.php";
private static final String[] MOVIES = new String[]{
"The Woman in Black: Angel of Death",
"20 Once Again",
"Taken 3",
"Tevar",
"I",
"Blackhat",
"Spare Parts",
"The Wedding Ringer",
"Ex Machina",
"Mortdecai",
"Strange Magic",
"The Boy Next Door",
"The SpongeBob Movie: Sponge Out of Water",
"Kingsman: The Secret Service",
"Boonie Bears: Mystical Winter",
"Project Almanac",
"Running Man",
"Wild Card",
"It Follows",
"C'est si bon",
"Yennai Arindhaal",
"Shaun the Sheep Movie",
"Jupiter Ascending",
"Old Fashioned",
"Somewhere Only We Know",
"Fifty Shades of Grey",
"Dragon Blade",
"Zhong Kui: Snow Girl and the Dark Crystal",
"Badlapur",
"Hot Tub Time Machine 2",
"McFarland, USA",
"The Duff",
"The Second Best Exotic Marigold Hotel",
"A la mala",
"Focus",
"The Lazarus Effect",
"Chappie",
"Faults",
"Road Hard",
"Unfinished Business",
"Cinderella",
"NH10",
"Run All Night",
"X+Y",
"Furious 7",
"Danny Collins",
"Do You Believe?",
"Jalaibee",
"The Divergent Series: Insurgent",
"The Gunman",
"Get Hard",
"Home"
};
private RecyclerView mRecyclerView;
private ExampleAdapter mAdapter;
private List<ExampleModel> mModels;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_main, container, false);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
return view;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setHasOptionsMenu(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mModels = new ArrayList<>();
// for (String movie : MOVIES) {
// mModels.add(new ExampleModel(movie));
// }
populate();
// mAdapter = new ExampleAdapter(getActivity(), mModels);
// mRecyclerView.setAdapter(mAdapter);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_main, menu);
final MenuItem item = menu.findItem(R.id.action_search);
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
searchView.setOnQueryTextListener(this);
}
@Override
public boolean onQueryTextChange(String query) {
final List<ExampleModel> filteredModelList = filter(mModels, query);
mAdapter.animateTo(filteredModelList);
mRecyclerView.scrollToPosition(0);
return true;
}
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
private List<ExampleModel> filter(List<ExampleModel> models, String query) {
query = query.toLowerCase();
final List<ExampleModel> filteredModelList = new ArrayList<>();
for (ExampleModel model : models) {
final String text = model.getText().toLowerCase();
if (text.contains(query)) {
filteredModelList.add(model);
}
}
return filteredModelList;
}
public void populate(){
JsonArrayRequest request = new JsonArrayRequest(url,
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray jsonArray) {
// hidePDialog();
String email, status;
// Member member;
final String names[] = new String[jsonArray.length()];
for(int i = 0; i < jsonArray.length(); i++) {
try {
JSONObject object = jsonArray.getJSONObject(i);
names[i] = object.getString("firstname") + " " + object.getString("lastname");
email = object.getString("email");
if(Integer.parseInt(object.getString("activated"))==1){
status = "Active";
}else{
status = "Not Active";
}
// member = new Member(name, email, status);
} catch (Exception e) {
}
}
for(String name : names){
Log.wtf("name", name);
mModels.add(new ExampleModel(name));
}
mAdapter.notifyDataSetChanged();
}
}, new Response.ErrorListener(){
@Override
public void onErrorResponse(VolleyError volleyError) {
volleyError.printStackTrace();
}
});
AppController.getInstance().addToRequestQueue(request);
mAdapter = new ExampleAdapter(getActivity(), mModels);
mRecyclerView.setAdapter(mAdapter);
}
}
If you'll notice I just commented the codes that are being used on the repo. I tried to replicate it as much as possible.
You are mixing up synchronous and asynchronous code. If you create and assign the ExampleAdapter
after you added all models to mModels
it should work as you expect.
public void populate() {
final JsonArrayRequest request = new JsonArrayRequest(url, new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray jsonArray) {
try {
for (int i = 0; i < jsonArray.length(); i++) {
final JSONObject object = jsonArray.getJSONObject(i);
final String name = object.getString("firstname") + " " + object.getString("lastname");
mModels.add(new ExampleModel(name));
}
mAdapter = new ExampleAdapter(getActivity(), mModels);
mRecyclerView.setAdapter(mAdapter);
} catch (JSONException e) {
Log.e(LOG_TAG, "Failed to parse member json.", e);
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
volleyError.printStackTrace();
}
});
AppController.getInstance().addToRequestQueue(request);
}
What would be even better is creating the Adapter
once in onViewCreated()
and then using the animateTo()
method whenever your list of models changes:
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mAdapter = new ExampleAdapter(getActivity(), new ArrayList<>());
mRecyclerView.setAdapter(mAdapter);
...
updateMemberList();
}
public void updateModels() {
final JsonArrayRequest request = new JsonArrayRequest(url, new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray jsonArray) {
try {
for (int i = 0; i < jsonArray.length(); i++) {
final JSONObject object = jsonArray.getJSONObject(i);
final String name = object.getString("firstname") + " " + object.getString("lastname");
mModels.add(new ExampleModel(name));
}
mAdapter.animateTo(mModels);
} catch (JSONException e) {
Log.e(LOG_TAG, "Failed to parse member json.", e);
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
volleyError.printStackTrace();
}
});
AppController.getInstance().addToRequestQueue(request);
}
Both things work, just what you were trying - which was modifiying the List
in your Fragment
- does not. The Adapter
has its own internal List
of models and that is the one you need to modify if you want change what is displayed in the RecyclerView
.