Android: Fetch Different Object List Data Using Retrofit - android

I have am trying to fetch Different types of List data using Retrofit.
I have make a List and put data on that.
Can anyone suggest me how I can fetch Different Type of Model Data? I have When I tried to put Object List to my Custom model list I got this error :
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to .....
Model Class
public class WorkType {
#SerializedName("type")
#Expose
private String type;
#SerializedName("worklist")
#Expose
private List<Object> worklist = null;
/**
* No args constructor for use in serialization
*
*/
public WorkType() {
}
/**
*
* #param worklist
* #param type
*/
public WorkType(String type, List<Object> worklist) {
super();
this.type = type;
this.worklist = worklist;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Object> getWorkList() {
return worklist;
}
public void setWorkList(List<Object> worklist) {
this.worklist = worklist;
}
}
Retrofit Interface
#FormUrlEncoded
#POST("worklist")
Call<ArrayList<WorkType>> worklist(
#Field("teamid") String teamID
);
Fragment from where I make a API request
public class WorkTypeListFragment extends Fragment {
private FragmentWorkTypeListBinding binding;
private LoadingDialog loadingDialog;
private Context context;
public WorkTypeListFragment() {
// Required empty public constructor
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
this.context = context;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
binding = DataBindingUtil.inflate(inflater,R.layout.fragment_work_type_list,container,false);
init();
String teamID = getActivity().getIntent().getStringExtra("teamid");
fetchClientDetails("team1");
return binding.getRoot();
}
private void init() {
loadingDialog = new LoadingDialog(getActivity());
}
private void fetchClientDetails(String teamID){
loadingDialog.startLoadingDialog(); // Added Loading Screen
Call<ArrayList<WorkType>> call = RetrofitClient
.getInstance()
.getRetrofitApi()
.worklist(teamID);
call.enqueue(new Callback<ArrayList<WorkType>>() {
#Override
public void onResponse(Call<ArrayList<WorkType>> call, Response<ArrayList<WorkType>> response) {
try{
if(response.code() == 200){
ArrayList<WorkType> workTypeArrayList = response.body();
//Log.d("TAG", "onResponse: "+workTypeArrayList.get(1).getWorkList().get(0).getClientname());
assert workTypeArrayList != null;
bindDataToView(workTypeArrayList);
} else {
Toast.makeText(getContext(), "Response Code is no 200", Toast.LENGTH_SHORT).show();
loadingDialog.dismissDialog();
}
}catch(Exception e){
e.printStackTrace();
}
}
#Override
public void onFailure(Call<ArrayList<WorkType>> call, Throwable t) {
Toast.makeText(getContext(), "Something Went wrong! Please try again later!", Toast.LENGTH_SHORT).show();
loadingDialog.dismissDialog();
}
});
}
private void bindDataToView(ArrayList<WorkType> workTypeArrayList) {
WorkTypesAdapter adapter = new WorkTypesAdapter(context,workTypeArrayList);
binding.workTypeRv.setLayoutManager(new LinearLayoutManager(context));
binding.workTypeRv.setAdapter(adapter);
}
}
RecyclearView Adapter Class
public class WorkTypesAdapter extends RecyclerView.Adapter<WorkTypesAdapter.ViewHolder> {
private Context mCtx;
private List<WorkType> workTypeList;
private final static int survey = 1;
private final static int service = 2;
private final static int maintain = 3;
public WorkTypesAdapter(Context mCtx, List<WorkType> modelServiceList) {
this.mCtx = mCtx;
this.workTypeList = modelServiceList;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mCtx);
View view = inflater.inflate(R.layout.layout_worktype, null);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
WorkType currentWorkType = workTypeList.get(position);
String modelClass = currentWorkType.getType();
List<Object> objectList = currentWorkType.getWorkList();
switch (modelClass){
/*case "survey":
List<SurveyWorkList> surveyWorkLists = new ArrayList<>();
for (Object object : objectList) {
surveyWorkLists.add((SurveyWorkList) object);
holder.workType.setText(currentWorkType.getType());
holder.workTypeCount.setText(surveyWorkLists.size());
}
break;*/
case "service":
List<ServiceWorkList> serviceWorkLists = new ArrayList<>();
for (Object object : objectList) {
serviceWorkLists.add((ServiceWorkList) object);
}
/*holder.workType.setText(currentWorkType.getType());
holder.workTypeCount.setText(serviceWorkLists.size());*/
break;
/*case "maintain":
List<MaintainWorkList> maintainWorkLists = new ArrayList<>();
for (Object object : objectList) {
maintainWorkLists.add((MaintainWorkList) object);
}
holder.workType.setText(currentWorkType.getType());
holder.workTypeCount.setText(maintainWorkLists.size());
break;*/
default:
//Do nothing
}
/*holder.workType.setText(modelService.getType());
holder.workTypeCount.setText(workTypeList.size());*/
}
#Override
public int getItemCount() {
return workTypeList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
TextView workType, workTypeCount;
public ViewHolder(#NonNull View itemView) {
super(itemView);
workType = itemView.findViewById(R.id.work_type_tv);
workTypeCount = itemView.findViewById(R.id.work_type_count_tv);
}
}
}
API response
[
{
"type": "survey",
"worklist": []
},
{
"type": "service",
"worklist": [
{
"serviceid": "HS2020031613054318",
"clientid": "R2020031612594874",
"clientname": "********",
"companyname": "",
"membership": "",
"phone": [
"*********"
],
"**************",
"account": 2,
"slot": "morning",
"orderstatus": "Completed",
"orderstatuscode": "8",
"remarks": ""
}
]
},
{
"type": "maintain",
"worklist": []
}
]
The survey and maintain will have different Parameter.

