I need to execute a query to my DB to get some IDs and then use those IDs to execute another query to Realm DB and return the result to the Adapter which is used to create UI. My problem is that the adapter is created in onCreatView (main thread) and i need to let that wait queries result. Do you know how can i do? Really thanks :)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Realm realm = Realm.getDefaultInstance();
cardList = new ArrayList(realm.where(Card.class).findAll().sort("rarity"));
View rootView = inflater.inflate(R.layout.inventory_fragment_layout, null);
RecyclerView recyclerView = rootView.findViewById(R.id.inventory_recycler);
recyclerView.setLayoutManager(new GridLayoutManager(this.getContext(), 2));
adapter = new inventoryFragmentRecyclerAdapter(this.getContext(), getCards()); <----- getCards() is used here.
adapter.setClickListener(this);
recyclerView.setAdapter(adapter);
TextView topText = rootView.findViewById(R.id.inv_topText);
topText.setTypeface(Typeface.createFromAsset(getActivity().getAssets(), "fonts/Square.ttf"));
return rootView;
}
.
.
.
.
.
.
public List<Card> getCards() { //It is used when adapter is created, and it need to contain all cards to display
//Realm realm = Realm.getDefaultInstance();
String urlToGet = "myurl";
String user_name = settings.getString("username", null);
OkHttpClient client = new OkHttpClient();
RequestBody formBody = new FormBody.Builder()
.add("user_name", user_name)
.build();
Request request = new Request.Builder()
.url(urlToGet)
.post(formBody)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
responseCardInInventory = response.body().string();
handler.post(new Runnable() {
#Override
public void run() {
List<CardInInv> cardListInInv = new ArrayList<>();
Gson gson = new Gson();
CardInInventory civ = gson.fromJson(responseCardInInventory, CardInInventory.class);
cardListInInv = getCards(civ);
//HERE I NEED TO USE REALM TO EXECUTE A QUERY USING cardListInInv
}
});
}
});
//HERE I NEED TO RETURN THE RESULT OF THE QUERY EXECUTED BEFORE
return cardsIninv;
}
EDIT 1: Hre is my adapter code
public class inventoryFragmentRecyclerAdapter extends RecyclerView.Adapter<inventoryFragmentRecyclerAdapter.ViewHolder> {
private List<Card> dataCard = new ArrayList<>();
private LayoutInflater mInflater;
private ItemClickListener mClickListener;
// data is passed into the constructor
public inventoryFragmentRecyclerAdapter(Context context, List<Card> data) {
this.mInflater = LayoutInflater.from(context);
this.dataCard = data;
}
// inflates the cell layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.inventory_rw, parent, false);
return new ViewHolder(view);
}
// binds the data to the in each cell
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.cardImage.setImageBitmap(BitmapFactory.decodeByteArray(dataCard.get(position).getCardImage(), 0, dataCard.get(position).getCardImage().length));
}
// total number of cells
#Override
public int getItemCount() {
return dataCard.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ImageView cardImage;
//instanzio le componenti della pagina
ViewHolder(View itemView) {
super(itemView);
cardImage = itemView.findViewById(R.id.inv_rw_cardimage);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
// convenience method for getting data at click position
Card getItem(int id) {
return dataCard.get(id);
}
// allows clicks events to be caught
public void setClickListener(ItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
Move your query to your adapter and start your adapter with an empty list. Make your query call at the end of your constructor. When you've successfully finished your query, notify your adapter that it has changed and let it handle the changes with your new data at the end of your queries finishing successfully. So after doing that your adapter would look something like this.
public inventoryFragmentRecyclerAdapter(Context context, List<Card> data) {
this.mInflater = LayoutInflater.from(context);
getCards();
}
public void getCards() { //It is used when adapter is created, and it need to contain all cards to display
//Realm realm = Realm.getDefaultInstance();
String urlToGet = "myurl";
String user_name = settings.getString("username", null);
OkHttpClient client = new OkHttpClient();
RequestBody formBody = new FormBody.Builder()
.add("user_name", user_name)
.build();
Request request = new Request.Builder()
.url(urlToGet)
.post(formBody)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
responseCardInInventory = response.body().string();
handler.post(new Runnable() {
#Override
public void run() {
List<CardInInv> cardListInInv = new ArrayList<>();
Gson gson = new Gson();
CardInInventory civ = gson.fromJson(responseCardInInventory, CardInInventory.class);
cardListInInv = getCards(civ);
//use realm to do all your card inventory stuff to get your resulting object
dataCard = yourObjectListAfterUsingRealm;
notifyDataSetChanged();
}
});
}
});
}
move This line adapter = new inventoryFragmentRecyclerAdapter(context, yourList);
inside onResponse() and pass the list directly without the getCards();
Edit:
initialize your adapter when your data is ready.where ? this is based on your needs.
or initialize it with empty list and call adapter.notifyDataSetChanged() when something changed (added or removed from the list or a brand new list is initialized)
Create your adapter with empty list
adapter = new inventoryFragmentRecyclerAdapter(this.getContext(), new ArrayList<Card>());
and then in your adapter create a method like this
public void updateCardList(List<Card> cardList) {
this.mCards = cardList;
notifyDataSetChanged();
}
and call this function in the
#Override
public void onResponse(Call call, final Response response)
Related
In my current code, I'm able to pass and display one value to the RecyclerView. I'm not sure what I'm missing or if I have to completely change my code.
Here's my Adapter Class:
public class TechSkillsAdapter extends RecyclerView.Adapter<TrainingViewHolder> {
Context c;
ArrayList<String> trainings;
public TechSkillsAdapter(Context c, ArrayList<String> trainings) {
this.c = c;
this.trainings = trainings;
}
#Override
public TrainingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(c).inflate(R.layout.cv_traininglist, parent, false);
return new TrainingViewHolder(v);
}
#Override
public void onBindViewHolder(TrainingViewHolder holder, int position) {
holder.date_txt.setText(trainings.get(position));
}
#Override
public int getItemCount() {
return trainings.size();
}
}
I'm retrieving the list using retrofit then passing the values to a method that displays them to the recyclerview.
Here's how I'm retrieving the trainings:
private void getTraining(final String id, String tid){
com.trendmicro.projectlara.apis.ApiServiceTraining apiService = ApiClient.getClient().create(ApiServiceTraining.class);
Call<List<Training>> call = apiService.getMyTraining(id, tid);
call.enqueue(new Callback<List<Training>>() {
#Override
public void onResponse (Call<List<Training>> call, Response<List<Training>> response) {
List<Training> training = response.body();
for(Training t: training){
fillTrainings(t.getTraining_title().toString(), t.getTraining_date().toString());
}
}
Here's my fillTrainings method.
I'm passing two values but I'm only able to display one value:
private void fillTrainings(String title, String date) {
training.add(title);
adapter = new TechSkillsAdapter(getContext(), training);
rv.setAdapter(adapter);
progressDialog.dismiss();
}
Here's what I'm trying to fix,I'm not sure how to display the date as well since the way I'm adding the values is: training.add(title);
Any help or tip is much appreciated. Thanks!
This is because you're recreate the adapter each time you have an item with this code:
#Override
public void onResponse (Call<List<Training>> call, Response<List<Training>> response) {
List<Training> training = response.body();
for(Training t: training){
// here you're only send one time
fillTrainings(t.getTraining_title().toString(), t.getTraining_date().toString());
}
}
You can fix it by sending all the list to your method by changing the method to this:
private void fillTrainings(List<Training> trainList) {
for(Training train: trainList) {
training.add(train.getTraining_title().toString());
}
adapter = new TechSkillsAdapter(getContext(), training);
rv.setAdapter(adapter);
progressDialog.dismiss();
}
then you can use it with:
#Override
public void onResponse (Call<List<Training>> call, Response<List<Training>> response) {
List<Training> training = response.body();
fillTrainings(training);
}
You are receiving a List of Training, but for some reason your adapter is backed by List of String. Why is that?
Modify your adapter to hold Trainings and then bind both the title and the date to the view.
public class TechSkillsAdapter extends RecyclerView.Adapter<TrainingViewHolder> {
Context c;
ArrayList<Training> trainings;
public TechSkillsAdapter(Context c, ArrayList<Training> trainings) {
this.c = c;
this.trainings = trainings;
}
#Override
public TrainingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(c).inflate(R.layout.cv_traininglist, parent, false);
return new TrainingViewHolder(v);
}
#Override
public void onBindViewHolder(TrainingViewHolder holder, int position) {
holder.title_txt.setText(trainings.get(position).getTraining_title().toString());
holder.date_txt.setText(trainings.get(position).getTraining_date().toString());
}
#Override
public int getItemCount() {
return trainings.size();
}
}
And then in your onResponse just do:
#Override
public void onResponse (Call<List<Training>> call, Response<List<Training>> response) {
List<Training> training = response.body();
adapter = new TechSkillsAdapter(getContext(), training);
rv.setAdapter(adapter);
progressDialog.dismiss();
}
This should work, but you can improve this if you create and set your adapter once (in onCreate) and pass it some list, and then in onResponse just update that list and do adapter.notifyDataSetChanged() Sort of like this:
//Activity
List<Training> mTrainingsList = new ArrayList<Training>();
//onCreate
adapter = new TechSkillsAdapter(getContext(), mTrainingsList);
...
}
#Override
public void onResponse (Call<List<Training>> call, Response<List<Training>> response) {
List<Training> training = response.body();
mTrainingList.clear();
mTrainingList.addAll(training);
adapter.notifyDatasetChanged();
progressDialog.dismiss();
}
EDIT: Also, please note that in your code you're going over the list of trainings and you recreate the adapter for each item! Try to avoid this in the future.
Whenever i try to add data to recycler view, the recycler view doesn't show any data. I tried debugging the program and I am successfully getting JSON data using Retrofit into the application(Checked by printing it in Log). But RecyclerView shows no data.Here is my code:
CartActivity.java
public class CartActivity extends AppCompatActivity {
RecyclerView listshowrcy;
List<CartDisplay> cartlist = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
API api = retrofit.create(API.class);
String username = getIntent().getStringExtra("Username");
Call<List<CartDisplay>> call = api.getCartContent(username);
call.enqueue(new Callback<List<CartDisplay>>() {
#Override
public void onResponse(Call<List<CartDisplay>> call, Response<List<CartDisplay>> response) {
List<CartDisplay> cart = response.body();
for(CartDisplay cartContent : cart){
cartlist.add(cartContent);
}
}
#Override
public void onFailure(Call<List<CartDisplay>> call, Throwable t) {
}
});
listshowrcy = (RecyclerView)findViewById(R.id.cartList);
listshowrcy.setHasFixedSize(true);
CartAdapter cardadapter = new CartAdapter(cartlist,this,username);
listshowrcy.setAdapter(cardadapter);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
listshowrcy.setLayoutManager(linearLayoutManager);
}
}
CartAdapter.java
public class CartAdapter extends RecyclerView.Adapter<CartAdapter.Holderview> {
private List<CartDisplay> cartlist;
private Context context;
private String username;
public CartAdapter(List<CartDisplay> cartlist, Context context,String username) {
this.cartlist = cartlist;
this.context = context;
this.username = username;
}
#Override
public Holderview onCreateViewHolder(ViewGroup parent, int viewType) {
View layout = LayoutInflater.from(parent.getContext()).inflate(R.layout.cart_item,parent,false);
return new Holderview(layout);
}
#Override
public void onBindViewHolder(Holderview holder, int position) {
holder.pname.setText(cartlist.get(position).getP_name());
holder.pquant.setText(cartlist.get(position).getQuantity());
holder.price.setText(String.valueOf(cartlist.get(position).getPrice()));
}
#Override
public int getItemCount() {
return cartlist.size();
}
class Holderview extends RecyclerView.ViewHolder
{
TextView pname;
TextView pquant;
TextView price;
Holderview(View itemview){
super(itemview);
pname = (TextView)itemview.findViewById(R.id.product_name);
pquant = (TextView)itemview.findViewById(R.id.product_quant);
price = (TextView)itemview.findViewById(R.id.product_price);
}
}
}
After you get your response you must notify adapter, that data has changed:
#Override
public void onResponse(Call<List<CartDisplay>> call, Response<List<CartDisplay>> response) {
List<CartDisplay> cart = response.body();
cartList.clear(); // don't forget to clear list, to avoid duplicates
for(CartDisplay cartContent : cart){
cartlist.add(cartContent);
}
adapter.notifyDataSetChanged();
}
Another way: you can create method: adapter.setData(cardList)
And there refresh adapter data and call notifyDataSetChanged()
In addition to #kdblue's answer, there is another issue with your code. The adapter doesn't know that new data has been added to the underlying list.
You can either use notifyDataSetChanged:
List<CartDisplay> cart = response.body();
for(CartDisplay cartContent : cart){
cartlist.add(cartContent);
}
cardadapter.notifyDataSetChanged();
Or let the adapter handle new items directly, by adding a method to the adapter like:
public void add(CartDisplay cartDisplay) {
cartlist.add(user);
notifyItemInserted(cartlist.size());
}
And adding the items directly to the adapter:
List<CartDisplay> cart = response.body();
for(CartDisplay cartContent : cart){
cardadapter.add(cartContent);
}
Be aware that you will have to change you code structure to apply these strategies.
I am using OkHttp to get HTML string and list the information in RecyclerView in a fragment.
However, when the app runs, it didn't show list information at first launch.
After I click other fragment page and go back to this fragment page, it show list.
But when I swipe down to see more list, the list repeat for twice (or more?) and the item background color disordered.
How can I fix it? Thanks!
My Adapter
public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
private List<NewsModel> mNewsList;
class ViewHolder extends RecyclerView.ViewHolder {
TextView newsNameText;
TextView newsDataText;
View listView;
public ViewHolder(View newsView) {
super(newsView);
newsNameText = (TextView) newsView.findViewById(R.id.news_Name);
newsDataText = (TextView) newsView.findViewById(R.id.news_Data);
listView = newsView;
}
}
public NewsAdapter(List<NewsModel> newsList) {
mNewsList = newsList;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item, parent, false);
final ViewHolder holder = new ViewHolder(view);
return holder;
}
public void setData(List<NewsModel> viewData) {
mNewsList.clear();
mNewsList.addAll(viewData);
notifyDataSetChanged();
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
NewsModel news = mNewsList.get(position);
holder.setIsRecyclable(true);
if(position % 2 == 0){
holder.listView.setBackgroundColor(0x80E0EEEE);
}
holder.newsNameText.setText(news.getName());
holder.newsDataText.setText(news.getData());
}
#Override
public int getItemCount() {
return mNewsList.size();
}
}
My fragment
public class NewsFragment extends Fragment {
List<NewsModel> resultList = new ArrayList<>();
List<NewsModel> htmlList = new ArrayList<>();
NewsAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View newsView = inflater.inflate(R.layout.fragment_news, container, false);
RecyclerView newsRecyclerView = (RecyclerView) newsView.findViewById(R.id.news_list);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
newsRecyclerView.setLayoutManager(layoutManager);
adapter = new NewsAdapter(getNews());
newsRecyclerView.setAdapter(adapter);
return newsView;
}
private List<NewsModel> getNews() {
new Thread(new Runnable() {
#Override
public void run() {
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://www.career.fudan.edu.cn/jsp/career_talk_list.jsp?count=50&list=true")
.build();
Response response = client.newCall(request).execute();
String resultString = response.body().string();
resultList.clear();
resultList.addAll(getResult(resultString));
adapter.notifyDataSetChanged();
/*new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
adapter.setData(resultList);
adapter.notifyDataSetChanged();
}
});//postdelayed (runnable long) cannot be applied to runnable*/
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
return resultList;
}
private List<NewsModel> getResult(final String response) {
XXXXXX
return htmlList;
}
}
The problem is that maybe you are adding many entries and since recyclerview is trying to reuse those views instead of redrawing again and again which cause sometimes view inconsistency. Here is the problem discussed Look into it if you are having the same problem.
to disable it or enable it to use in your bindViewHolder()
setIsRecyclable(Boolean enable)
And your second problem is that onCreateView() is called the second time when coming back from another fragment causing addition of duplicate data again so you need to clear the list before adding any new entries and Why it's not showing in the first run because you have added data in another thread and did not updated the adapter about it.
List<NewsModel> resultList = new ArrayList<>();
NewsAdapter adapter ;
public class NewsFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View newsView = inflater.inflate(R.layout.fragment_news, container, false);
RecyclerView newsRecyclerView = (RecyclerView) newsView.findViewById(R.id.news_list);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
newsRecyclerView.setLayoutManager(layoutManager);
adapter = new NewsAdapter(resultList);
newsRecyclerView.setAdapter(adapter);
getNews();
return newsView;
}
private void getNews(){
AsyncTask<Void,Void,String> asyncTask = new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(final Void... voids) {
String resultString = null;
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://www.career.fudan.edu.cn/jsp/career_talk_list.jsp?count=50&list=true")
.build();
Response response = null;
try {
response = client.newCall(request).execute();
resultString = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
return resultString;
}
#Override
protected void onPostExecute(final String resultString) {
super.onPostExecute(resultString);
resultList.clear();
resultList.addAll(getResult(resultString));
adapter.notifyDataSetChanged();
}
}.execute();
}
The thread will change the resultList in some delay, but you already passed old data before that.
Please try as following...
public class NewsFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View newsView = inflater.inflate(R.layout.fragment_news, container, false);
RecyclerView newsRecyclerView = (RecyclerView) newsView.findViewById(R.id.news_list);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
newsRecyclerView.setLayoutManager(layoutManager);
getNews(newsRecyclerView);
return newsView;
}
private void getNews(final RecyclerView newsRecyclerView){
new Thread(new Runnable() {
#Override
public void run() {
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://www.career.fudan.edu.cn/jsp/career_talk_list.jsp?count=50&list=true")
.build();
Response response = client.newCall(request).execute();
String resultString = response.body().string();
List<NewsModel> resultList = getResult(resultString);
NewsAdapter adapter = new NewsAdapter(resultList);
newsRecyclerView.setAdapter(adapter);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
private List<NewsModel> getResult(final String response) {
XXXXXXXXX
return List;
}
Main pattern is bad.
The easiest way for this code is to set (not add) items in adapter when it is downloaded and invoke on adapter notifyDataSetChanged() - all cells will be redraw.
So make adapter as field, add method to adapter setData() and:
...
Response response = client.newCall(request).execute();
String resultString = response.body().string();
resultList = getResult(resultString);
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
adapter.setData(results);
adapter.notifyDataSetChanged();
}
});
I am trying to display data in a recycler view in android. i but it keeps displaying only the last datas and i dont know why.i seem to be doing everything right. And the recycler view has a view pager.
this is my
Myadapter class
public class MyAdapter extends RecyclerView.Adapter<MyHolder> {
Context c;
List<Getter> getter;
public MyAdapter(List<Getter> getter, Context c) {
super();
this.c = c;
this.getter = getter;
}
//INITIALIZE VIEWHODER
#Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//VIEW OBJ
View v= LayoutInflater.from(parent.getContext()).inflate(R.layout.model,null);
//HOLDER
MyHolder holder=new MyHolder(v);
return holder;
}
//BIND VIEW TO DATA
#Override
public void onBindViewHolder(MyHolder holder, int position) {
String images[] = {getter.get(position).getUrl1(), getter.get(position).getUrl2()};
holder.gamename.setText(getter.get(position).getGame_name());
holder.cost.setText(getter.get(position).getCost());
holder.usname.setText(getter.get(position).getFull_name());
Picasso.with(c)
.load(getter.get(position).getPicture())
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.transform(new CircleTransform())
.fit()
.into(holder.usimage);
CustomPagerAdapter mCustomPagerAdapter = new CustomPagerAdapter(c,images);
holder.mViewPager.setAdapter(mCustomPagerAdapter);
holder.indicator.setViewPager(holder.mViewPager);
holder.setItemClickListener(new ItemClickListener() {
#Override
public void onItemClick(View v, int pos) {
Snackbar.make(v,getter.get(pos).getGame_name(),Snackbar.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return getter.size();
}
}
This is my mainactivty class
public class All_timeline extends Fragment {
SqlHandler sqlHandler;
RecyclerView rv;
MyAdapter adapter;
private List<Getter> getter;
public All_timeline() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View x = inflater.inflate(R.layout.all_timeline, container, false);
sqlHandler = new SqlHandler(getActivity());
//recycler
rv = (RecyclerView) x.findViewById(R.id.mRecycler);
getter= new ArrayList<>();
rv.setLayoutManager(new LinearLayoutManager(getActivity()));
rv.setItemAnimator(new DefaultItemAnimator());
rv.addItemDecoration(new SimpleDividerItemDecoration(getResources()));
registerUser("arinzeaco#gmail.com");
adapter=new MyAdapter(getter,getActivity());
rv.setAdapter(adapter);
return x;
}
public void registerUser(final String email) {
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("username", email)
.build();
Request request = new Request.Builder().url("http://www.thethinker.com.ng/gamer/allpost.php").post(body).build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Toast.makeText(getActivity(), "Registration failed",
Toast.LENGTH_SHORT).show();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
final String myResponse = response.body().string();
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
JSONObject jso;
Getter contactListItems = new Getter();
try {
jso = new JSONObject(myResponse);
JSONArray categories = jso.getJSONArray("posts");
for (int i = 0; i < categories.length(); i++) {
String image1 = categories.getJSONObject(i).getString("image_1");
String image2 = categories.getJSONObject(i).getString("image_2");
String username = categories.getJSONObject(i).getString("username");
String video_url = categories.getJSONObject(i).getString("video_url");
String liked = categories.getJSONObject(i).getString("liked");
String cost = categories.getJSONObject(i).getString("cost");
String following = categories.getJSONObject(i).getString("following");
String game_name = categories.getJSONObject(i).getString("game_name");
String full_name = categories.getJSONObject(i).getString("full_name");
String userimage = categories.getJSONObject(i).getString("userimage");
contactListItems.setUsername(username);
contactListItems.setGame_name(game_name);
contactListItems.setCost(cost);
contactListItems.setFollowing(following);
contactListItems.setLiked(liked);
contactListItems.setFull_name(full_name);
contactListItems.setVideo(video_url);
contactListItems.setUrl1(image1);
contactListItems.setUrl2(image2);
contactListItems.setPicture(userimage);
getter.add(contactListItems);
}
} catch (JSONException e) {
e.printStackTrace();
}
}});
}
});
}
}
I have also check other stackoverflow questions like RecyclerView displaying the last item in the adapter several times. Need all adapter items to show in RecyclerView. but i just don't get what i am doing wrong.
I think it related to concurrency issue, please try to call http method after you set adapter, and don't forget to call notifyDataSetChanged() after all data inserted. One more think, make sure you insert different Getter instance for every item
for example in onCreateView
adapter=new MyAdapter(getter,getActivity());
rv.setAdapter(adapter);
registerUser("arinzeaco#gmail.com");
in onResponse:
#Override
public void onResponse(Call call, Response response) throws IOException {
final String myResponse = response.body().string();
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
JSONObject jso;
try {
jso = new JSONObject(myResponse);
JSONArray categories = jso.getJSONArray("posts");
for (int i = 0; i < categories.length(); i++) {
Getter contactListItems = new Getter();
String image1 = categories.getJSONObject(i).getString("image_1");
String image2 = categories.getJSONObject(i).getString("image_2");
String username = categories.getJSONObject(i).getString("username");
String video_url = categories.getJSONObject(i).getString("video_url");
String liked = categories.getJSONObject(i).getString("liked");
String cost = categories.getJSONObject(i).getString("cost");
String following = categories.getJSONObject(i).getString("following");
String game_name = categories.getJSONObject(i).getString("game_name");
String full_name = categories.getJSONObject(i).getString("full_name");
String userimage = categories.getJSONObject(i).getString("userimage");
contactListItems.setUsername(username);
contactListItems.setGame_name(game_name);
contactListItems.setCost(cost);
contactListItems.setFollowing(following);
contactListItems.setLiked(liked);
contactListItems.setFull_name(full_name);
contactListItems.setVideo(video_url);
contactListItems.setUrl1(image1);
contactListItems.setUrl2(image2);
contactListItems.setPicture(userimage);
getter.add(contactListItems);
}
adapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}});
}
});
I'm trying to populate a ListView with a JSON from a server. I'm getting the data from the server but I can't seem to figure out how to put it in a ListView. The error I'm getting is in the onResponse.
It says: "Error:(84, 54) error: constructor JucatoriLiberiArrayAdapter in class JucatoriLiberiArrayAdapter cannot be applied to given types;
required: Context,ArrayList
found: FragmentActivity,Call>
reason: actual argument Call> cannot be converted to ArrayList by method invocation conversion"
I think I've tried almost every Alt+Enter fix there is. Also tried to change type from Call<ArrayList<FreePlayers> to just ArrayList<> or just Call<>.
This is my class:
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
final Retrofit builder = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.baseUrl(ROOT)
.build();
REST_CLIENT = builder.create(API.class);
final Call<FreePlayers> request = REST_CLIENT.getFreePlayers(1);
request.enqueue(new Callback<FreePlayers>() {
#Override
public void onResponse(final Call<FreePlayers> call, final Response<FreePlayers> response) {
ArrayList<FreePlayers> players = null;
players = call;
ListView lv = (ListView) getView().findViewById(android.R.id.list);
JucatoriLiberiArrayAdapter adapter = new JucatoriLiberiArrayAdapter(getActivity(),
players);
lv.setAdapter(adapter);
}
#Override
public void onFailure(final Call<FreePlayers> call, final Throwable t) {
}
});
}
My API interface:
public interface API {
#FormUrlEncoded
#POST("/fan-sport/app-test/")
Call<ArrayList<FreePlayers>> getFreePlayers(#Field("getFreePlayers") int freePlayers);
}
And this is my custom adapter:
public class JucatoriLiberiArrayAdapter extends BaseAdapter {
private Context context;
private ArrayList<FreePlayers> players;
public JucatoriLiberiArrayAdapter(Context context, ArrayList<FreePlayers> playersList) {
super();
this.context = context;
this.players = playersList;
}
#Override
public int getCount() {
return 0;
}
#Override
public Object getItem(final int position) {
return null;
}
#Override
public long getItemId(final int position) {
return 0;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_view_jucatori_liberi, null);
TextView playerName = (TextView) convertView.findViewById(R.id.name);
playerName.setText((CharSequence) players.get(position));
}
return convertView;
}
}
In your onResponse() you receive a Call object wheras your adapter expects a List<FreePlayers>, the response argument is the list of players you want to give to your adapter.
Try this code:
final Call<List<FreePlayers>> request = REST_CLIENT.getFreePlayers(1);
request.enqueue(new Callback<List<FreePlayers>>() {
#Override
public void onResponse(final Call<List<FreePlayers>> call, final Response<List<FreePlayers>> response) {
ArrayList<FreePlayers> players = null;
players = response.body();
ListView lv = (ListView) getView().findViewById(android.R.id.list);
JucatoriLiberiArrayAdapter adapter = new JucatoriLiberiArrayAdapter(getActivity(),
players);
lv.setAdapter(adapter);
}
#Override
public void onFailure(final Call<FreePlayers> call, final Throwable t) {
}
});
call is assgined to players, but players type is ArrayList<FreePlayers> and call type is Call<List<FreePlayers>. Not the same. The adapter expects ArrayList<FreePlayers>.
You're declaring
Call<FreePlayers>,
but expect to receive
Call<ArrayList<FreePlayers>>.
Also, you're Adapter is broken. These methods should look something like:
#Override
public int getCount() {
if (players == null) return 0;
return players.size();
}
#Override
public Object getItem(final int position) {
if (players == null || players.size() == 0) return null;
return players.get(position);
}
#Override
public long getItemId(final int position) {
return getItem(position).getId(); // or something like an id that suits you.
}