I am trying to Access a Json object nested within another Json object. I have written a POJO class but does not allow me to access data:
Here is Json Example:
{
"relationships": {
"competition": {
"data": {
"type": "competitions",
"id": "37"
}
}
},
"attributes": {
"has_league_table": false,
"name": "Round of 16",
"stage": "Round of 16"
},
"type": "rounds",
"id": "881"
},
I want to access the data JSON Object within Relationships->Competitions JSON objects
Here is my POJO Classes:
public class Relationships {
private Competition competition;
public Competition getCompetition ()
{
return competition;
}
public void setCompetition (Competition competition)
{
this.competition = competition;
}
}
Competition POJO
public class Competition {
private Data data;
public Data getData ()
{
return this.data;
}
public void setData (Data data)
{
this.data = data;
}
}
DATA POJO
public class Data {
private String id;
private String type;
public String getId ()
{
return this.id;
}
public void setId (String id)
{
this.id = id;
}
public String getType ()
{
return this.type;
}
public void setType (String type)
{
this.type = type;
}
}
And my Adapter
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder>{
private List<Included> includedData;
public Adapter(List<Included> includedData) {
this.includedData = includedData;
}
#Override
public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int i) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.tvCompetitionName.setText(includedData.get(position).getAttributes().getName());
holder.homeTeam.setText(includedData.get(position).getRelationships().getCompetition().getData().getType());
holder.itemView.setTag(includedData.get(position));
}
#Override
public int getItemCount() {
return includedData.size();
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView tvCompetitionName;
private TextView homeTeam;
private TextView score;
public ViewHolder(View itemView) {
super(itemView);
tvCompetitionName = (TextView) itemView.findViewById(R.id.competitionNameTV);
homeTeam = (TextView) itemView.findViewById(R.id.homeTeamTv);
score = (TextView) itemView.findViewById(R.id.score);
}
}
}
However in my onBindViewHolder
holder.homeTeam.setText(includedData.get(position).getRelationships().getCompetition().getData().getType());
produces error:
java.lang.NullPointerException: Attempt to invoke virtual method 'com.xxx.xxxx.DataModel_Included.Data com.xxxx.xxxx.DataModel_Included.Competition.getData()' on a null object reference
Any help on this?
Related
Recently I have created RecyclerView with Multiple ViewTypes followed this video. In the video the lecturer followed the traditional method of sending data using ArrayList In MainAvtivity. But when I used ViewModel and Retrofit it is not passing any data and nothing show in the screen.
And here an expiation of what I have done.
First:
I have 3 diffrents types of views so I created a 3 model classes for each view called (FirstImageModel,LiveModel,DailyImageModel).
FirstImageModel class -- All other 2 classes have same stretcher.
public class FirstImageModel {
#SerializedName("firstImageUrl")
private String firstImageUrl;
public FirstImageModel(String firstImageUrl) {
this.firstImageUrl = firstImageUrl;
}
public String getFirstImageUrl() {
return firstImageUrl;
}
public void setFirstImageUrl(String firstImageUrl) {
this.firstImageUrl = firstImageUrl;
}
and I have created a fourth class called ItemModel that have type int and Object object.
public class ItemModel {
private int type;
private Object object;
public ItemModel(int type) {
this.type = type;
this.object = object;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
}
Second:
I have created Adapter class called HomeAdapter that extends from RecyclerView and I made 3 classes for eatch view inside the same class HomeAdapter.
public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<ItemModel> items;
public HomeAdapter(List<ItemModel> items) {
this.items = items;
}
public void setHomeList(List<ItemModel> items) {
this.items = items;
notifyDataSetChanged();
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
// Here is types are: 0-FirstImage, 1-Live, 2-DailyImage
if (viewType == 0) {
return new FirstImageViewHolder(
LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_home_container_firstimage,
parent,
false
)
);
} else if (viewType == 1) {
return new LiveViewHolder(
LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_home_container_live,
parent,
false
)
);
} else {
return new DailyImageViewHolder(
LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_home_container_dailyimage,
parent,
false
)
);
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) == 0) {
FirstImageModel firstImageModel = (FirstImageModel) items.get(position).getObject();
((FirstImageViewHolder) holder).setFirstImageData(firstImageModel);
} else if (getItemViewType(position) == 1) {
LiveModel liveModel = (LiveModel) items.get(position).getObject();
((LiveViewHolder) holder).setLiveImageData(liveModel);
} else {
DailyImageModel dailyImageModel = (DailyImageModel) items.get(position).getObject();
((DailyImageViewHolder) holder).setDailyImageData(dailyImageModel);
}
}
#Override
public int getItemCount() {
if(this.items != null) {
return this.items.size();
}
return 0;
}
#Override
public int getItemViewType(int position) {
return items.get(position).getType();
}
/* firstImage Adapter */
static class FirstImageViewHolder extends RecyclerView.ViewHolder {
private ImageView firstImage;
FirstImageViewHolder(#NonNull View itemView) {
super(itemView);
firstImage = itemView.findViewById(R.id.image_home_firstImage);
}
void setFirstImageData(FirstImageModel firstImageModel) {
Glide.with(itemView.getContext())
.load(firstImageModel.getFirstImageUrl())
.into(firstImage);
}
}
/* Live Adapter */
static class LiveViewHolder extends RecyclerView.ViewHolder {
private ImageView liveImage;
LiveViewHolder(#NonNull View itemView) {
super(itemView);
liveImage = itemView.findViewById(R.id.image_home_liveImage);
}
void setLiveImageData(LiveModel liveModel) {
Glide.with(itemView.getContext())
.load(liveModel.getImageLiveInfoUrl())
.into(liveImage);
}
}
/* DailyImage Adapter */
static class DailyImageViewHolder extends RecyclerView.ViewHolder {
private ImageView dailyImage;
DailyImageViewHolder(#NonNull View itemView) {
super(itemView);
dailyImage = itemView.findViewById(R.id.image_home_dailyImage);
}
void setDailyImageData(DailyImageModel dailyImageModel) {
Glide.with(itemView.getContext())
.load(dailyImageModel.getDailyImageUrl())
.into(dailyImage);
}
}
My Problem:
When I use Retrofit to load the data, I don't Know how to pass the 3 views types data to the RecyclerView using ViewModel. My ViewModel class.
public class HomeViewModel extends ViewModel {
private MutableLiveData<List<ItemModel>> homeObjectsList;
private Call<List<ItemModel>> call;
public HomeViewModel(){
homeObjectsList = new MutableLiveData<>();
}
public MutableLiveData<List<ItemModel>> getHomeItemsListObserver() {
return homeObjectsList;
}
public void makeApiCallHome() {
APIServiceHome apiServiceHome = RetroInstanceHome.getRetroClientHome().create(APIServiceHome.class);
call = apiServiceHome.getHomeObjectsList();
call.enqueue(new Callback<List<ItemModel>>() {
#Override
public void onResponse(Call<List<ItemModel>> call, Response<List<ItemModel>> response) {
homeObjectsList.postValue(response.body());
}
#Override
public void onFailure(Call<List<ItemModel>> call, Throwable t) {
homeObjectsList.postValue(null);
}
});
}
Also here's my fragment that should dislay the data in RecyclerView.
public class HomeFragment extends Fragment {
View rootView;
RecyclerView recyclerView;
private List<ItemModel> itemModelList;
private HomeViewModel viewModel;
private HomeAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_home, container, false);
initializeContent();
initializeViewModel();
return rootView;
}
private void initializeContent() {
recyclerView = rootView.findViewById(R.id.recyclerView_home);
recyclerView.setAdapter(new HomeAdapter(itemModelList));
}
private void initializeViewModel() {
ProgressBar progressBar = rootView.findViewById(R.id.progress_bar_home);
viewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
viewModel.getHomeItemsListObserver().observe(getActivity(), new Observer<List<ItemModel>>() {
#Override
public void onChanged(List<ItemModel> itemModels) {
if(itemModels != null) {
progressBar.setVisibility(View.GONE);
itemModelList = itemModels;
adapter.setHomeList(itemModels);
}
}
});
viewModel.makeApiCallHome();
}
I hope this explanation was clear to show the problem. Waiting for your answer
When item is removed from studentList throws:
**java.lang.UnsupportedOperationException
at java.util.AbstractList.remove(AbstractList.java:161)
at com.sayedy.naweed.test.newtest.TestCase$2.onSwiped**
I implemented ItemTouchHelper.Callback as will but leads to same exception.
I can swap studentList items using onMove() without any problem why can't delete item using onSwiped()?
RecyclerView:
public class TestCase extends RecyclerView.Adapter<TestCase.PassedViewHolder> {
private Context context;
private List<Student> studentList;
private ItemTouchHelper itemTouchHelper;
public TestCase(Context context, List<Student> studentList) {
this.context = context;
this.studentList = studentList;
}
public void setItemTouchHelper(ItemTouchHelper itemTouchHelper) {
this.itemTouchHelper = itemTouchHelper;
}
#NonNull
#Override
public PassedViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
StudentPassedRowBinding rowBinding = DataBindingUtil.inflate(
LayoutInflater.from(context),
R.layout.student_passed_row,
parent, false);
return new PassedViewHolder(rowBinding.getRoot());
}
#Override
public void onBindViewHolder(#NonNull PassedViewHolder holder, int position) {
holder.passedRowBinding.setStudent(studentList.get(position));
holder.passedRowBinding.getRoot().setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
itemTouchHelper.startDrag(holder);
return false;
}
});
}
#Override
public int getItemCount() {
return studentList.size();
}
class PassedViewHolder extends RecyclerView.ViewHolder {
public StudentPassedRowBinding passedRowBinding;
public PassedViewHolder(#NonNull View itemView) {
super(itemView);
passedRowBinding = DataBindingUtil.bind(itemView);
}
}
public ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(ItemTouchHelper.DOWN | ItemTouchHelper.UP, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
int currentPosition = viewHolder.getAdapterPosition();
int targetPosition = target.getAdapterPosition();
Collections.swap(studentList, currentPosition,targetPosition);
notifyItemMoved(currentPosition, targetPosition);
return true;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
studentList.remove(viewHolder.getAdapterPosition());
notifyItemRemoved(viewHolder.getAdapterPosition());
}
};
}
The fragment initializes RecyclerView:
public View onCreateView(#NonNull LayoutInflater inflater,
#Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
studentBinding = FragmentStudentBinding.inflate(inflater);
// Data
List<Student> students = Arrays.asList(
new Student("Ahmad", 1, R.drawable.profile, "PASS"),
new Student("Mahmood", 2, R.drawable.profile, "FAIL"),
new Student("Zakir", 3, R.drawable.profile, "PASS"),
new Student("Rezaq", 8, R.drawable.profile, "FAIL"),
new Student("Zeya", 9, R.drawable.profile, "FAIL"),
new Student("Rasool", 10, R.drawable.profile, "FAIL"),
new Student("Parwiz", 11, R.drawable.profile, "FAIL"));
TestCase testCase = new TestCase(getContext(), students);
studentBinding.studentRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
studentBinding.studentRecyclerView.setAdapter(testCase);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(testCase.simpleCallback);
testCase.setItemTouchHelper(itemTouchHelper);
itemTouchHelper.attachToRecyclerView(studentBinding.studentRecyclerView);
return studentBinding.getRoot();
}
Student class:
public class Student implements Parcelable {
private String name;
private int id;
private int studentProfile;
private String result;
public Student(String name, int id, int studentProfile, String result) {
this.name = name;
this.id = id;
this.studentProfile = studentProfile;
this.result = result;
}
protected Student(Parcel in) {
name = in.readString();
id = in.readInt();
studentProfile = in.readInt();
result = in.readString();
}
public static final Creator<Student> CREATOR = new Creator<Student>() {
#Override
public Student createFromParcel(Parcel in) {
return new Student(in);
}
#Override
public Student[] newArray(int size) {
return new Student[size];
}
};
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getStudentProfile() {
return studentProfile;
}
public void setStudentProfile(int studentProfile) {
this.studentProfile = studentProfile;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(id);
dest.writeInt(studentProfile);
dest.writeString(result);
}
}
I solved the problem.
The Arrays.asList() return a fixed-size list.
This list allow you to do operations like get and set, but the add and remove operations will throw UnsupportedOperationException.
I am using spinner in my app I am populating spinner with the data fetching from the server.I am using Retrofit2 as a networking library. There are 2 values I am fetching from the server one is state name and other is state id.
In spinner I am showing state name, but on select state it should select corresponding state name id that I have fetched from the server. In spinner state name is showing successfully but I want to gets corresponding state name id that I have in POJO class and not item position.
Below is my code:
Server response is given below:
{
"data": [
{
"id": "5",
"name": "Bihar"
},
{
"id": "7",
"name": "Chhattisgarh"
},
{
"id": "10",
"name": "Delhi"
}
],
"status": true,
"code": 200
}
States.java
public class States {
#SerializedName("data")
#Expose
private List<AllStates> data = null;
#SerializedName("status")
#Expose
private Boolean status;
#SerializedName("code")
#Expose
private int code;
public States(){
}
public List<AllStates> getData() {
return data;
}
public void setData(List<AllStates> data) {
this.data = data;
}
public Boolean getStatus() {
return status;
}
public void setStatus(Boolean status) {
this.status = status;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
AllStates.java
public class AllStates {
#SerializedName("id")
#Expose
private String id;
#SerializedName("name")
#Expose
private String name;
public AllStates(){
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
CalenderFragment.java
public class CalendarFragment extends Fragment {
Spinner spinnerState;
List<AllStates> stateList = new ArrayList<>();
ArrayList<String> stateSpinnerList = new ArrayList<>();
public CalendarFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_calendar, container, false);
spinnerState = view.findViewById(R.id.spinnerState);
spinnerState.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String item = parent.getItemAtPosition(position).toString();
Toast.makeText(parent.getContext(), "Selected: " + item, Toast.LENGTH_LONG).show();
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
Retrofit retrofit = RetrofitClient.getInstance();
ApiService apiService = retrofit.create(ApiService.class);
apiService.allStates().subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<States>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(States states) {
stateList = states.getData();
stateSpinnerList.add("Select state");
for(int i =0;i<stateList.size();i++){
stateSpinnerList.add(stateList.get(i).getName());
}
ArrayAdapter<String> stateAdapter = new ArrayAdapter<>(getActivity(),android.R.layout.simple_list_item_1,stateSpinnerList);
spinnerState.setAdapter(stateAdapter);
}
#Override
public void onError(Throwable e) {
TastyToast.makeText(getActivity(),e.getMessage(),TastyToast.LENGTH_SHORT,
TastyToast.ERROR).show();
}
#Override
public void onComplete() {
}
});
return view;
}
}
How can I get the desired result?
So what I understand is you are selecting state from Spinner and getting name of state but you want to get stateId.
one possible solution, I can think of is to use HashMap<StateName, StateId> map.
when you receive state name from spinner just call map.get(name) and you will get state Id.
Edit:
you can implement it like this
HashMap<String, Integer> map = new HashMap<>();
for(state in list){
map.put(state.name, state.id);
}
spinnerState.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String name = parent.getItemAtPosition(position).toString();
int id = map.get(name);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
If you don't want to use a custom adapter then fetch selected spinner position and using that position fetch your State model
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// int position = spinnerState.getSelectedItemPosition();
if(position >= 1){
AllStates allStates = stateList.get(position - 1)
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
Now you can access id from allStates model
I am using name and description in RecyclerView.
But name and description has edittext where user can change the name,description and submit the entire fields.
Now question is how to get the entire fields of all items in the recyclerview android?
public static List<CityEvent> getData() {
List<CityEvent> list = new ArrayList<>();
list.add(new CityEvent("Some event", "Some event in London", CityEvent.EVENT_TYPE));
list.add(new CityEvent("Some event", "Some event in London", CityEvent.EVENT_TYPE));
list.add(new CityEvent("Some event", "Some event in London", CityEvent.EVENT_TYPE));
list.add(new CityEvent("Some event", "Some event in London", CityEvent.EVENT_TYPE));
list.add(new CityEvent("Some event", "Some event in London", CityEvent.EVENT_TYPE));
list.add(new CityEvent("Some event", "Some event in London", CityEvent.EVENT_TYPE));
list.add(new CityEvent("Droidcon", "Droidcon in Berlin", CityEvent.EVENT_TYPE));
return list;
}
public class CityEvent {
public static final int EVENT_TYPE = 1;
private String mName;
private String mDescription;
private int mType;
public CityEvent(String name, String description, int type) {
this.mName = name;
this.mDescription = description;
this.mType = type;
}
public String getName() {
return mName;
}
public void setName(String name) {
this.mName = name;
}
public String getDescription() {
return mDescription;
}
public void setDescription(String description) {
this.mDescription = description;
}
public int getType() {
return mType;
}
public void setType(int type) {
this.mType = type;
}
}
So I placed this in edittext fields.
public class DifferentRowAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<CityEvent> mList;
public DifferentRowAdapter(List<CityEvent> list) {
this.mList = list;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
switch (viewType) {
case CITY_TYPE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_city, parent, false);
return new CityViewHolder(view);
case EVENT_TYPE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_event, parent, false);
return new EventViewHolder(view);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
CityEvent object = mList.get(position);
if (object != null) {
switch (object.getType()) {
case EVENT_TYPE:
((EventViewHolder) holder).mTitle.setText(object.getName()); //in edittext i am using name
((EventViewHolder) holder).mDescription.setText(object.getDescription()); //in edittext i am using description.
break;
}
}
}
#Override
public int getItemCount() {
if (mList == null)
return 0;
return mList.size();
}
#Override
public int getItemViewType(int position) {
if (mList != null) {
CityEvent object = mList.get(position);
if (object != null) {
return object.getType();
}
}
return 0;
}
public static class EventViewHolder extends RecyclerView.ViewHolder {
private EditText mTitle;
private EditText mDescription;
public EventViewHolder(View itemView) {
super(itemView);
mTitle = (EditText) itemView.findViewById(R.id.titleTextView);
mDescription = (EditText) itemView.findViewById(R.id.descriptionTextView);
}
}
}
Now question is if i change the edittext fields how to get all items once again to store in array list?
Because i need to send this in array list as POST request parameters.
So how to get all items to send it?
//For eg: POST params:
"cityEvent": [
{
"type": "event"
"title":"london",
"description":"some events"
}
]
MainActivity:
//just pasting the main logic
DifferentRowAdapter adapter = new DifferentRowAdapter(getData());
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, OrientationHelper.VERTICAL, false);
final RecyclerView mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(linearLayoutManager);
//this is imp
mRecyclerView.setNestedScrollingEnabled(false);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.setAdapter(adapter);
I think what you need to do is listen for text change in each of your EditText fields for all ViewHolder objects. You can set the listeners either in onBindViewHolder() or in the constructor of ViewHolder class, in your case EventViewHolder. Then you need to have to ArrayList, one for title and one for description and set them with the initial values that you put into these fields. On any text change, you can update the value in the ArrayList by using TextWatcher's onTextChanged(). When you need to pass all the values, you just need to pass the two ArrayList objects I mentioned above.
This is how your onBindViewHolder() should look like after the line where you have used setText() for your fields. titleData and descriptionData are two ArrayList<String> objects and assumed to be initialized.
titleData.add(object.getName());
descriptionData.add(object.getDescription());
((EventViewHolder)holder).mTitle.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
titleData.remove(position);
titleData.add(position, s.toString());
}
((EventViewHolder)holder).mDescription.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
descriptionData.remove(position);
descriptionData.add(position, s.toString());
}
This question already has an answer here:
Android - null object reference when iterating List
(1 answer)
Closed 5 years ago.
i want parse json with retrofit2 but my code dose not work
this web service is:(please check the webservice):
http://services.groupkt.com/country/search?text=
this is my model class:
public class Country {
#SerializedName("name")
#Expose
private String name;
#SerializedName("alpha2_code")
#Expose
private String alpha2Code;
#SerializedName("alpha3_code")
#Expose
private String alpha3Code;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAlpha2Code() {
return alpha2Code;
}
public void setAlpha2Code(String alpha2Code) {
this.alpha2Code = alpha2Code;
}
public String getAlpha3Code() {
return alpha3Code;
}
public void setAlpha3Code(String alpha3Code) {
this.alpha3Code = alpha3Code;
}
}
And:
public class CountryResponse {
#SerializedName("messages")
#Expose
private List<String> messages = null;
#SerializedName("result")
#Expose
private List<Country> countryList = null;
public List<String> getMessages() {
return messages;
}
public void setMessages(List<String> messages) {
this.messages = messages;
}
public List<Country> getCountryList() {
return countryList;
}
public void setCountryList(List<Country> countryList) {
this.countryList = countryList;
}
}
And:
public class Example {
#SerializedName("RestResponse")
#Expose
private CountryResponse restResponse;
public CountryResponse getRestResponse() {
return restResponse;
}
public void setRestResponse(CountryResponse restResponse) {
this.restResponse = restResponse;
}
}
And this is my interface class:
public interface APIInterface {
#GET("search?text=")
Call<Example> getCountries();
}
And i write 2 classes for return retrofit object:
public class APIClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl) {
if (retrofit == null) {
retrofit = new Retrofit.Builder().baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create()).build();
}
return retrofit;
}
}
public class APIUtils {
public static final String BASE_URL =
"http://services.groupkt.com/country/";
public static APIInterface getSOService() {
return APIClient.getClient(BASE_URL).create(APIInterface.class);
}
}
My Adapter:
public class ResponseAdapter extends
RecyclerView.Adapter<ResponseAdapter.ViewHolder> {
private List<Example> mItems;
private Context mContext;
Example example;
CountryResponse countyResponse;
public ResponseAdapter(Context context, Example example) {
this.example = example;
mContext = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.item_list, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Example example = mItems.get(position);
TextView textView = holder.name;
textView.setText(example.getRestResponse()
.getCountryList().get(position).getName());
TextView textView1 = holder.alpha;
textView1.setText(example.getRestResponse().
getCountryList().get(position).getAl
pha2Code());
TextView textView2 = holder.alpha2;
textView2.setText(example.getRestResponse().
getCountryList().get(position).getAl
pha3Code());
}
#Override
public int getItemCount() {
return mItems.size();
}
public void updateAnswers(CountryResponse countryRes) {
countyResponse = countryRes;
notifyDataSetChanged();
}
private Example getItem(int adapterPosition) {
return mItems.get(adapterPosition);
}
public interface PostItemListener {
void onPostClick(long id);
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView name, alpha, alpha2;
public ViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.name);
alpha = (TextView) itemView.findViewById(R.id.alpha);
alpha2 = (TextView) itemView.findViewById(R.id.alpha2);
}
}
}
And My Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_response);
apiInterface= APIUtils.getSOService();
mRecyclerView= (RecyclerView) findViewById(R.id.my_recycler_view);
mAdapter=new ResponseAdapter(this,new Example());
RecyclerView.LayoutManager layoutManager = new
LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setHasFixedSize(true);
loadAnswers();
}
private void loadAnswers() {
apiInterface.getCountries().enqueue(new Callback<Example>() {
#Override
public void onResponse(Call<Example> call, Response<Example>
response) {
mAdapter.updateAnswers(response.body().getRestResponse());
}
#Override
public void onFailure(Call<Example> call, Throwable t) {
}
});
}
when run a error showing that
'java.util.Iterator java.util.List.iterator()' on a null object reference
You have
#Override
public int getItemCount() {
return mItems.size();
}
public void updateAnswers(CountryResponse countryRes) {
countyResponse = countryRes;
notifyDataSetChanged();
}
Your List is not initialized in the first place. Secondly you need to populate your List with items. And your list must be Country list not of type Example
You need to change to
public void updateAnswers(CountryResponse countryRes) {
mItems.addAll(countryRes.getCountryList())
notifyDataSetChanged();
}
And also initialize the list
List<Country> mItems = new ArrayList();
// note its of type Country not of Example
Finally update your views accordingly in onBindViewHolder
textView.setText(mItems.get(position).getName());
textView1.setText(mItems.get(position).getAlpha2Code());
textView2.setText(mItems.get(position).getAlpha3Code());