Reputation: 89
I am getting a NullPointerException when calling a Rest API using RetroFit. The thing is I am using the same method and Adapter structure with another call that has the same structure of json, but for some reason only this call is getting a NullPointerException, please try to help:
The exception log:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List com.mad.footstats.data.goals.response.GoalsResponse.getTopGoalsList()' on a null object reference
at com.mad.footstats.ui.fragments.StandingsFragment$2.onResponse(StandingsFragment.java:84)
This is the Fragment where I am calling the Rest api with retrofit:
public class StandingsFragment extends Fragment {
private final static String TAG = "Call Failed";
private StandingsAdapter mStandingsAdapter;
private RecyclerView mRecyclerView;
private ProgressBar mProgressBar;
private String mTournamentId;
private String mRegion;
private String mKey;
private GoalsAdapter mGoalsAdapter;
private AssistsAdapter mAssistsAdapter;
public StandingsFragment(){
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_standings, container, false);
// Getting the Arguments
Bundle bundle = getArguments();
mTournamentId = bundle.getString("tournament_id");
mRegion = bundle.getString("region");
mKey = bundle.getString("key");
// Showing the Progressbar
mProgressBar = view.findViewById(R.id.standings_progress_bar);
// Creating an instance of the ApiInterface
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
// Calling to get the standings from the API
Call<StandingsResponse> call = apiService.getStandings(mRegion,mTournamentId,mKey);
// Logging the URL Call
Log.wtf("URL Called", call.request().url() + "");
call.enqueue(new Callback<StandingsResponse>() {
@Override
public void onResponse(Call<StandingsResponse> call, Response<StandingsResponse> response) {
generateStandings(response.body().getStandings());
mStandingsAdapter.notifyDataSetChanged();
mProgressBar.setVisibility(View.GONE);
}
@Override
public void onFailure(Call<StandingsResponse> call, Throwable t) {
Log.e(TAG, t.toString());
Toast.makeText(getActivity(), R.string.enqueue_failure, Toast.LENGTH_LONG).show();
mProgressBar.setVisibility(View.GONE);
}
});
// Calling to get the Goals from the API
Call<GoalsResponse> goalsCall = apiService.getGoalsLeaders(mRegion,mTournamentId,mKey);
// Logging the URL Call
Log.wtf("URL Called", call.request().url() + "");
goalsCall.enqueue(new Callback<GoalsResponse>() {
@Override
public void onResponse(Call<GoalsResponse> call, Response<GoalsResponse> response) {
generateGoals(response.body().getTopGoalsList());
mGoalsAdapter.notifyDataSetChanged();
}
@Override
public void onFailure(Call<GoalsResponse> call, Throwable t) {
Log.e(TAG, t.toString());
Toast.makeText(getActivity(), R.string.enqueue_failure, Toast.LENGTH_LONG).show();
mProgressBar.setVisibility(View.GONE);
}
});
// Calling to get the Assists from the API
Call<AssistsResponse> assistsCall = apiService.getAssistsLeaders(mRegion,mTournamentId,mKey);
// Logging the URL Call
Log.wtf("URL Called", call.request().url() + "");
assistsCall.enqueue(new Callback<AssistsResponse>() {
@Override
public void onResponse(Call<AssistsResponse> call, Response<AssistsResponse> response) {
generateAssists(response.body().getTopAssists());
mGoalsAdapter.notifyDataSetChanged();
}
@Override
public void onFailure(Call<AssistsResponse> call, Throwable t) {
Log.e(TAG, t.toString());
Toast.makeText(getActivity(), R.string.enqueue_failure, Toast.LENGTH_LONG).show();
}
});
return view;
}
/**
* Method to generate List of standings using RecyclerView with custom adapter
*/
private void generateStandings(final List<Standings> empDataList) {
mRecyclerView = getView().findViewById(R.id.standings_rv);
mStandingsAdapter = new StandingsAdapter(empDataList, R.layout.item_standings, getActivity());
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecyclerView.setAdapter(mStandingsAdapter);
}
/**
* Method to generate List of Goal leaders using RecyclerView with Custom adapter
*/
private void generateGoals(final List<TopGoals> topGoals){
RecyclerView recyclerView = getView().findViewById(R.id.goals_rv);
mGoalsAdapter = new GoalsAdapter(topGoals,R.layout.item_goals, getActivity());
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setAdapter(mGoalsAdapter);
}
/**
* Method to generate List of assists leaders using RecyclerView with Custom adapter
*/
private void generateAssists(final List<TopAssists> topAssists){
RecyclerView assistsRecyclerView = getView().findViewById(R.id.assists_rv);
mAssistsAdapter = new AssistsAdapter(topAssists,R.layout.item_assists, getActivity());
assistsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
assistsRecyclerView.setAdapter(mAssistsAdapter);
}
Furthermore, Here is an example of the Json generated from the API call:
{
"tournament": {
"id": "sr:tournament:136",
"name": "A-League",
"sport": {
"id": "sr:sport:1",
"name": "Soccer"
},
"category": {
"id": "sr:category:34",
"name": "Australia",
"country_code": "AUS"
},
"current_season": {
"id": "sr:season:45280",
"name": "A-League 17\/18",
"start_date": "2017-10-06",
"end_date": "2018-05-28",
"year": "17\/18"
}
},
"season_coverage_info": {
"season_id": "sr:season:45280",
"scheduled": 148,
"played": 143,
"max_coverage_level": "gold",
"max_covered": 140,
"min_coverage_level": "bronze"
},
"top_assists": [{
"assists": 12,
"rank": 1,
"player": {
"id": "sr:player:22132",
"name": "George, Leroy"
},
"team": {
"id": "sr:competitor:5970",
"name": "Melbourne Victory",
"abbreviation": "MEL"
}
}, {
"assists": 10,
"rank": 2,
"player": {
"id": "sr:player:139782",
"name": "Petratos, Dimitri"
},
"team": {
"id": "sr:competitor:2934",
"name": "Newcastle United Jets FC",
"abbreviation": "NEW"
}
}]
If you need any more code please request and I'll provide immediately.
Edit: here is GoalsResponse.Java:
public class GoalsResponse {
@SerializedName("generated_at")
@Expose
private String mGeneratedAt;
@SerializedName("schema")
@Expose
private String mSchema;
@SerializedName("top_goals")
private List<TopGoals> mTopGoalsList;
public String getGeneratedAt() {
return mGeneratedAt;
}
public void setGeneratedAt(String generatedAt) {
mGeneratedAt = generatedAt;
}
public String getSchema() {
return mSchema;
}
public void setSchema(String schema) {
mSchema = schema;
}
public List<TopGoals> getTopGoalsList() {
return mTopGoalsList;
}
public void setTopGoalsList(List<TopGoals> topGoalsList) {
mTopGoalsList = topGoalsList;
}
Example of TopAssists and TopGoals in the Json Reply:
{
"tournament": {
"id": "sr:tournament:136",
"name": "A-League",
"sport": {
"id": "sr:sport:1",
"name": "Soccer"
},
"category": {
"id": "sr:category:34",
"name": "Australia",
"country_code": "AUS"
},
"current_season": {
"id": "sr:season:45280",
"name": "A-League 17\/18",
"start_date": "2017-10-06",
"end_date": "2018-05-28",
"year": "17\/18"
}
},
"season_coverage_info": {
"season_id": "sr:season:45280",
"scheduled": 148,
"played": 143,
"max_coverage_level": "gold",
"max_covered": 140,
"min_coverage_level": "bronze"
},
"top_goals": [{
"goals": 32,
"rank": 1,
"player": {
"id": "sr:player:159665",
"name": "Salah, Mohamed"
},
"team": {
"id": "sr:competitor:44",
"name": "Liverpool FC",
"abbreviation": "LIV"
}
}, {
"goals": 30,
"rank": 2,
"player": {
"id": "sr:player:108579",
"name": "Kane, Harry"
},
"team": {
"id": "sr:competitor:33",
"name": "Tottenham Hotspur",
"abbreviation": "TOT"
}
}],
"top_assists": [{
"assists": 12,
"rank": 1,
"player": {
"id": "sr:player:22132",
"name": "George, Leroy"
},
"team": {
"id": "sr:competitor:5970",
"name": "Melbourne Victory",
"abbreviation": "MEL"
}
}, {
"assists": 10,
"rank": 2,
"player": {
"id": "sr:player:139782",
"name": "Petratos, Dimitri"
},
"team": {
"id": "sr:competitor:2934",
"name": "Newcastle United Jets FC",
"abbreviation": "NEW"
}
}]
Upvotes: 1
Views: 128
Reputation: 763
What you should do is, in Retrofit first check wheather the response is successfull, so change the onResponse callback to something like this:
goalsCall.enqueue(new Callback<GoalsResponse>() {
@Override
public void onResponse(Call<GoalsResponse> call, Response<GoalsResponse> response) {
if(response.isSuccessful()){
Log.d(TAG, response.body().toString())
generateGoals(response.body().getTopGoalsList());
mmGoalsAdapter.notifyDataSetChanged();
}
else{
Log.d(TAG,"in not successfull" + response.code().toString())
}
}
@Override
public void onFailure(Call<GoalsResponse> call, Throwable t) {
Log.e(TAG, t.toString());
Toast.makeText(getActivity(), R.string.enqueue_failure, Toast.LENGTH_LONG).show();
mProgressBar.setVisibility(View.GONE);
}
});
If everything is ok on Android side, which seems it is, you should be able to see the Log statement in isSuccessful() block. otherwise, there might be something wrong with the server.
Let me know if it helped.
Upvotes: 1