I have found the answer.
First, you have to make a model class:
#SerializedName("contents")
#Expose
private JsonElement contents = null;
In my API I got an element type. So you know in which type you have to parse the data. Let's say you have three types. So we will create a Type object:
switch(type)
case 1:
Type type = new TypeToken<ArrayList<Banner>>() {
}.getType();
ArrayList<Banner> bannerList = new Gson().fromJson(baseModel.getContents(), type);

Related

Recycleview not populated with JSON and Retrofit?

I am making a simple app in which the user will able to search for books by its name, with google.com book api. For now, I wish to present a list of books with android in their name. I am doing it with Retrofit2 and RecycleView, but nothing is showing.
MainActivity:
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
KnjigaAdapter knjigaAdapter;
List<KnjigaModel> listaKnjiga;
public static final String BASE_URL = "https://www.googleapis.com/books/";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
uzmiKomentare();
}
public void uzmiKomentare() {
Gson gson = new GsonBuilder().serializeNulls().create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
KnjigaApi knjigaApi = retrofit.create(KnjigaApi.class);
final Call<KnjigaModel> pozivZaListuKnjiga = knjigaApi.getKnjige("android");
pozivZaListuKnjiga.enqueue(new Callback<KnjigaModel>() {
#Override
public void onResponse(Call<KnjigaModel> call, Response<KnjigaModel> response) {
if (!response.isSuccessful()) {
return;
}
//generateRecycleView(WHAT TO PUT HERE!!!!);
}
#Override
public void onFailure(Call<KnjigaModel> call, Throwable t) {
Log.d("MainActivity:", t.getMessage());
}
});
}
private void generateRecycleView(List<KnjigaModel> knjige) {
listaKnjiga = new ArrayList<>();
recyclerView = findViewById(R.id.recycleview);
knjigaAdapter = new KnjigaAdapter(this, knjige);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(knjigaAdapter);
if (knjigaAdapter.getItemCount() == 0){
Log.i("List is empty: ","YES");
}
else {
Log.i("list is empty: ","No");
}
}
}
api inteface:
public interface KnjigaApi {
#GET("v1/volumes")
Call<KnjigaModel> getKnjige(#Query("q") String knjiga);
}
model class:
public class KnjigaModel {
#SerializedName("title")
#Expose
private String imeKnjige;
#SerializedName("authors")
#Expose
private String imeAutora;
#SerializedName("thumbnail")
#Expose
private String slikaKnjige;
public KnjigaModel(String imeKnjige, String imeAutora,String slikaKnjige) {
this.imeKnjige = imeKnjige;
this.imeAutora = imeAutora;
this.slikaKnjige = slikaKnjige;
}
public String getImeKnjige() {
return imeKnjige;
}
public String getImeAutora() {
return imeAutora;
}
public String getSlikaKnjige() {
return slikaKnjige;
}
}
and my adapter:
public class KnjigaAdapter extends RecyclerView.Adapter<KnjigaAdapter.KomentariViewHolder> {
private List<KnjigaModel> listaKnjiga;
private LayoutInflater inflater;
private Context context;
public KnjigaAdapter(Context context, List<KnjigaModel> listaKnjiga) {
this.listaKnjiga = listaKnjiga;
this.context = context;
}
#Override
public KomentariViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
inflater = LayoutInflater.from(context);
// Inflate the custom layout
View postView = inflater.inflate(R.layout.single_item, parent, false);
// Return a new holder instance
return new KomentariViewHolder(postView);
}
#Override
public void onBindViewHolder(KomentariViewHolder holder, int position) {
KnjigaModel knjige = listaKnjiga.get(position);
holder.naslovKnjige.setText(knjige.getImeKnjige());
holder.imeAutora.setText(knjige.getImeAutora());
Glide.with(context)
.load(knjige.getSlikaKnjige())
.into(holder.slikaKnjige);
}
#Override
public int getItemCount() {
return listaKnjiga.size();
}
public class KomentariViewHolder extends RecyclerView.ViewHolder {
private TextView naslovKnjige;
private TextView imeAutora;
private ImageView slikaKnjige;
public KomentariViewHolder(View itemView) {
super(itemView);
naslovKnjige = itemView.findViewById(R.id.ime_knjige);
imeAutora = itemView.findViewById(R.id.autor_knjige);
slikaKnjige = itemView.findViewById(R.id.sika_korica);
}
}
}
my JSON format:
https://www.googleapis.com/books/v1/volumes?q=android
First of all, I strongly recommend to use RxJava for asynchronous requests, though it's totally optional.
Your Problem:
Your "getKnjige" Method returns only ONE Model, though the endpoint is named volumes (plural), you need to wrap your KnjigaModel in a class like
data class KnjigaResponse(val items: List<KnjigaModel>)
(Kotlin for simplicity, you can also generate a Java class with a single member volumes member that holds a list of KnjigaModel)
In addition, your model is wrong. authors is not a string, but a List of Strings, and "thumbnail" is wrapped in an "imageLinks" Object, and title is wrapped in a volumeInfo Object.
Your retrofit interface then would look like this:
public interface KnjigaApi {
#GET("v1/volumes")
Call<KnjigaResponse> getKnjige(#Query("q") String knjiga);
Request:
final Call<KnjigaResponse> pozivZaListuKnjiga = knjigaApi.getKnjige("android");
pozivZaListuKnjiga.enqueue(new Callback<KnjigaResponse>() {
#Override
public void onResponse(Call<KnjigaResponse> call, Response<KnjigaResponse> response) {
if (!response.isSuccessful()) {
return;
}
generateRecycleView(response.items);
}
#Override
public void onFailure(Call<KnjigaResponse> call, Throwable t) {
Log.d("MainActivity:", t.getMessage());
}
});

How to parse this json objects on recyclerview? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I want to show this json in recyclerview. how can I do it?
I just want to list "user" and "exchangeName".
My Json;
{
"events": {
"101": {
"id": "0001",
"type": "exchange",
"user": "BTUser01",
"exchangeName": "BTCTurk",
"transactions": {
"send": "249",
"get": "24.1"
},
"certificate": [
"BTUser01Certificate"
]
},
"102": {
"id": "0002",
"type": "exchange",
"user": "BTUser02",
"exchangeName": "Koinim",
"transactions": {
"send": "300",
"get": "641"
},
"certificate": [
"BTUser02Certificate"
]
},
"103": {
"id": "0003",
"type": "exchange2",
"user": "BTUser03",
"exchangeName": "Koineks",
"transactions": {
"send": "823",
"get": "751"
},
"certificate": [
"BTUser03Certificate"
]
},
"104": {
"id": "0004",
"type": "exchange3",
"user": "BTUser04",
"exchangeName": "Paribu",
"transactions": {
"send": "543",
"get": "3.1"
},
"certificate": [
"BTUser04Certificate"
]
}
}
}
MainActivity;
public class MainActivity extends AppCompatActivity {
TextView ev, ev2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ev = (TextView) findViewById(R.id.ev);
ev2 = (TextView) findViewById(R.id.ev2);
Retrofit retrofit = new Retrofit.Builder().baseUrl("MYAPİ_ADRESS_LINK").addConverterFactory(GsonConverterFactory.create()).build();
Service service = retrofit.create(Service.class);
Call<ResponseBody> call = service.getData();
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(#NonNull Call<ResponseBody> call, #NonNull Response<ResponseBody> response) {
if (response.isSuccessful()) {
String res = null;
if (response.body() != null) {
try {
res = response.body().string();
parse(res);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
#Override
public void onFailure(#NonNull Call<ResponseBody> call, #NonNull Throwable t) {
int a = 0;
}
});
}
Model parse(String str) {
Model model = new Model();
try {
String source = str.replace("\n", "").replace("\t", "").replace("\r", "");
String s = new Gson().toJson(source);
s = s.replace("\\","");
s = s.substring(1,s.length()-1);
JSONObject object = new JSONObject(s).getJSONObject("events");
Iterator<String> iter = object.keys();
while (iter.hasNext()) {
String key = iter.next();
try {
JSONObject value = new JSONObject(String.valueOf(object.get(key)));
model.setExternalId(Integer.parseInt(key));
model.setUser(value.getString("user"));
model.setSend(value.getString("send"));
ev.setText(model.user);
ev2.setText(model.send);
return model;
} catch (JSONException e) {
// Something went wrong!
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return model;
}
}
My Model;
public class Model {
int externalId;
int id;
String type;
String user;
String exchangeName;
Transactions transactions;
List<certificate> certificateList;
public int getExternalId() {
return externalId;
}
public void setExternalId(int externalId) {
this.externalId = externalId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getExchangeName() {
return exchangeName;
}
public void setExchangeName(String exchangeName) {
this.exchangeName = exchangeName;
}
public Transactions getTransactions() {
return transactions;
}
public void setTransactions(Transactions transactions) {
this.transactions = transactions;
}
public List<certificate> getCertificateList() {
return certificateList;
}
public void setCertificateList(List<certificate> certificateList) {
this.certificateList = certificateList;
}
class Transactions{
String send;
String get;
public String getSend() {
return send;
}
public void setSend(String send) {
this.send = send;
}
public String getGet() {
return get;
}
public void setGet(String get) {
this.get = get;
}
}
class certificate{
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
First of all you could have found this answer easily in the hundreds of tutorials and guides available.
To achieve this you will need to create a custom adapter and a custom view for the adapter item.
To preface this answer. I wasn't sure if you want to show multiple Model items in the RecyclerView, or some other data. This example assumes that you use a List<Model>, however, it's an easy change to make it work with another list of objects.
Example of how the adapter could look like
public class MyAdapter extends RecyclerView.Adapter
{
private Context _context;
private List<Model> _items;
public void setItems(List<Model> items)
{
this._items = items;
notifyDataSetChanged();
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType)
{
_context = parent.getContext();
return new MyAdapter.ItemViewHolder(parent);
}
#Override
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, int position)
{
final MyAdapter.ItemViewHolder viewHolder = (MyAdapter.ItemViewHolder) holder;
final Model item = _items.get(position);
viewHolder._user.setText(item.user);
viewHolder._exchangeName.setText(item.exchangeName);
}
#Override
public int getItemCount()
{
return _items != null ? _items.size() : 0;
}
private static class ItemViewHolder extends RecyclerView.ViewHolder
{
private TextView _user;
private TextView _exchangeName;
private ItemViewHolder(ViewGroup parent)
{
super(LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_view, parent, false));
this._user = itemView.findViewById(R.id.user);
this._exchangeName = itemView.findViewById(R.id.exchange_name);
}
}
}
R.layout.adapter_view
This needs to be a view containing at least the two TextView views references from the MyAdapter above. Simple example:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#drawable/content_container"
android:orientation="vertical"
android:animateLayoutChanges="true"
android:padding="#dimen/padding_view_large"
android:layout_marginBottom="#dimen/padding_view_small">
<TextView
android:id="#+id/user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/placeholder"
android:textColor="#color/black"
android:textSize="#dimen/text_size_medium"
android:layout_marginTop="#dimen/padding_view_small"/>
<TextView
android:id="#+id/exchange_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/placeholder"
android:textColor="#color/black"
android:textSize="#dimen/text_size_medium"
android:layout_marginTop="#dimen/padding_view_small"/>
</LinearLayout>
Binding the adapter
//First we set up the adapter and add our List<Model> object.
MyAdapter adapter = new MyAdapter();
adapter.setItems(... List<Model> items);
//Set up our RecyclerView and set the adapter.
final RecyclerView recyclerView = rootView.findViewById(R.id.model_list);
recyclerView.setLayoutManager(new LinearLayoutManager(_context));
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
You need to first understand (and later create) the following things
RecyclerView Adapter
RecyclerView ViewHolder
After you read up on those two things the solution will be pretty clear. Just to point you in the right direction, you will have to create a custom adapter which you will use to populate your custom viewholders. Hope this helps get you going. Feel free to ask if you need any more help in this.

Android Retrofit 2.1.0 Response.body() is null, status code is 404

I am trying to make a call to this api and am having difficulty as the response.body() is returning null.
http://demo.museum.vebrary.vn/api/stuff/getall
I want to get stuff name of list and show to my recyclerview.
My model:
public class SOAnswersResponse {
#SerializedName("StuffModels")
#Expose
private List<StuffModel> stuffModels = null;
public List<StuffModel> getStuffModels() {
return stuffModels;
}
public void setStuffModels(List<StuffModel> stuffModels) {
this.stuffModels = stuffModels;
}
and
public class StuffModel {
#SerializedName("STUFFID")
#Expose
private Integer sTUFFID;
#SerializedName("STUFFCODE")
#Expose
private String sTUFFCODE;
#SerializedName("STUFFNAME")
#Expose
private String sTUFFNAME;
#SerializedName("STUFFNOTE")
#Expose
private String sTUFFNOTE;
#SerializedName("STUFFORDER")
#Expose
private Integer sTUFFORDER;
#SerializedName("CUSTOMERID")
#Expose
private String cUSTOMERID;
#SerializedName("EXHIBITS")
#Expose
private List<Object> eXHIBITS = null;
Json response
{
"StuffModels":[
{
"STUFFID":2,
"STUFFCODE":"Gi",
"STUFFNAME":"Giấy",
"STUFFNOTE":"",
"STUFFORDER":2,
"CUSTOMERID":"CAMAU",
"EXHIBITS":[
]
},
ApiUtils Class
public class ApiUtils {
private ApiUtils() {
}
public static final String BASE_URL = "http://demo.museum.vebrary.vn/api/";
public static SOService getSOService() {
return RetrofitClient.getClient(BASE_URL).create(SOService.class);
}
}
Service interface
public interface SOService {
#GET("/stuff/getall")
Call<SOAnswersResponse> getAnswers();
}
RetrofitClient Class
public class RetrofitClient {
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;
}
}
My RecyclerView adapter
public class CategogyNameRecyclerViewAdapter extends RecyclerView.Adapter<CategogyNameRecyclerViewAdapter.ViewHolder> {
private List<StuffModel> mItems;
private Context mContext;
private PostItemListener mItemListener;
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public TextView titleTv;
PostItemListener mItemListener;
public ViewHolder(View itemView, PostItemListener postItemListener) {
super(itemView);
titleTv = itemView.findViewById(R.id.tvListMenuCategogy);
this.mItemListener = postItemListener;
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
StuffModel item = getItem(getAdapterPosition());
this.mItemListener.onPostClick(item.getSTUFFID());
notifyDataSetChanged();
}
}
public CategogyNameRecyclerViewAdapter(Context context, List<StuffModel> posts, PostItemListener itemListener) {
mItems = posts;
mContext = context;
mItemListener = itemListener;
}
#Override
public CategogyNameRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View postView = inflater.inflate(R.layout.item_list_text, parent, false);
ViewHolder viewHolder = new ViewHolder(postView, this.mItemListener);
return viewHolder;
}
#Override
public void onBindViewHolder(CategogyNameRecyclerViewAdapter.ViewHolder holder, int position) {
StuffModel item = mItems.get(position);
TextView textView = holder.titleTv;
textView.setText(item.getSTUFFNAME());
}
#Override
public int getItemCount() {
return mItems.size();
}
public void updateAnswers(List<StuffModel> items) {
mItems = items;
notifyDataSetChanged();
}
private StuffModel getItem(int adapterPosition) {
return mItems.get(adapterPosition);
}
public interface PostItemListener {
void onPostClick(long id);
}
}
And my main activity
public class Testttt extends AppCompatActivity {
private CategogyNameRecyclerViewAdapter mAdapter;
private RecyclerView mRecyclerView;
private SOService mService;
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView(R.layout.test );
mService = ApiUtils.getSOService();
mRecyclerView = (RecyclerView) findViewById(R.id.rcvCategogyNameMenuTest);
mAdapter = new CategogyNameRecyclerViewAdapter(this, new ArrayList<StuffModel>(0), new CategogyNameRecyclerViewAdapter.PostItemListener() {
#Override
public void onPostClick(long id) {
Toast.makeText(Testttt.this, "Post id is" + id, Toast.LENGTH_SHORT).show();
}
});
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setHasFixedSize(true);
RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST);
mRecyclerView.addItemDecoration(itemDecoration);
loadAnswers();
}
public void loadAnswers() {
mService.getAnswers().enqueue(new Callback<SOAnswersResponse>() {
#Override
public void onResponse(Call<SOAnswersResponse> call, Response<SOAnswersResponse> response) {
Toast.makeText(Testttt.this, "333333333333333333"+response.body(), Toast.LENGTH_SHORT).show();
if(response.isSuccessful()) {
mAdapter.updateAnswers(response.body().getStuffModels());
Log.d("AnswersPresenter", "posts loaded from API");
}else {
int statusCode = response.code();
}
}
#Override
public void onFailure(Call<SOAnswersResponse> call, Throwable t) {
showErrorMessage();
Log.d("AnswersPresenter", "error loading from API");
}
});
}
public void showErrorMessage() {
Toast.makeText(this, "Error loading posts", Toast.LENGTH_SHORT).show();
}
}
The first thing that came in my mind:
Your
public static final String BASE_URL = "http://demo.museum.vebrary.vn/api/";
has a "/" at the the end and your
#GET("/stuff/getall")
Call<SOAnswersResponse> getAnswers();
starts with a "/". So there is a double backslash in the url that might leads to the 404 code. Does this solve the problem?
When i call your URL i receive XML. Maybe the API is not configured correctly?
Change your Service interface
public interface SOService {
#GET("stuff/getall")
Call<SOAnswersResponse> getAnswers();
}
it occurred because you have use start with backslash it already added in your base url

JSON was parse successfully but return a null data

Good day, I was watching an android tutorial.I followed it until it displayed the data successfully in the tutorial. but when I run my application it successfully parses the JSON response but it returns a null value when I try to display it.
This is my code
EstablishmentData.java
public class EstablishmentData implements Serializable {
public String estabName;
public String estabType;
public String estabAddress;
public String estabImage;
}
EstablishmentAdapter.java
public class EstablishmentAdapter extends RecyclerView.Adapter<EstablishmentAdapter.EstablishementViewHolder>{
private Context context;
private ArrayList<EstablishmentData> establishmentList;
public EstablishmentAdapter(Context context, ArrayList<EstablishmentData> establishmentList){
this.context= context;
this.establishmentList= establishmentList;
}
#Override
public EstablishementViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater= LayoutInflater.from(parent.getContext());
View view= inflater.from(parent.getContext()).inflate(R.layout.card_item, parent, false);
EstablishementViewHolder estabHolder = new EstablishementViewHolder(view);
return estabHolder;
}
#Override
public void onBindViewHolder(EstablishementViewHolder holder, int position) {
EstablishmentData establishmentData= establishmentList.get(position);
String image_url= "http://10.0.3.2/blowOut/" + establishmentData.estabImage;
Picasso.with(context)
// .load(establishmentData.estabImage)
.load(image_url)
.placeholder(R.drawable.blowout)
.error(android.R.drawable.stat_notify_error)
.into(holder.estabImage);
holder.estabName.setText(establishmentData.estabName);
holder.estabName.setTextColor(Color.rgb(255,0,0));
holder.estabAddress.setText(establishmentData.estabAddress);
holder.estabAddress.setTextColor(Color.rgb(255,0,0));
Log.d("Estab Adapter","Establishment logo: " +image_url);
Log.d("Estab Adapter","Establishment name: " +establishmentData.estabName);
Log.d("Estab Adapter","Establishment address: " +establishmentData.estabAddress);
}
#Override
public int getItemCount() {
if(establishmentList != null){
return establishmentList.size();
}
return 0;
}
//This is the ViewHolder class
public static class EstablishementViewHolder extends RecyclerView.ViewHolder{
public CardView cvItem;
public ImageView estabImage;
public TextView estabName;
public TextView estabAddress;
public EstablishementViewHolder(View itemView) {
super(itemView);
cvItem = itemView.findViewById(R.id.cvItem);
estabImage = itemView.findViewById(R.id.estabImage);
estabName = itemView.findViewById(R.id.estabName);
estabAddress = itemView.findViewById(R.id.estabAddress);
}
}
}
EstablishmentFragment.java
public class EstablishmentFragment extends Fragment {
final String TAG= "EstablishmentFragment";
RecyclerView rvItem;
CardView cvItem;
public EstablishmentFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_establishment, container, false);
rvItem= rootView.findViewById(R.id.rv_recycler_view_fragment_accounts); //fragment_establishment.xml-> rvItem
rvItem.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
rvItem.setLayoutManager(llm);
StringRequest stringRequest= new StringRequest(Request.Method.GET, AppConfig.URL_ESTABLISHMENT,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d(TAG, response);
ArrayList<EstablishmentData> establishmentData = new JsonConverter<EstablishmentData>()
.toArrayList(response, EstablishmentData.class);
EstablishmentAdapter adapter= new EstablishmentAdapter(getContext(), establishmentData);
rvItem.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if(error != null){
Log.d(TAG, error.getMessage());
Toast.makeText(getActivity(), "Something went wrong", Toast.LENGTH_SHORT);
}
}
}
);
MySingleton.getInstance(getContext()).addToRequestQueue(stringRequest);
return rootView;
}
}
JsonConverter.class
public class JsonConverter<T> {
public JsonConverter() {
}
public ArrayList<T> toArrayList(String jsonString, Class<T> clazz) {
GsonBuilder builder = new GsonBuilder();
builder.setDateFormat("dd/MM/yy HH:mm:ss");
Gson gson = builder.create();
Type type = new JsonConverter.ListParameterizedType(clazz);
ArrayList<T> list = (ArrayList)gson.fromJson(jsonString, type);
return list;
}
public List<T> toList(String jsonString, Class<T> clazz) {
List<T> list = this.toArrayList(jsonString, clazz);
return list;
}
private static class ListParameterizedType implements ParameterizedType {
private Type type;
private ListParameterizedType(Type type) {
this.type = type;
}
public Type[] getActualTypeArguments() {
return new Type[]{this.type};
}
public Type getRawType() {
return ArrayList.class;
}
public Type getOwnerType() {
return null;
}
}
}
JSON
[{
"name": "Lechon-nan",
"type": "Lechon",
"address": "Lechon street",
"image": "jollibee.png"
}, {
"name": "Lechon",
"type": "Lechon",
"address": "Lechon",
"image": "mcdo.png"
}]
Logcat
Adapter: Establishment image: http://10.0.3.2/blowOut/null
Adapter: Establishment address: null
Adapter: Establishment name: null
Use same name for variable in your pojo class like same as in Json key
public class EstablishmentData implements Serializable {
public String name;
public String type;
public String address;
public String image;
}
Like this.

RecyclerView reload same data when refresh

I have a problem, when i swipe to refresh the data, the first swipe is ok but after that every swipe reload and add the same data over and over again, by the end i have a list with same items over and over... I'm using a loader.
I tried to clear before but i don't understand what's wrong with my code, if someone could explain it to me. Thank You.
Here my code :
public abstract class NewsFragment extends Fragment implements LoaderManager.LoaderCallbacks<ArrayList<Articles>> {
protected ItemAdapter mArticleAdapter;
protected RecyclerView mRecyclerView;
protected NewsFragment.OnNewSelectedInterface mListener;
protected RecyclerView.LayoutManager mManager;
protected SwipeRefreshLayout mSwipeRefreshLayout;
protected LoaderManager mLoaderManager;
private boolean mStateSaved;
private static final int NEWS_LOAD_ID = 1;
public static final String KEY_LIST = "key_list";
public interface OnNewSelectedInterface {
void onListNewSelected(int index, ArrayList<Articles> articles);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.list_present_news, container, false);
mListener = (NewsFragment.OnNewSelectedInterface) getActivity();
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeContainer);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
mManager = new LinearLayoutManager(getActivity());
mArticleAdapter = new ItemAdapter(getActivity(), new ArrayList<Articles>(), mListener);
mLoaderManager = getLoaderManager();
mStateSaved = mArticleAdapter.isStateSaved();
mRecyclerView.setAdapter(mArticleAdapter);
mRecyclerView.setLayoutManager(mManager);
getData();
refreshData();
if(!isNetworkAvailable())alertUserAboutError();
setDivider();
return view;
}
private void setDivider() {
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView
.getContext(), DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
}
private void getData() {
getLoaderManager().initLoader(NEWS_LOAD_ID, null, this).forceLoad();
}
private void alertUserAboutError() {
AlertDialogFragment alertDialogFragment = new AlertDialogFragment();
alertDialogFragment.show(getActivity().getFragmentManager(), "error_dialog");
}
protected abstract String[] getUrl();
private boolean isNetworkAvailable() {
ConnectivityManager manager = (ConnectivityManager)
getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
boolean isAvailable = false;
if (networkInfo != null && networkInfo.isConnected()) {
isAvailable = true;
}
return isAvailable;
}
private void refreshData() {
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
mArticleAdapter.clear();
mSwipeRefreshLayout.setRefreshing(false);
}
});
mSwipeRefreshLayout.setColorSchemeResources(
android.R.color.holo_orange_light,
android.R.color.holo_red_light);
}
#Override
public Loader<ArrayList<Articles>> onCreateLoader(int id, Bundle args) {
return new NewsLoader(getActivity(), getUrl());
}
#Override
public void onLoadFinished(Loader<ArrayList<Articles>> loader, ArrayList<Articles> data) {
if (data != null && !data.isEmpty()) {
mArticleAdapter.addAll(data);
}
}
#Override
public void onLoaderReset(Loader<ArrayList<Articles>> loader) {
mArticleAdapter.clear();
}
}
My loader class :
public class NewsLoader extends AsyncTaskLoader<ArrayList<Articles>>{
private ArrayList<Articles> mArticlesArrayList;
private String[] mUrl;
public NewsLoader(Context context, String[] url) {
super(context);
mUrl = url;
}
#Override
public ArrayList<Articles> loadInBackground() {
OkHttpClient mClient = new OkHttpClient();
for (String aMUrl : mUrl) {
Request mRequest = new Request.Builder().url(aMUrl).build();
try {
Response response = mClient.newCall(mRequest).execute();
try {
if (response.isSuccessful()) {
String json = response.body().string();
getMultipleUrls(json);
}
} catch (IOException | JSONException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return mArticlesArrayList;
}
private void getMultipleUrls(String jsonData) throws JSONException {
if (mArticlesArrayList == null) {
mArticlesArrayList = getArticleForecast(jsonData);
} else {
mArticlesArrayList.addAll(getArticleForecast(jsonData));
}
}
private ArrayList<Articles> getArticleForecast(String jsonData) throws JSONException {
JSONObject forecast = new JSONObject(jsonData);
JSONArray articles = forecast.getJSONArray("articles");
ArrayList<Articles> listArticles = new ArrayList<>(articles.length());
for (int i = 0; i < articles.length(); i++) {
JSONObject jsonArticle = articles.getJSONObject(i);
Articles article = new Articles();
String urlImage = jsonArticle.getString("urlToImage");
article.setTitle(jsonArticle.getString("title"));
article.setDescription(jsonArticle.getString("description"));
article.setImageView(urlImage);
article.setArticleUrl(jsonArticle.getString("url"));
listArticles.add(i, article);
}
return listArticles;
}
}
My Adapter class :
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ArticleViewHolder> {
private static final String TAGO = ItemAdapter.class.getSimpleName();
private final NewsFragment.OnNewSelectedInterface mListener;
private ArrayList<Articles> mArticlesList;
private Context mContext;
private int lastPosition = -1;
private boolean mStateSaved = false;
public boolean isStateSaved() {
return mStateSaved;
}
public void setStateSaved(boolean stateSaved) {
mStateSaved = stateSaved;
}
public ItemAdapter(Context context, ArrayList<Articles> articles, NewsFragment.OnNewSelectedInterface listener){
mContext = context;
mArticlesList = articles;
mListener = listener;
}
#Override
public ArticleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_card_view, parent, false);
ArticleViewHolder articleViewHolder = new ArticleViewHolder(view);
articleViewHolder.setIsRecyclable(false);
return articleViewHolder;
}
#Override
public void onBindViewHolder(ArticleViewHolder holder, int position) {
holder.bindArticle(mArticlesList.get(holder.getAdapterPosition()));
setAnimation(holder.itemView, holder.getAdapterPosition());
}
private void setAnimation(View viewToAnimate, int position) {
if (position > lastPosition) {
Animation animation = AnimationUtils.loadAnimation(viewToAnimate.getContext(), android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
#Override
public int getItemCount() {
return mArticlesList.size();
}
public void clear() {
mArticlesList.clear();
notifyDataSetChanged();
}
public void addAll(ArrayList<Articles> articles) {
mArticlesList.addAll(articles);
notifyDataSetChanged();
}
protected class ArticleViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private ImageView mImageView;
private TextView mTitleTextView, mDescriptionTextView;
private FloatingActionButton mSaveButton;
private ArticleViewHolder(View itemView) {
super(itemView);
mImageView = (ImageView) itemView.findViewById(R.id.photoImageView);
mTitleTextView = (TextView) itemView.findViewById(R.id.titleWithoutImage);
mDescriptionTextView = (TextView) itemView.findViewById(R.id.descriptionTextView);
mSaveButton = (FloatingActionButton) itemView.findViewById(R.id.floatingActionButton);
itemView.setOnClickListener(this);
}
private void bindArticle(final Articles article) {
Glide.with(mContext).load(article.getImageView()).into(mImageView);
mTitleTextView.setText(article.getTitle());
mDescriptionTextView.setText(article.getDescription());
if(mDescriptionTextView.getText().equals("")){
mDescriptionTextView.setVisibility(View.GONE);
}
mSaveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
insertArticle(article);
article.setStateSaved(true);
}
});
Log.v(TAGO, "Item id : " + getItemId()
+ "Item count : " + getItemCount()
+ "Item position : " + getAdapterPosition()
+ String.valueOf(article.isStateSaved()));
}
private void insertArticle(Articles articles) {
String title = articles.getTitle();
String description = articles.getDescription();
String url = articles.getArticleUrl();
ContentValues contentValues = new ContentValues();
contentValues.put(ArticleContract.ArticleEntry.COLUMN_TITLE_ARTICLE, title);
contentValues.put(ArticleContract.ArticleEntry.COLUMN_DESCRIPTION_ARTICLE, description);
contentValues.put(ArticleContract.ArticleEntry.COLUMN_URL_ARTICLE, url);
Uri uri = mContext.getContentResolver().insert(ArticleContract.ArticleEntry.CONTENT_URI, contentValues);
if(uri == null) {
Log.v(TAGO, "Error");
} else Toast.makeText(mContext, "Article Saved", Toast.LENGTH_SHORT).show();
}
#Override
public void onClick(View view) {
mListener.onListNewSelected(getLayoutPosition(), mArticlesList);
}
}
}
You are using ViewHolder#setIsRecyclable incorrectly; this method is meant to be used to prevent a ViewHolder from being recycled only while changes are being made to it. According to the documentation:
Calls to setIsRecyclable() should always be paired (one call to
setIsRecyclabe(false) should always be matched with a later call to
setIsRecyclable(true)).
This means none of your ViewHolder objects will be recycled, effectively making the use of a RecyclerView worthless, and preventing it from reusing the views when you attempt to bind new objects to your RecyclerView.
So, in short, remove that line of code.
I noticed a few other small issues with your adapter code as well, which can cause a multitude headaches in the future; so I took the liberty of highlighting some of the changes I would make.
Just for my own sanity, I will refer to your Articles class as Article.
It is usually not a good idea to pass around your Context all over the place. The View passed to your ViewHolder already has a reference to a Context, so you can use that instead.
As for the insertArticle() code, the Activity should be handling this anyway. So you can pass the Article back to the Activity by passing a listener to your Adapter (and subsequently, each ViewHolder) instead of the Context.
You should also consider using the DiffUtil class instead of just calling notifyDataSetChanged(); it is much more efficient. Just make sure your Article class is implementing equals() and hashCode() or it will not work.
I didn't include the animation code (that can easily be added back in) or the saved state code (mostly because I don't know what you were trying to do).
public class ArticleAdapter extends RecyclerView.Adapter<Article> {
private List<Article> mData;
private ArticleViewHolder.OnSelectedListener mOnSelectedListener;
private ArticleViewHolder.OnSaveListener mOnSaveListener;
public ArticleAdapter(ArticleViewHolder.OnSelectedListener onSelectedListener, ArticleViewHolder.OnSaveListener onSaveListener) {
mOnSelectedListener = onSelectedListener;
mOnSaveListener = onSaveListener;
mData = new ArrayList<>();
}
public void replaceData(final List<Article> data) {
final List<Article> oldData = new ArrayList<>(mData);
mData.clear();
if (data != null) {
mData.addAll(data);
}
DiffUtil.calculateDiff(new DiffUtil.Callback() {
#Override
public int getOldListSize() {
return oldData.size();
}
#Override
public int getNewListSize() {
return mData.size();
}
#Override
public int areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldData.get(oldItemPosition).equals(mData.get(newItemPosition));
}
#Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldData.get(oldItemPosition).equals(mData.get(newItemPosition));
}
}).dispatchUpdatesTo(this);
}
#Override
public ArticleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_card_view, parent, false);
return new SelectLocationViewHolder(view, mOnSelectedListener, mOnSaveListener);
}
#Override
public void onBindViewHolder(ArticleViewHolder holder, int position) {
holder.bind(mData.get(position));
}
#Override
public int getItemCount() {
return mData.size();
}
}
public class ArticleViewHolder extends RecyclerView.ViewHolder {
public interface OnSelectedListener {
void onSelected(Article article);
}
public interface OnSaveListener {
void onSave(Article article);
}
private View mView;
private Article mArticle;
private OnSelectedListener mOnSelectedListener;
private OnSaveListener mOnSaveListener;
private ImageView mImageView;
private TextView mTitleTextView, mDescriptionTextView;
private FloatingActionButton mSaveButton;
public ArticleViewHolder(View itemView, final OnSelectedListener onSelectedListener, final OnSaveListener onSaveListener) {
super(itemView);
mImageView = (ImageView) itemView.findViewById(R.id.photoImageView);
mTitleTextView = (TextView) itemView.findViewById(R.id.titleWithoutImage);
mDescriptionTextView = (TextView) itemView.findViewById(R.id.descriptionTextView);
mSaveButton = (FloatingActionButton) itemView.findViewById(R.id.floatingActionButton);
mView = itemView;
mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onSelectedListener.onSelected(mArticle);
}
});
mSaveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onSaveListener.onSave(mArticle);
}
});
}
public void bind(Article article) {
mArticle = article;
mTitleTextView.setText(article.getTitle());
mDescriptionTextView.setText(article.getDescription());
if(TextUtils.isEmpty(article.getDescription())) {
mDescriptionTextView.setVisibility(View.GONE);
}
Glide.with(mView.getContext()).load(article.getImage()).into(mImageView);
}
}
Edit
The actual issue is that your loader uses the same ArrayList every time, and keeps adding the new results to it.
public class NewsLoader extends AsyncTaskLoader<List<Article>> {
private final String[] mUrls;
private final OkHttpClient mClient;
public NewsLoader(Context context, OkHttpClient client, String... urls) {
super(context);
mClient = client;
mUrls = urls;
}
#Override
public List<Article> loadInBackground() {
List<Article> articles = new ArrayList<>();
for (String url : mUrls) {
Request request = new Request.Builder().url(url).build();
try {
Response response = mClient.newCall(request).execute();
if (response.isSuccessful()) {
parseData(response.body().string(), articles);
}
} catch (IOException | JSONException e) {
e.printStackTrace();
}
}
return articles;
}
private void parseData(List<Article> articles, String data) throws JSONException {
JSONObject forecast = new JSONObject(data);
JSONArray a = forecast.getJSONArray("articles");
for (int i = 0; i < a.length(); i++) {
JSONObject o = a.getJSONObject(i);
Article article = new Article(
o.getString("title"),
o.getString("description"),
o.getString("url"),
o.getString("urlToImage"));
articles.add(article);
}
}
}
Also, you may have noticed, I made a small change to your Article constructor. You should consider making the Article class immutable, as this will prevent you from making mistakes when dealing with multithreading. It should look something like this:
public class Article {
private final String mTitle;
private final String mDescription;
private final String mUrl;
private final String mImageUrl;
public Article(String title, String description, String url, String imageUrl) {
mTitle = title;
mDescription = description;
mUrl = url;
mImageUrl = imageUrl;
}
public String title() {
return mTitle;
}
public String description() {
return mDescription;
}
public String url() {
return mUrl;
}
public String imageUrl() {
return mImageUrl;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Article other = (Article) o;
return mTitle != null && mTitle.equals(other.mTitle) &&
mDescription != null && mDescription.equals(other.mDescription) &&
mUrl != null && mUrl.equals(other.mUrl) &&
mImageUrl != null && mImageUrl.equals(other.mImageUrl);
}
#Override
public int hashCode() {
int result = mTitle != null ? mTitle.hashCode() : 0;
result = 31 * result + (mDescription != null ? mDescription.hashCode() : 0);
result = 31 * result + (mUrl != null ? mUrl.hashCode() : 0);
result = 31 * result + (mImageUrl != null ? mImageUrl.hashCode() : 0);
return result;
}
}
#Override
public void onBindViewHolder(ArticleViewHolder holder, int position) {
holder.bindArticle(mArticlesList.get(position));
setAnimation(holder.itemView, position);
}
public void addAll(ArrayList<Articles> articles) {
mArticlesList.clear();
mArticlesList.addAll(articles);
notifyDataSetChanged();
}
If this doesn't wrok then I think your api is giving you redundant data.
Why you are using articleViewHolder.setIsRecyclable(false);
One another place which might cause the problem is
private void getMultipleUrls(String jsonData) throws JSONException {
if (mArticlesArrayList == null) {
mArticlesArrayList = getArticleForecast(jsonData);
} else {
mArticlesArrayList.addAll(getArticleForecast(jsonData));
}
}
You are calling it from a loop add adding data to your arraylist. There somehow multiple data can be inserted in your ArrayList

Categories

Resources