Reputation: 6743
I'm experimenting with GitHub search users API. My goal is to write a simple app: type a username and any GitHub username related with it will be displayed on RecyclerView (using MVVM pattern).
For example, here's how to search username clive:
https://api.github.com/search/users?q=clive
And here are relevant parts the code:
APIConfig.java
public class APIConfig {
public static final String BASE_URL = "https://api.github.com";
public static final String END_POINT_SEARCH_USERS = "/search/users";
}
APIEndPoint.java
import com.divbyzero.app.githubusersearch.model.User;
import java.util.List;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface APIEndPoint {
@GET(APIConfig.END_POINT_SEARCH_USERS)
Call<List<User>> getSearchResult(@Query("q") String param);
}
User.java
package com.divbyzero.app.githubusersearch.model;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class User {
@SerializedName("login")
@Expose
private String login;
@SerializedName("avatar_url")
@Expose
private String avatar_url;
public void setLogin(String login){
this.login = login;
}
public void setAvatarUrl(String url){
this.avatar_url = url;
}
public String getLogin(){
return login;
}
public String getAvatarUrl(){
return avatar_url;
}
public User(String login, String url){
this.login = login;
this.avatar_url = url;
}
}
UserViewModel.java
package com.divbyzero.app.githubusersearch.viewmodel;
import android.util.Log;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.divbyzero.app.githubusersearch.api.APIEndPoint;
import com.divbyzero.app.githubusersearch.api.APIService;
import com.divbyzero.app.githubusersearch.model.User;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class UserViewModel extends ViewModel {
private MutableLiveData<ArrayList<User>> mutableLiveData = new MutableLiveData<>();
public void setSearchResult(String param){
Retrofit retrofit = APIService.getRetrofitService();
APIEndPoint apiEndpoint = retrofit.create(APIEndPoint.class);
Call<List<User>> call = apiEndpoint.getSearchResult(param);
call.enqueue(new Callback<List<User>>() {
@Override
public void onResponse(Call<List<User>> call, Response<List<User>> response) {
mutableLiveData.setValue((ArrayList<User>) response.body());
Log.d("DBG", "OK");
}
@Override
public void onFailure(Call<List<User>> call, Throwable t) {
Log.d("DBG", "Failed");
}
});
}
public LiveData<ArrayList<User>> getSearchResult(){
return mutableLiveData;
}
}
Full source code: https://github.com/anta40/GithubUserSearch
When I type any username on the SearchView and hit the ENTER key, no search result is displayed (the recyclerview is still empty). After further inspection, I found that "DBG: Failed" was shown on logcat, which means the GitHub API wasn't properly called. How to fix this?
Upvotes: 0
Views: 883
Reputation: 5362
Error which appear in your view model is:
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
So there is a problem with parsing your response. You are receiving it, but parsing wrong.
After calling this GET request (which you are using):
https://api.github.com/search/users?q=some_name
I am receiving:
{
"total_count": 0,
"incomplete_results": false,
"items": [
]
}
Base on receiving .json
I see, that as a root element is JSON OBJECT. In you ViewModel you are expecting List<User>
(JSON ARRAY) which is not true. You are receiving object with 3 fields. And one of this field is your List<User>
.
You have to create new model class describing data which you are receiving. To parse (from json to Java) all received received data, it should contains 3 fields.
Example of your new class:
public class GitHubResponse {
private long totalCount;
private boolean incompleteResults;
private List<User> items;
}
and use this class eveywhere in ViewModel and APIEndPoint.java
. To access data - ad getters to this class.
Reformat code (Ctrl + Alt + L)
Add "start" state (beacuse after starting app view is empty)
Add empty state (when received data is empty)
Add loading state (when you are loading data and waiting for the response)
Add error state (when connection failed or some problem with parsing data)
Upvotes: 1