I have a recyclerview and i'm trying to implement Endless Scroll with this popular android Endless scroll Library. It almost working well, except that when i get to the buttom of the current list, it reloads and starts from the top instead of continuing from the last visible item.
This is my Scroll Listerner.
scrollListener = new EndlessRecyclerViewScrollListener(manager) {
#Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
// Triggered only when new data needs to be appended to the list
// Add whatever code is needed to append new items to the bottom of the list
loadMore(page);
++page;
}
};
mRecyclerView.addOnScrollListener(scrollListener);
This is my loadMore()
public void loadMore(int page) {
String url = myurl + page;
StringRequest stringRequest = new StringRequest(url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
//Log.i("Responses", response);
ArrayList<Deal> deals = new JsonConverter<Deal>().toArrayList(response, Deal.class);
dealArrayList.addAll(deals);
adapter = new DealAdapter(getApplicationContext(), dealArrayList);
mRecyclerView.setAdapter(adapter);
newList = deals;
adapter.notifyItemRangeInserted(newList.size(), dealArrayList.size());
stopAnim();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, error.toString());
Toast.makeText(getApplicationContext(), "Bad Network Connection. Please Try Again", Toast.LENGTH_LONG).show();
stopAnim();
}
}
);
int socketTimeout = 30000; // 30 seconds. You can change it
RetryPolicy policy = new DefaultRetryPolicy(socketTimeout,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
stringRequest.setRetryPolicy(policy);
MySingleton.getInstance(getApplicationContext()).addToRequestQueue(stringRequest);
mSwipeRefresh.setRefreshing(false);
}
I can't figure out whats wrong.
Help.
Edited..
My app calls this function when it first lunches and then call the loadMore function when i scroll.
public void firstRun(int page) {
String url = myurl + page;
StringRequest stringRequest = new StringRequest(url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.i("Responses", response);
dealArrayList = new JsonConverter<Deal>().toArrayList(response, Deal.class);
adapter = new DealAdapter(getApplicationContext(), dealArrayList);
mRecyclerView.setAdapter(adapter);
newList = dealArrayList;
adapter.notifyDataSetChanged();
stopAnim();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, error.toString());
Toast.makeText(getApplicationContext(), "Bad Network Connection. Please Try Again", Toast.LENGTH_LONG).show();
stopAnim();
}
}
);
int socketTimeout = 30000; // 30 seconds. You can change it
RetryPolicy policy = new DefaultRetryPolicy(socketTimeout,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
stringRequest.setRetryPolicy(policy);
MySingleton.getInstance(getApplicationContext()).addToRequestQueue(stringRequest);
mSwipeRefresh.setRefreshing(false);
}
This is my Adapter
public class DealAdapter extends RecyclerView.Adapter<DealAdapter.ViewHolder> {
private Context context;
private ArrayList<Deal> deals;
public DealAdapter(Context context, ArrayList<Deal> deals) {
this.context = context;
this.deals = deals;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.card_view, parent, false);
final ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
Deal deal = deals.get(position);
holder.mCardTitle.setText(deal.title);
holder.mCardLocation.setText(deal.location);
holder.mCardDiscount.setText(String.valueOf(deal.discount));
holder.mCardPrice.setText(deal.price);
holder.mCardContact.setText(deal.contact);
holder.mCardDescription.setText(deal.description);
String url = myurl + deal.image;
Picasso.with(context)
.load(url).resize(0,300)
.placeholder(R.drawable.load)
.error(android.R.drawable.stat_notify_error)
.into(holder.mCardImage);
holder.mCardDescription.setOnClickListener(new View.OnClickListener() {
boolean isClicked = false;
#Override
public void onClick(View v) {
if(isClicked){
//This will shrink textview to 2 lines if it is expanded.
holder.mCardDescription.setMaxLines(2);
holder.more.setVisibility(View.VISIBLE);
holder.mCardInvisible.setVisibility(View.GONE);
isClicked = false;
} else {
//This will expand the textview if it is of 2 lines
holder.mCardDescription.setMaxLines(Integer.MAX_VALUE);
holder.more.setVisibility(View.GONE);
holder.mCardInvisible.setVisibility(View.VISIBLE);
isClicked = true;
}
}
});
}
#Override
public int getItemCount() {
if (deals != null) {
return deals.size();
}else{
return 0;
}
}
static class ViewHolder extends RecyclerView.ViewHolder {
private TextView mCardTitle;
private ImageView mCardImage;
private TextView mCardLocation;
private TextView mCardDescription;
private TextView mCardContact;
private TextView mCardPrice;
private TextView mCardDiscount, more;
private LinearLayout mCardInvisible;
private ViewHolder(View itemView) {
super(itemView);
mCardTitle = (TextView) itemView.findViewById(R.id.mCardTitle);
mCardImage = (ImageView) itemView.findViewById(R.id.mCardImage);
mCardLocation = (TextView) itemView.findViewById(R.id.mCardLocation);
mCardDescription = (TextView) itemView.findViewById(R.id.mCardDescription);
mCardContact = (TextView) itemView.findViewById(R.id.mCardContact);
mCardPrice = (TextView) itemView.findViewById(R.id.mCardPrice);
mCardDiscount = (TextView) itemView.findViewById(R.id.mCardDiscount);
more = (TextView) itemView.findViewById(R.id.mCardMore);
mCardInvisible = (LinearLayout) itemView.findViewById(R.id.mCardInvisible);
}
}
}
Edited:: This is my OnRefresh Listener
mSwipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
firstRun(1);
}
}, 3000);
}
});
In your adapter add a new function that merges the data you have with the new ones:
public void addAll(List data){
deals.addAll(data);
notifyDataSetChanged();
}
Your onResponse in loadMore function should look like:
public void onResponse(String response) {
//Log.i("Responses", response);
ArrayList<Deal> deals = new JsonConverter<Deal>().toArrayList(response, Deal.class);
adapter.addAll(deals);
stopAnim();
}
Related
Hi, I faced an issue here.. I was creating a chatbot in which user can type a text to send it and also can select a text out of the recommended texts
so I created two RecycleViews
My goal is - when the user selects one of the recommended text, then that text should appear in the Chatting RecycleView
here is my main Activity Class
public class Charts extends AppCompatActivity {
private static final String USER_KEY = "user";
private static final String BOT_KEY = "bot";
RecyclerView chart_recycle,auto_texts;
EditText message_text;
ImageView send_btn,mic_button;
ImageView setting_button;
ChartsAdapter chartsAdapter;
RecyclerView.LayoutManager linearLayout;
ArrayList<ChartModeClass> modeClassesArrayList = new ArrayList<>();
AutoAdapter autoAdapter;
RecyclerView.LayoutManager horizontal;
List<Texts> list = new ArrayList();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chatting_hole);
message_text = findViewById(R.id.message_text);
send_btn = findViewById(R.id.send_btn);
mic_button = findViewById(R.id.mic_btn);
setting_button = findViewById(R.id.setting_button);
chart_recycle = findViewById(R.id.chart_recycle);
chart_recycle.setHasFixedSize(true);
auto_texts = findViewById(R.id.auto_texts);
auto_texts.setHasFixedSize(true);
linearLayout = new LinearLayoutManager(getApplicationContext(), RecyclerView.VERTICAL, false);
chart_recycle.setLayoutManager(linearLayout);
//Auto text
horizontal = new LinearLayoutManager(getApplicationContext(),RecyclerView.HORIZONTAL, false);
auto_texts.setLayoutManager(horizontal);
chartsAdapter = new ChartsAdapter(modeClassesArrayList, Charts.this);
chart_recycle.setAdapter(chartsAdapter);
//Auto texts
autoAdapter = new AutoAdapter(getApplicationContext(),list);
auto_texts.setAdapter(autoAdapter);
addInputs();
BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(Charts.this);
mic_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
bottomSheetDialog.setContentView(R.layout.record);
bottomSheetDialog.show();
}
});
message_text.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (charSequence.toString().trim().length()==0){
mic_button.setVisibility(View.VISIBLE);
send_btn.setVisibility(View.GONE);
}else {
send_btn.setVisibility(View.VISIBLE);
mic_button.setVisibility(View.GONE);
}
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (charSequence.toString().trim().isEmpty()){
// Toast.makeText(getApplicationContext(),"Enter text",Toast.LENGTH_LONG).show();
mic_button.setVisibility(View.VISIBLE);
send_btn.setVisibility(View.GONE);
}else {
send_btn.setVisibility(View.VISIBLE);
mic_button.setVisibility(View.GONE);
}
}
#Override
public void afterTextChanged(Editable editable) {
if (editable.toString().length()==0){
mic_button.setVisibility(View.VISIBLE);
send_btn.setVisibility(View.GONE);
}
}
});
send_btn.setOnClickListener(view -> {
if (message_text.getText().toString().isEmpty()) {
Toast.makeText(Charts.this, "Please enter text..", Toast.LENGTH_SHORT).show();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
returnResponse(message_text.getText().toString());
}
message_text.setText("");
});
}
#SuppressLint("NotifyDataSetChanged")
private void returnResponse(String message) {
modeClassesArrayList.add(new ChartModeClass(message, USER_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size()-1);
String url = "http://xxxxxxxxxxxxxxxx"+message;
String BASE_URL = "https://xxxxxxxxx";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitApi retrofitApi = retrofit.create(RetrofitApi.class);
Call<MessageModeClass> call = retrofitApi.getMessage(url);
call.enqueue(new Callback<MessageModeClass>() {
#Override
public void onResponse(#NonNull Call<MessageModeClass> call, #NonNull Response<MessageModeClass> response) {
if (response.isSuccessful()) {
MessageModeClass messageModeClass = response.body();
if (messageModeClass != null) {
modeClassesArrayList.add(new ChartModeClass(messageModeClass.getCnt(), BOT_KEY));
}
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
} else {
Toast.makeText(Charts.this, "response is null", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(#NonNull Call<MessageModeClass> call, #NonNull Throwable t) {
modeClassesArrayList.add(new ChartModeClass("No response check your network connection!", BOT_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
}
});
}
#SuppressLint("NotifyDataSetChanged")
#Override
protected void onStart() {
super.onStart();
String lang = getIntent().getExtras().getString("lang");
if (lang.equals("english")){
modeClassesArrayList.add(new ChartModeClass("Hey welcome back am fema bot", BOT_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
}else if (lang.equals("swahili")){
modeClassesArrayList.add(new ChartModeClass("Habari karibu miminni bot niliyetengenezw", BOT_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
}else {
modeClassesArrayList.add(new ChartModeClass("Hey welcome back am fema bot", BOT_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
}
}
private void addInputs() {
Texts text1 = new Texts("gender?");
Texts text2 = new Texts("gender equality");
Texts text3 = new Texts("what is good about females");
Texts text4 = new Texts("un goals");
Texts text5 = new Texts("about men");
list.addAll(Arrays.asList(new Texts[]{text1,text2,text3,text4,text5}));
}
}
here is my Adapter class class codes
public class AutoAdapter extends RecyclerView.Adapter<AutoAdapter.ViewHolderClass> {
Context context;
List<Texts> list;
public AutoAdapter(Context context, List<Texts> list) {
this.context = context;
this.list = list;
}
#NonNull
#Override
public ViewHolderClass onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_list,parent,false);
ViewHolderClass viewHolderClass = new ViewHolderClass(view);
return viewHolderClass;
}
#Override
public void onBindViewHolder(#NonNull ViewHolderClass holder, #SuppressLint("RecyclerView") int position) {
holder.input_text.setText(list.get(position).getText());
holder.input_text.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// my stack
}
});
}
#Override
public int getItemCount() {
return list.size();
}
public class ViewHolderClass extends RecyclerView.ViewHolder {
TextView input_text;
public ViewHolderClass(#NonNull View itemView) {
super(itemView);
input_text = itemView.findViewById(R.id.input_text);
}
}
}
You can add a list of your recommendations in another RecyclerView
Then in the ViewHolder of each item of the RecyclerView add Callback to listen on click events when a user clicks one of the item like the following
public class ViewHolderClass extends RecyclerView.ViewHolder {
private TextView input_text;
private final Callback callback; // custom callback
public ViewHolderClass(#NonNull View itemView, Callback callback) {
super(itemView);
this.callback = callback;
input_text = itemView.findViewById(R.id.input_text);
// now add onClickListener of the itemView to fire custom callback
itemView.setOnClickListener(view -> {
this.callback.onItemClick(getAdapterPosition());
});
}
// this is my custom callback for return click event
public interface Callback {
void onItemClick(int position);
}
}
Now inside your adapter add the callback from viewholder
public class AutoAdapter extends RecyclerView.Adapter<AutoAdapter.ViewHolderClass> {
private Context context;
private List<Texts> list;
private AutoAdapterCallback callback;
public AutoAdapter(Context context, List<Texts> list) {
this.context = context;
this.list = list;
}
public setCallback(AutoAdapterCallback callback) {
this.callback = callback;
}
#NonNull
#Override
public ViewHolderClass onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_list,parent,false);
ViewHolderClass viewHolderClass = new ViewHolderClass(view, new ViewHolderClass.Callback() {
#Override
public void onItemClick(int position) {
// forward callback to adapter callback
if (callback != null) {
// get actual item from its position
final Texts texts = getItemByPosition(position);
// send to adapter callback
callback.onItemClick(texts);
}
});
return viewHolderClass;
}
#Override
public void onBindViewHolder(#NonNull ViewHolderClass holder, #SuppressLint("RecyclerView") int position) {
holder.input_text.setText(list.get(position).getText());
// I haven't used this inteady I added callback on viewholder side
// holder.input_text.setOnClickListener(new View.OnClickListener() {
// #Override
// public void onClick(View view) {
// // my stack
// }
// });
}
#Override
public int getItemCount() {
return list.size();
}
// return Texts object by given position
public Texts getItemByPosition(int position) {
return this.list.get(position);
}
// add adapter callback to be called by viewholder
public interface AdapterCallback {
void onItemClick(Texts texts);
}
}
After that, now on your Activity you can easily listen on any item when a user clicks and get its corresponding Texts object from list as following:
//code ...
// here
//Auto texts
autoAdapter = new AutoAdapter(getApplicationContext(),list);
//set callback to listen for click events
autoAdapter.setCallback(new AutoAdapter.AutoAdapterCallback() {
#Override
public void onItemClick(Texts texts) {
// you can get your clicked item here
// now you can put texts object to another RecyclerView :)
}
});
auto_texts.setAdapter(autoAdapter);
//code ...
I'm getting the error:
RecyclerView﹕ No adapter attached; skipping layout
I checked some other answers people have given for this issue, but had no luck.
Adapter:
public class MyAdapter extends RecyclerView.Adapter<com.example.myapplication.MyAdapter.MyViewHolder> {
private Context context;
private List<HeadlineModel> headlineModelList;
public MyAdapter(Context context, List<HeadlineModel> headlineModelList) {
this.context = context;
this.headlineModelList = headlineModelList;
}
#NonNull
#Override
public com.example.myapplication.MyAdapter.MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from(context).inflate(R.layout.news_item_layout,parent,false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final com.example.myapplication.MyAdapter.MyViewHolder holder, int position) {
final HeadlineModel headlineModel=headlineModelList.get(position);
holder.newTitle.setText(headlineModel.getTitle());
holder.newsDescription.setText(headlineModel.getDescription());
holder.newsDescription.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Uri uri= Uri.parse(headlineModel.getUrl());
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
context.startActivity(intent);
//Log.v("SSSSSS",headlineModel.getUrl());
}
});
holder.newsName.setText(headlineModel.getName());
holder.newsTime.setText(headlineModel.getPublishedAt());
Glide.with(context).load(headlineModel.getUrlToImage())
.thumbnail(0.5f)
.into(holder.newsImage);
}
#Override
public int getItemCount() {
return headlineModelList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView newTitle;
TextView newsDescription;
TextView newsName;
TextView newsTime;
ImageView newsImage;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
newTitle=itemView.findViewById(R.id.tv_news_title);
newsDescription=itemView.findViewById(R.id.tv_news_desc);
newsName=itemView.findViewById(R.id.tv_name);
newsTime=itemView.findViewById(R.id.tv_news_date);
newsImage=itemView.findViewById(R.id.im_news_image);
}
}
}
The recycler view in onCreateView in my fragment is initialized like this:
RecyclerView recyclerView;
com.example.myapplication.MyAdapter myAdapter;
private ProgressDialog progressDialog;
List<com.example.myapplication.HeadlineModel> headlineModelList;
private static final String URL="http://newsapi.org/v2/top-headlines?country=in&apiKey=cbd46bd6a4f54fe69d0cb261dbe1a878";
public HeadlinesFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootview=inflater.inflate(R.layout.fragment_headlines, container, false);
// Inflate the layout for this fragment
recyclerView=rootview.findViewById(R.id.headRecyclerView);
headlineModelList=new ArrayList<>();
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL,false));
progressDialog=new ProgressDialog(getContext(),R.style.ProgressColor);
progressDialog.setMessage("loading...");
progressDialog.show();
loadData();
return rootview;
}
loadData() function that is called
private void loadData() {
progressDialog.setMessage("Loading data...");
//progressDialog.show();
JsonObjectRequest jsonObjectRequest=new JsonObjectRequest(Request.Method.GET, URL, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
progressDialog.dismiss();
try {
JSONArray jsonArray=response.getJSONArray("articles");
for (int i=0;i<jsonArray.length();i++){
JSONObject jsonObject=jsonArray.getJSONObject(i);
String title=jsonObject.getString("title");
String desc=jsonObject.getString("description");
String url=jsonObject.getString("url");
String urlToImage=jsonObject.getString("urlToImage");
String publishedAt=jsonObject.getString("publishedAt");
JSONObject source=jsonObject.getJSONObject("source");
String name=source.getString("name");
// for formatting time and date //
String year=publishedAt.substring(0,4);
String month=publishedAt.substring(5,7);
String date=publishedAt.substring(8,10);
String hour=publishedAt.substring(11,13);
//String hour="11";
String min=publishedAt.substring(14,16);
//Log.v("XXXXXX",min);
String updatedDate=date.concat("-").concat(month).concat("-").concat(year).concat(" ");
String print="";
int convertHour= Integer.parseInt(hour);
int convertMin= Integer.parseInt(min);
if (convertHour==12) {
convertHour=12;
print="PM";
}
else if (convertHour>11&&convertMin>0){
convertHour=convertHour-12;
print="PM";
}else {
print="AM";
}
String newHour= String.valueOf(convertHour);
String updatedTime=updatedDate.concat(newHour).concat(":").concat(min).concat(" ").concat(print);
myAdapter=new com.example.myapplication.MyAdapter(getContext(),headlineModelList);
com.example.myapplication.HeadlineModel headlineModel=new com.example.myapplication.HeadlineModel(name,title,desc,url,urlToImage,updatedTime);
headlineModelList.add(headlineModel);
recyclerView.setAdapter(myAdapter);
myAdapter.notifyDataSetChanged();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
})
{
#Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
Cache.Entry cacheEntry = HttpHeaderParser.parseCacheHeaders(response);
if (cacheEntry == null) {
cacheEntry = new Cache.Entry();
}
final long cacheHitButRefreshed = 3 * 60 * 1000; // in 3 minutes cache will be hit, but also refreshed on background
final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely
long now = System.currentTimeMillis();
final long softExpire = now + cacheHitButRefreshed;
final long ttl = now + cacheExpired;
cacheEntry.data = response.data;
cacheEntry.softTtl = softExpire;
cacheEntry.ttl = ttl;
String headerValue;
headerValue = response.headers.get("Date");
if (headerValue != null) {
cacheEntry.serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue);
}
headerValue = response.headers.get("Last-Modified");
if (headerValue != null) {
cacheEntry.lastModified = HttpHeaderParser.parseDateAsEpoch(headerValue);
}
cacheEntry.responseHeaders = response.headers;
final String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(new JSONObject(jsonString), cacheEntry);
} catch (UnsupportedEncodingException | JSONException e) {
return Response.error(new ParseError(e));
}
}
#Override
protected void deliverResponse(JSONObject response) {
super.deliverResponse(response);
}
#Override
public void deliverError(VolleyError error) {
super.deliverError(error);
}
#Override
protected VolleyError parseNetworkError(VolleyError volleyError) {
return super.parseNetworkError(volleyError);
}
};
RequestQueue queue= Volley.newRequestQueue(getContext());
queue.add(jsonObjectRequest);
}
Does anyone know what I'm doing wrong?
Set the Adapter before the API call success because your API response is async and till will take time depending upon response size, network speed etc, till that time recycler view needs to be created and it is having no adapter.
You can set adaptor before calling loadData() and later when you get the list of response set the data in the adapter of your recylerview and call notify on the adapter.
myAdapter=new com.example.myapplication.MyAdapter(getContext(),headlineModelList);
recyclerView.setAdapter(myAdapter);
use it on onCreateView method and myAdapter.notifyDataSetChanged(); use it when API success
When I run the app, nothing is visible. Please help me
There seems to be no problem, but I have been wondering about this for a few days.
The debugger shows this warning message:
Android E/RecyclerView: No adapter attached; skipping layout
I don't know what the hell is wrong.
Here is my MainActivity code
private void setUrl(final String dateUrl)
{
myRecyclerView.setAlpha(0.5f);
loadingPanel.setVisibility(View.VISIBLE);
noteTextView.setVisibility(View.GONE);
new Thread(new Runnable() {
#Override
public void run() {
url = "http://data.nba.net/10s/prod/v1/" + dateUrl + "/scoreboard.json";
final RequestQueue requestQueue = Volley.newRequestQueue(NbaApp.getCurrentActivity());
JsonObjectRequest objectRequest = new JsonObjectRequest(Request.Method.GET, url,null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
jsonObject = response;
gameCardsCreater = new GameCardsCreater(jsonObject);
if (gameCardsCreater.isGameNight()) {
runOnUiThread(new Runnable() {
#Override
public void run() {
gameCardsCreater.populateCards();
setCardsCreater();
myRecyclerView.setEnabled(true);
myRecyclerView.setVisibility(View.VISIBLE);
loadingPanel.setVisibility(View.GONE);
myRecyclerView.setAlpha(1);
runLayoutAnimation(myRecyclerView);
}
});
} else {
myRecyclerView.setEnabled(false);
myRecyclerView.setVisibility(View.GONE);
noteTextView.setVisibility(View.VISIBLE);
noteTextView.setText(R.string.no_games_tonight);
loadingPanel.setVisibility(View.GONE);
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
myRecyclerView.setEnabled(false);
myRecyclerView.setVisibility(View.GONE);
noteTextView.setVisibility(View.VISIBLE);
noteTextView.setText(R.string.error_getting_info);
loadingPanel.setVisibility(View.GONE);
}
});
requestQueue.add(objectRequest);
}
}).start();
}
#SuppressLint("ClickableViewAccessibility")
public void setCardsCreater() {
gameArrayList = new ArrayList<>();
gameArrayList = gameCardsCreater.getGameArrayList();
GameAdapter adapter = new GameAdapter(gameArrayList, new CustomItemClickListener() {
#Override
public void onItemClick(View v, int position) {
if (isNetworkConnected()) {
Intent myIntent = new Intent(MainActivity.this, GameActivity.class);
Bundle extras = new Bundle();
extras.putString("gameDate", gameArrayList.get(position).getGameDate());
extras.putString("gameId", gameArrayList.get(position).getGameId());
extras.putString("homeTeamWins", gameArrayList.get(position).getHomeTeamWins());
extras.putString("awayTeamWins", gameArrayList.get(position).getAwayTeamWins());
extras.putBoolean("isGameActivated", gameArrayList.get(position).isGameActive());
extras.putString("homeTeamName", gameArrayList.get(position).getHomeTeamName());
extras.putString("awayTeamName", gameArrayList.get(position).getAwayTeamName());
extras.putBoolean("isGameOver", gameArrayList.get(position).isGameOver());
overridePendingTransition(R.anim.fadein, R.anim.fadeout);
myIntent.putExtras(extras);
MainActivity.this.startActivity(myIntent);
} else {
Toast.makeText(NbaApp.getCurrentActivity(), "Check your internet connection", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onItemLongClick(View v, int position) {
}
});
myRecyclerView.setHasFixedSize(true);
myRecyclerView.setAdapter(adapter);
LinearLayoutManager llm = new LinearLayoutManager(this);
llm.setOrientation(LinearLayoutManager.VERTICAL);
myRecyclerView.setLayoutManager(llm);
}
2.Here is my RecyclerView adapter code, GameAdapter
public class GameAdapter extends RecyclerView.Adapter<GameAdapter.MyViewHolder> {
private final CustomItemClickListener listener;
private ArrayList<Game> gameList;
public GameAdapter(ArrayList<Game> myValues, CustomItemClickListener listener) {
this.gameList = myValues;
this.listener = listener;
}
static class MyViewHolder extends RecyclerView.ViewHolder {
private TextView homeTeamNameTextView;
private TextView awayTeamNameTextView;
private ImageView awayTeamLogoImageView;
private ImageView homeTeamLogoImageView;
private TextView awayTeamScoreTextView;
private TextView homeTeamScoreTextView;
private TextView awayTeamWinsTextView;
private TextView homeTeamWinsTextView;
private TextView nuggetTextView;
private TextView gameTimeTextView;
MyViewHolder(View itemView) {
super(itemView);
awayTeamNameTextView = itemView.findViewById(R.id.awayteamname);
homeTeamNameTextView = itemView.findViewById(R.id.hometeamname);
awayTeamLogoImageView = itemView.findViewById(R.id.awayteamlogo);
homeTeamLogoImageView = itemView.findViewById(R.id.hometeamlogo);
awayTeamScoreTextView = itemView.findViewById(R.id.awayteamscore);
homeTeamScoreTextView = itemView.findViewById(R.id.hometeamscore);
awayTeamWinsTextView = itemView.findViewById(R.id.awayteamwins);
homeTeamWinsTextView = itemView.findViewById(R.id.hometeamwins);
nuggetTextView = itemView.findViewById(R.id.nuggettext);
gameTimeTextView = itemView.findViewById(R.id.gameTime);
}
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View listItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_view_game, parent, false);
final MyViewHolder myViewHolder = new MyViewHolder(listItem);
listItem.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.onItemClick(v, myViewHolder.getAdapterPosition());
}
});
return myViewHolder;
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
Game game = gameList.get(position);
holder.homeTeamNameTextView.setText(game.getHomeTeamName());
holder.awayTeamNameTextView.setText(game.getAwayTeamName());
Picasso.get().load(game.getAwayTeamImage()).into(holder.awayTeamLogoImageView);
Picasso.get().load(game.getHomeTeamImage()).into(holder.homeTeamLogoImageView);
holder.awayTeamScoreTextView.setText(game.getAwayTeamScore());
holder.homeTeamScoreTextView.setText(game.getHomeTeamScore());
holder.awayTeamWinsTextView.setText(game.getAwayTeamWins());
holder.homeTeamWinsTextView.setText(game.getHomeTeamWins());
if (game.getNugget().isEmpty())
holder.nuggetTextView.setVisibility(View.GONE);
else
holder.nuggetTextView.setText(game.getNugget());
holder.gameTimeTextView.setText(game.getGameTime());
if (game.isGameActive())
holder.gameTimeTextView.setTextColor(Color.parseColor("#ff0000"));
else
holder.gameTimeTextView.setTextColor(Color.parseColor("#B4B4B4"));
if (!game.getHomeTeamScore().isEmpty() && !game.getAwayTeamScore().isEmpty()) {
if (Integer.parseInt(game.getHomeTeamScore()) > Integer.parseInt(game.getAwayTeamScore())) {
holder.homeTeamScoreTextView.setTextColor(Color.parseColor("#ffffff"));
holder.awayTeamScoreTextView.setTextColor(Color.parseColor("#B4B4B4"));
} else if (Integer.parseInt(game.getHomeTeamScore()) < Integer.parseInt(game.getAwayTeamScore())) {
holder.homeTeamScoreTextView.setTextColor(Color.parseColor("#B4B4B4"));
holder.awayTeamScoreTextView.setTextColor(Color.parseColor("#ffffff"));
} else {
holder.homeTeamScoreTextView.setTextColor(Color.parseColor("#B4B4B4"));
holder.awayTeamScoreTextView.setTextColor(Color.parseColor("#B4B4B4"));
}
}
}
#Override
public int getItemCount() {
return gameList.size();
}
}
i want create a fragment and have inside a recycler view for show products ...
but when i render it is show this error : RecyclerView: No adapter attached; skipping layout
below i copy my codes;
this code is for adapter class :
private ArrayList<Products> ProductsList;
private Context context;
public Adapter(ArrayList<Products> productsList, Context context) {
ProductsList = productsList;
this.context = context;
}
#Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.row_layout, parent, false);
return new MyHolder(v);
}
#Override
public void onBindViewHolder(MyHolder holder, final int position) {
Products products = ProductsList.get(position);
holder.txtName.setText(products.getName());
holder.txtPrice.setText("$ " + products.getPrice());
Picasso.get().load(Config.ipValue + "/images/" + products.getPhoto()).into(holder.imgV);
holder.imgV.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
v.startAnimation(AnimationUtils.loadAnimation(context, android
.R.anim.slide_in_left));
}
});
}
#Override
public int getItemCount() {
return ProductsList.size();
}
class MyHolder extends RecyclerView.ViewHolder {
TextView txtName;
TextView txtPrice;
ImageView imgV;
public MyHolder(View itemView) {
super(itemView);
txtName = itemView.findViewById(R.id.rowTxtProductName);
txtPrice = itemView.findViewById(R.id.rowTxtPrice);
imgV = itemView.findViewById(R.id.rowImgProduct);
}
}
and this one for web api class :
public class WebApiHandler {
Context context;
String apiLink = "";
ArrayList<Products> products = new ArrayList<>();
public WebApiHandler(Context context) {
this.context = context;
}
void apiConnect(String type) {
switch (type) {
case "getproducts": {
apiLink = Config.getProductsWebApi;
break;
}
}
ProgressDialog dialog = ProgressDialog.show(context, "Connecting...",
"please wait", false, false);
StringRequest request = new StringRequest(Request.Method.POST,
apiLink, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
dialog.dismiss();
showJson(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
dialog.dismiss();
}
});
RequestQueue queue = Volley.newRequestQueue(context);
queue.add(request);
}
private void showJson(String response) {
products.clear();
try {
JSONObject jsonObject = new JSONObject(response);
JSONArray jsonArray = jsonObject.getJSONArray("response");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject object = jsonArray.getJSONObject(i);
String id = object.getString("id");
String name = object.getString("name");
String description = object.getString("description");
String price = object.getString("price");
String photo = object.getString("photo");
Products p = new Products(id, name, description, price, photo);
products.add(p);
}
} catch (JSONException e) {
e.printStackTrace();
}
VerticalFragment.productsArrayList = products;
IData iData = (IData) context;
iData.sendData();
}}
and my fragment code :
public class VerticalFragment extends Fragment implements IData {
RecyclerView rcVertical;
WebApiHandler webApiHandler;
static ArrayList<Products> productsArrayList = new ArrayList<>();
public VerticalFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_vertical, container, false);
rcVertical = view.findViewById(R.id.rcVertical);
webApiHandler = new WebApiHandler(getContext());
webApiHandler.apiConnect("getproducts");
rcVertical.addOnItemTouchListener(new RecyclerTouchListener(getContext(), rcVertical,
new RecyclerTouchListener.ClickListener() {
#Override
public void onClick(View view, int position) {
ProductActivity.products = productsArrayList.get(position);
startActivity(new Intent(getContext(), ProductActivity.class));
}
#Override
public void onLongClick(View view, int position) {
}
}));
return view;
}
#Override
public void sendData() {
Adapter adapter = new Adapter(productsArrayList, getContext());
rcVertical.setLayoutManager(new LinearLayoutManager((getContext())));
rcVertical.setItemAnimator(new DefaultItemAnimator());
rcVertical.setAdapter(adapter);
}}
i should say i create a interface and have one method i say it sendData
This is a common error when there is no adapter attached to recyclerview upon showing recyclerview. It will not cause any harm to your app, but you could avoid it by setting empty adapter without data, and later when you get your data, provide it to your adapter and notify it
Edit - Example added
Create setter for your list in adapter. After that, in your fragment make adapter global and in onCreateView make instance of your adapter and attach it to recyclerview
adapter = new Adapter(new ArrayList<>(), getContext());
rcVertical.setAdapter(adapter);
...Initialize recyclerview...
And then in your sendData interface put your loaded values in it
adapter.setData(productsArrayList);
adapter.notifyDataSetChanged();
I want to implement one code where data will come on Scroll and if the data is add on list then we pull down(SwipeRefreshLayout) the new data will come on that list. In my below code the add on data is coming in response but not come in list? I have read many tutorials like this but data is coming on Swipe refresh but not shown on list. Thank you in advance
public class UpdatesFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener{
SwipeRefreshLayout mSwipeRefreshLayout;
UserSessionManager session;
private List<SuperHero> listSuperHeroes;
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
private RecyclerView.Adapter adapter;
public ProgressBar progressBar;
public String user_id;
TextView textView;
FloatingActionButton fab;
public int a=1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.fragment_updates, container, false);
session = new UserSessionManager(getActivity());
// get user data from session
HashMap<String, String> user = session.getUserDetails();
user_id = user.get(UserSessionManager.KEY_USER_ID);
// SwipeRefreshLayout
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_container);
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary,
android.R.color.holo_green_dark,
android.R.color.holo_orange_dark,
android.R.color.holo_blue_dark);
/**
* Showing Swipe Refresh animation on activity create
* As animation won't start on onCreate, post runnable is used
*/
mSwipeRefreshLayout.post(new Runnable() {
#Override
public void run() {
mSwipeRefreshLayout.setRefreshing(true);
// Fetching data from server
getDataFromServer(1);
}
});
return view;
}
public void onViewCreated(View v, Bundle savedInstanceState) {
super.onViewCreated(v, savedInstanceState);
fab = (FloatingActionButton)v.findViewById(R.id.fab);
recyclerView = (RecyclerView) v.findViewById(R.id.updatesRecycler);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(layoutManager);
listSuperHeroes = new ArrayList<>();
adapter = new CardAdapter(listSuperHeroes, getActivity());
recyclerView.setAdapter(adapter);
textView = (TextView)v.findViewById(R.id.text);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(getContext(), AddWebPostActivity.class);
startActivity(i);
}
});
getDataFromServer(a);
recyclerView.setOnScrollListener(new EndlessRecyclerOnScrollListener((LinearLayoutManager) layoutManager) {
#Override
public void onLoadMore(int current_page) {
getDataFromServer(current_page);
}
});
}
public void getDataFromServer(int requestCount) {
Log.e("count",String.valueOf(requestCount));
final String DATA_URL = "https://XYZ.php?username="+user_id + "&page="+requestCount;
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(DATA_URL,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
mSwipeRefreshLayout.setRefreshing(false);
Log.e("URL___________",DATA_URL);
Log.e("response___________", String.valueOf(response));
parseData(response);
adapter.notifyDataSetChanged();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getContext(), "No More Items Available", Toast.LENGTH_SHORT).show();
}
});
RequestQueue requestQueue = Volley.newRequestQueue(getContext());
requestQueue.getCache().clear();
requestQueue.add(jsonArrayRequest);
}
private void parseData(JSONArray array) {
for (int i = 0; i < array.length(); i++) {
SuperHero superHero = new SuperHero();
JSONObject json = null;
try {
json = array.getJSONObject(i);
superHero.setPost_title(json.getString(Config.TAG_POST_TITLE));
superHero.setPost_content(json.getString(Config.TAG_POST_CONTENT));
superHero.setPost_parent(json.getString(Config.TAG_POST_PARENT));
superHero.setPost_date(json.getString(Config.TAG_POST_DATE));
superHero.setPost_date_gmt(json.getString(Config.TAG_POST_DATE_GMT));
superHero.setScheduled_date(json.getString(Config.TAG_SCHEDULED_DATE));
superHero.setTo_ping(json.getString(Config.TAG_IP_ADDRESS));
superHero.setVisit_post(json.getString(Config.TAG_VISIT_POST));
superHero.setUr_id(json.getString(Config.TAG_UR_ID));
} catch (JSONException e) {
e.printStackTrace();
}
listSuperHeroes.add(superHero);
}
}
/**
* Called when a swipe gesture triggers a refresh.
*/
#Override
public void onRefresh() {
getDataFromServer(1);
}
}
Adapter
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> {
UserSessionManager session;
public String user_id;
public String ur_id;
private Context context;
//String visit;
//List to store all superheroes
List<SuperHero> superHeroes;
//Constructor of this class
public CardAdapter(List<SuperHero> superHeroes, Context context){
super();
//Getting all superheroes
this.superHeroes = superHeroes;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.web_post, parent, false);
// Session class instance
session = new UserSessionManager(context);
session.checkLogin();
// get user data from session
HashMap<String, String> user = session.getUserDetails();
user_id = user.get(UserSessionManager.KEY_USER_ID);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
//Getting the particular item from the list
final SuperHero superHero = superHeroes.get(position);
holder.tvPostTitle.setText(superHero.getPost_title());
holder.tvPostContent.setText(superHero.getPost_content());
holder.tvPostDateTime1.setText(superHero.getPost_date() +" / " +superHero.getPost_date_gmt());
final String visit = superHero.getVisit_post();
holder.tvVisitPost.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent(context,VisitWebView.class);
i.putExtra("visitURL",visit);
context.startActivity(i);
}
});
}
#Override
public int getItemCount() {
return superHeroes.size();
}
#Override
public int getItemViewType(int position) {
return position;
}
class ViewHolder extends RecyclerView.ViewHolder{
//Views
public TextView tvPostTitle,tvPostContent,tvPostDateTime1,tvVisitPost;
public ImageButton removeButton;
//Initializing Views
public ViewHolder(final View itemView) {
super(itemView);
tvPostTitle = (TextView) itemView.findViewById(R.id.tvPostTitle);
tvPostContent = (TextView) itemView.findViewById(R.id.tvPostContent);
tvPostDateTime1 = (TextView) itemView.findViewById(R.id.tvPostDateTime1);
tvVisitPost = (TextView) itemView.findViewById(R.id.tvVisitPost);
removeButton = (ImageButton) itemView.findViewById(R.id.removeButton);
}
}
}
use this method
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
mSwipeRefreshLayout.setRefreshing(true);
getDataFromServer(1);
}
instead of this
mSwipeRefreshLayout.post(new Runnable() {
#Override
public void run() {
mSwipeRefreshLayout.setRefreshing(true);
// Fetching data from server
getDataFromServer(1);
}
});
Please call adapter and pass fresh list data after this line
listSuperHeroes.add(superHero) in parseData(response) function ;
adapter = new CardAdapter(listSuperHeroes, getActivity());
recyclerView.setAdapter(adapter)
adapter.notifyDataSetChanged();