Reputation: 111
Please I tried to solve this problem for two days ago.. I saw most of the solutions provided in the website but no one solved my problem..
The app has stopped and I get this error: E/RecyclerView: No adapter attached; skipping layout
Here is my MainActivity:
public class MainActivity extends AppCompatActivity {
RecyclerView listWebsite;
RecyclerView.LayoutManager layoutManager;
NewsService mService;
ListSourceAdapter adapter;
AlertDialog dialog;
SwipeRefreshLayout swipeLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
swipeLayout = (SwipeRefreshLayout)findViewById(R.id.swipeRefresh);
swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
loadWebsiteSource(true);
}
});
Paper.init(this);
mService = Common.getNewsService();
listWebsite = (RecyclerView)findViewById(R.id.list_source);
listWebsite.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
listWebsite.setLayoutManager(layoutManager);
dialog = new SpotsDialog(this);
loadWebsiteSource(true);
}
private void loadWebsiteSource(boolean isRefreshed) {
if(!isRefreshed)
{
String cache = Paper.book().read("cache");
if(cache != null && !cache.isEmpty())
{
// Convert cache from Json to Object
WebSite website = new Gson().fromJson(cache, WebSite.class);
adapter = new ListSourceAdapter(getBaseContext(), website);
adapter.notifyDataSetChanged();
listWebsite.setAdapter(adapter);
}
else
{
dialog.show();
mService.getSources().enqueue(new Callback<WebSite>() {
@Override
public void onResponse(Call<WebSite> call, Response<WebSite> response) {
adapter = new ListSourceAdapter(getBaseContext(), response.body());
adapter.notifyDataSetChanged();
listWebsite.setAdapter(adapter);
Paper.book().write("cache", new Gson().toJson(response.body()));
}
@Override
public void onFailure(Call<WebSite> call, Throwable t) {
}
});
}
}
else
{
dialog.show();
mService.getSources().enqueue(new Callback<WebSite>() {
@Override
public void onResponse(Call<WebSite> call, Response<WebSite> response) {
adapter = new ListSourceAdapter(getBaseContext(), response.body());
adapter.notifyDataSetChanged();
listWebsite.setAdapter(adapter);
Paper.book().write("cache", new Gson().toJson(response.body()));
swipeLayout.setRefreshing(false);
}
@Override
public void onFailure(Call<WebSite> call, Throwable t) {
}
});
}
}
}
and here's my adapter:
class ListSourceViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
ItemClickListener itemClickListener;
TextView source_title;
CircleImageView source_image;
public ListSourceViewHolder(View itemView) {
super(itemView);
source_image = (CircleImageView)itemView.findViewById(R.id.source_image);
source_title = (TextView)itemView.findViewById(R.id.source_name);
}
public void setItemClickListener(ItemClickListener itemClickListener){
this.itemClickListener = itemClickListener;
}
@Override
public void onClick(View view) {
}
}
public class ListSourceAdapter extends RecyclerView.Adapter<ListSourceViewHolder>{
private Context context;
private WebSite webSite;
private IconBetterIdeaService mService;
public ListSourceAdapter(Context baseContext, WebSite website) {
this.context = baseContext;
this.webSite = website;
mService = Common.getIconService();
}
@Override
public ListSourceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.source_layout, parent, false);
return new ListSourceViewHolder(itemView);
}
@Override
public void onBindViewHolder(final ListSourceViewHolder holder, int position) {
StringBuilder iconBetterApi = new StringBuilder("https://icons.better-idea.org/allicons.json?url=");
iconBetterApi.append(webSite.getSources().get(position).getUrl());
mService.getIconUrl(iconBetterApi.toString())
.enqueue(new Callback<IconBetterIdea>() {
@Override
public void onResponse(Call<IconBetterIdea> call, Response<IconBetterIdea> response) {
if(response.body().getIcons().size() > 0)
{
Picasso.with(context)
.load(response.body().getIcons().get(0).getUrl())
.into(holder.source_image);
}
}
@Override
public void onFailure(Call<IconBetterIdea> call, Throwable t) {
}
});
holder.source_title.setText(webSite.getSources().get(position).getName());
holder.setItemClickListener(new ItemClickListener() {
@Override
public void onClick(View view, int position, boolean isLongClick) {
}
});
}
@Override
public int getItemCount() {
return webSite.getSources().size();
}
}
Here's the Website class:
public class WebSite {
private String status;
private List<Source> sources;
public WebSite() {
}
public WebSite(String status, List<Source> sources) {
this.status = status;
this.sources = sources;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public List<Source> getSources() {
return sources;
}
public void setSources(List<Source> sources) {
this.sources = sources;
}
}
and here's the Source class:
public class Source {
private String id;
private String name;
private String description;
private String url;
private String category;
private String language;
private String country;
private UrlsToLogos urlsToLogos;
private List<String> sortBysAvailable;
public Source() {
}
public Source(String id, String name, String description, String url, String category, String language, String country, UrlsToLogos urlsToLogos, List<String> sortBysAvailable) {
this.id = id;
this.name = name;
this.description = description;
this.url = url;
this.category = category;
this.language = language;
this.country = country;
this.urlsToLogos = urlsToLogos;
this.sortBysAvailable = sortBysAvailable;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public UrlsToLogos getUrlsToLogos() {
return urlsToLogos;
}
public void setUrlsToLogos(UrlsToLogos urlsToLogos) {
this.urlsToLogos = urlsToLogos;
}
public List<String> getSortBysAvailable() {
return sortBysAvailable;
}
public void setSortBysAvailable(List<String> sortBysAvailable) {
this.sortBysAvailable = sortBysAvailable;
}
}
I'm using the newsapi.org api that retrieve the sources of news..
Upvotes: 0
Views: 79
Reputation: 158
Please read the error message... You do not have a Adapter attached to your RecyclerView
. In several of your execution paths, you only add an Adapter in a callback that is executed later on. Make sure that you are setting an Adapter for all conditions, and then update the Website data that you passed into the Adapter after you receive your response.
I'm thinking your else statement of loadWebsiteSource
would look some like:
else
{
dialog.show();
website = new WebSite(); //Whatever this object is
adapter = new ListSourceAdapter(getBaseContext(), website);
listWebsite.setAdapter(adapter)
mService.getSources().enqueue(new Callback<WebSite>() {
@Override
public void onResponse(Call<WebSite> call, Response<WebSite> response) {
website.update(response.body());
adapter.notifyDataSetChanged();
Paper.book().write("cache", new
Gson().toJson(response.body()));
swipeLayout.setRefreshing(false);
}
@Override
public void onFailure(Call<WebSite> call, Throwable t) {
}
});
}
Also as a note, you don't really want to be instantiating new Adapters
every time you fetch the data. Hold a reference to the Adapter
and the Data Set that the Adapter
represents, in this case WebSite, then update the WebSite Object (do not create new instances of this object either, update the state), and call one of the notify methods on the Adapter
Edit: The WebSite::update method could look something like:
public void update(WebSite newWebSiteData){
this.sources.clearAll();
this.sources.addAll(newWebSiteData.getSources());
this.sources.setStatus(newWebSiteData.getStatus());
}
Upvotes: 1