Reputation: 323
I'm not sure why this is happening, I am trying to get data from:
https://api.stackexchange.com/2.2/questions?order=desc&sort=creation&site=stackoverflow&tagged=android
Using the following code:
public interface StackOverflowAPI {
@GET("/2.2/questions?order=desc&sort=creation&site=stackoverflow")
Call<StackQuestions> loadQuestions(@Query("tagged") String tags);
}
and classes:
public class StackQuestion {
@SerializedName("title")
private String title;
@SerializedName("view_count")
private int numViews;
@SerializedName("is_answered")
private boolean solved;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getNumViews() {
return numViews;
}
public void setNumViews(int numViews) {
this.numViews = numViews;
}
public boolean isSolved() {
return solved;
}
public void setSolved(boolean solved) {
this.solved = solved;
}
}
public class StackQuestions {
List<StackQuestion> questions;
}
fragment:
public class AlphaFragment extends Fragment implements Callback<StackQuestions> {
private StackOverflowAPI stackOverflowAPI;
private EditText etxtQuestionToSearch;
private Button btnSearchQuestion;
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mStackQuestionsAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private ArrayList<StackQuestion> mStackQuestionsList;
private final static String TAG = "AlphaFragment";
public AlphaFragment() {}
// ------------------------ FRAGMENT LIFECYCLE ------------------------ //
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
} // end : onCreate Method
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_alpha, container, false);
etxtQuestionToSearch = (EditText) view.findViewById(R.id.etxt_stack_topic);
btnSearchQuestion = (Button) view.findViewById(R.id.button_stack_search);
mRecyclerView = (RecyclerView) view.findViewById(R.id.rcvw_stackquestions_list);
// Recycler View SETUP
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
btnSearchQuestion.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
searchStackQuestion();
} // end : onClick Method
});
return view;
} // end : onCreateView Method
// ------------------------- CALLBACK METHODS ------------------------- //
@Override
public void onResponse(Call<StackQuestions> call,
Response<StackQuestions> response) {
if (response == null) {
return;
}
List<StackQuestion> resultList = response.body().questions;
// X:ERROR: .questions == NULL, so Toast appears
if (resultList == null || resultList.isEmpty()) {
Toast.makeText(getActivity(), "Results for the query are null/empty", Toast.LENGTH_LONG).show();
return;
}
// Add resulting data from web service
for (StackQuestion question : resultList) {
mStackQuestionsList.add(question);
}
// Assign data to recycler view
mStackQuestionsAdapter = new StackQuestionsAdapter(
mStackQuestionsList,
getActivity(),
new RVTapListener() {
@Override
public void onItemClick(View v, int position) {
Toast.makeText(getActivity(), "Now clicked, but not implemented " + new Date(), Toast.LENGTH_SHORT).show();
} // end : onItemClick Method
}
);
mRecyclerView.setAdapter(mStackQuestionsAdapter);
} // end : onResponse Method
@Override
public void onFailure(Call<StackQuestions> call,
Throwable t) {
Toast.makeText(getActivity(), t.getLocalizedMessage(), Toast.LENGTH_LONG).show();
} // end : onFailure Method
// ------------------------- FRAGMENT METHODS ------------------------- //
private void init() {
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.stackexchange.com")
.addConverterFactory(GsonConverterFactory.create(gson))
.client(client)
.build();
stackOverflowAPI = retrofit.create(StackOverflowAPI.class);
} // end : init Method
private void searchStackQuestion() {
mStackQuestionsList = new ArrayList<>();
Call<StackQuestions> call = stackOverflowAPI.loadQuestions("android");
call.enqueue(this);
} // end : searchStackQuestion Method
}
Gradle dependencies:
compile 'com.google.code.gson:gson:2.7'
compile 'com.android.support:design:24.0.0'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.android.support:cardview-v7:24.0.0'
compile 'com.android.support:appcompat-v7:24.0.0'
compile 'com.android.support:recyclerview-v7:24.0.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
After executing the code, I've got on logcat, the following:
D/OkHttp: <-- 200 OK https://api.stackexchange.com/2.2/questions?order=desc&sort=creation&site=stackoverflow&tagged=android (1136ms)
D/OkHttp: Cache-Control: private
D/OkHttp: Content-Type: application/json; charset=utf-8
D/OkHttp: Access-Control-Allow-Origin: *
D/OkHttp: Access-Control-Allow-Methods: GET, POST
D/OkHttp: Access-Control-Allow-Credentials: false
D/OkHttp: X-Content-Type-Options: nosniff
D/OkHttp: Date: Tue, 28 Jun 2016 22:56:26 GMT
D/OkHttp: {"items":[{"tags":["android"],"owner":{"reputation":1,"user_id" ...
D/OkHttp: er_id":1163471,"user_type":"registered","accept_rate":93,"profil ...
D/OkHttp: e?type=large","display_name":"Vahid Zadeh","link":"http://stacko ...
D/OkHttp: n_id":38086882,"link":"stackoverflow.com/questions/380868 ...
D/OkHttp: ","animation-listener"],"owner":{"reputation":23,"user_id":43462 ...
D/OkHttp: <-- END HTTP (19295-byte body)
Everything is going fine, but i get NullPointerException in this part of the AlphaFragment:
List<StackQuestion> resultList = response.body().questions;
// X:ERROR: .questions == NULL, so Toast appears
if (resultList == null || resultList.isEmpty()) {
Toast.makeText(getActivity(), "Results for the query are null/empty", Toast.LENGTH_LONG).show();
return;
}
What could be the problem? I've got status code
200
, and there is JSON information right there; but, after trying to retrieve it, NPE
appears.
Thanks in advance...
Upvotes: 3
Views: 11535
Reputation: 71
Retrofit uses gson by default for parsing json, so to successfully parse json you need to define model in the same hierarchy.
I guess something like this would work:
public class StackQuestions {
private List<StackQuestion> items;
public void setItems(List<StackQuestion> items){
this.items = items;
}
public List<StackQuestions> getItems(){
return this.items;
}
}
public class StackQuestion{
private Owner owner;
public void setOwner(Owner owner){
this.owner = owner;
}
public Owner getOwner(){
return this.owner;
}
}
public class Owner {
@SerializedName("title")
private String title;
@SerializedName("view_count")
private int numViews;
@SerializedName("is_answered")
private boolean solved;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getNumViews() {
return numViews;
}
public void setNumViews(int numViews) {
this.numViews = numViews;
}
public boolean isSolved() {
return solved;
}
public void setSolved(boolean solved) {
this.solved = solved;
}
}
Upvotes: 0
Reputation: 505
I think there's a mistake in your model.
Try:
public class StackQuestions {
@SerializedName("items")
List<StackQuestion> questions;
}
Upvotes: 3