When I am writing the title of my question, then this site recommends me some answer but I can't find my answer that's why I am writing a new one. I am trying simple RecyclerView and it's run successfully but when I am fetching data from internet using volley library then I face this error
here is my code
BusinessActivity.java
public class BusinessActivity extends AppCompatActivity {
private final String URL = "https://api.myjson.com/bins/a44ec";
private JsonArrayRequest request;
private RequestQueue requestQueue;
private List<ArticleModel> articleList;
private RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_business);
articleList = new ArrayList<>();
recyclerView = findViewById(R.id.business_recyclerView);
jsonParse();
}
private void jsonParse() {
request = new JsonArrayRequest(URL, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
JSONObject jsonObject = null;
for (int i=0;i<response.length();i++){
try {
jsonObject = response.getJSONObject(i);
ArticleModel article = new ArticleModel();
article.setTitle(jsonObject.getString("title"));
article.setAuthor(jsonObject.getString("author"));
article.setDescription(jsonObject.getString("description"));
article.setPublishedAt(jsonObject.getString("publishedAt"));
article.setUrlToImage(jsonObject.getString("urlToImage"));
articleList.add(article);
} catch (JSONException e) {
e.printStackTrace();
}
}
setRecyclerView(articleList);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
requestQueue = Volley.newRequestQueue(BusinessActivity.this);
requestQueue.add(request);
}
private void setRecyclerView(List<ArticleModel> articleList) {
BusinessAdapter adapter = new BusinessAdapter(articleList,this);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
}
}
BusinessAdapter.java
public class BusinessAdapter extends RecyclerView.Adapter<BusinessAdapter.MyViewHolder> {
private List<ArticleModel> articleModels;
private Context context;
RequestOptions options;
public BusinessAdapter(List<ArticleModel> articleModels, Context context) {
this.articleModels = articleModels;
this.context = context;
options = new RequestOptions().centerCrop().placeholder(R.drawable.ic_launcher_background).error(R.drawable.ic_launcher_background);
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.category_row,parent,false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
ArticleModel articleModel = articleModels.get(position);
holder.title.setText(articleModel.getTitle());
holder.author.setText(articleModel.getAuthor());
holder.desc.setText(articleModel.getDescription());
holder.date.setText(articleModel.getPublishedAt());
Glide.with(context).load(articleModel.getUrlToImage()).apply(options).into(holder.image);
}
#Override
public int getItemCount() {
return articleModels.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView title,author,desc,date;
ImageView image;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
author = itemView.findViewById(R.id.author);
desc = itemView.findViewById(R.id.detail);
date = itemView.findViewById(R.id.date);
image = itemView.findViewById(R.id.image);
}
}
}
Error log
2020-04-01 00:15:53.117 8821-8821/com.atc.newsappproject E/RecyclerView: No adapter attached; skipping layout
2020-04-01 00:15:53.118 1752-1787/? E/storaged: getDiskStats failed with result NOT_SUPPORTED and size 0
How can I solve this?
Thank you.
This error usually happens when you don't set the RecyclerView when you create your Fragment or Activity. To fix this you need to:
Set your RecyclerView in onCreate instead of when you pick up result. You set it with an empty list.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_business);
articleList = new ArrayList<>();
recyclerView = findViewById(R.id.business_recyclerView);
setRecyclerView(articleList);
jsonParse();
}
You create a setter in your Adapter
public void setArticles(ArrayList<ArticleModel> articles){
this.articles = articles;
notifyDataSetChanged();
}
Create private BusinessAdapter adapter; below private RecyclerView recyclerView;
Finally in your onResponse you call adapter.setArticles(articlesList);
Here is a link with a lot of solutions if you still got issue: recyclerview No adapter attached; skipping layout
Related
I can't get my code work
I'm trying to get a list of my database activities.
A lot of research here and none of the answers helped me
My Adapter
public class AtividadesAdapter extends RecyclerView.Adapter<AtividadesAdapter.AtividadesViewHolder> {
private Context mCtx;
private List<Atividades> atividadesList;
public AtividadesAdapter(Context mCtx, List<Atividades> atividadesList) {
this.mCtx = mCtx;
this.atividadesList = atividadesList;
}
#Override
public AtividadesViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mCtx);
View view = inflater.inflate(R.layout.atividades_lista, null);
return new AtividadesViewHolder(view);
}
#Override
public void onBindViewHolder(AtividadesViewHolder holder, int position) {
Atividades atividades = atividadesList.get(position);
holder.textViewAtividade.setText(atividades.getAtividade());
holder.textViewData.setText(String.valueOf(atividades.getDataPrevista()));
holder.textViewHora.setText(String.valueOf(atividades.getHora()));
holder.textViewDestinatarios.setText(atividades.getDestinatarios());
}
#Override
public int getItemCount() {
return atividadesList.size();
}
class AtividadesViewHolder extends RecyclerView.ViewHolder {
TextView textViewAtividade, textViewData, textViewHora, textViewDestinatarios;
public AtividadesViewHolder(View itemView) {
super(itemView);
textViewAtividade = itemView.findViewById(R.id.textViewAtividade);
textViewData = itemView.findViewById(R.id.textViewData);
textViewHora = itemView.findViewById(R.id.textViewHora);
textViewDestinatarios = itemView.findViewById(R.id.textViewDestinatarios);
}
}
}
My activity
public class AtividadesActivity extends AppCompatActivity {
private static final String URL_ATIVIDADES = "";
List<Atividades> atividadesList = new ArrayList<>();
public RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.atividadesrecyclerview);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
loadAtividades();
}
private void loadAtividades() {
StringRequest stringRequest = new StringRequest(Request.Method.GET, URL_ATIVIDADES,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONArray array = new JSONArray(response);
for (int i = 0; i < array.length(); i++) {
JSONObject a = array.getJSONObject(i);
Log.d("Valores", a.getString("Atividade"));
atividadesList.add(new Atividades(
a.getInt("idAtividade"),
a.getString("Atividade"),
java.sql.Date.valueOf(a.getString("dataPrevista")),
java.sql.Time.valueOf(a.getString("hora")),
a.getString("Destinatarios"),
a.getString("Local")
));
}
AtividadesAdapter mAdapter = new AtividadesAdapter(AtividadesActivity.this, atividadesList);
recyclerView.setAdapter(mAdapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
Volley.newRequestQueue(this).add(stringRequest);
}
}
Everytime i'm trying to start the app, i get this error.
I have already change the xml files to match with the examples provided here but still have no success.
Please attach parent and the rest:
#Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
return new AtividadesViewHolder(LayoutInflater.from(mCtx).inflate(R.layout.atividades_lista, parent, false));
}
Based on your question and the code I think this will help you.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.atividadesrecyclerview);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
AtividadesAdapter mAdapter = new AtividadesAdapter(getApplicationContext, atividadesList);
recyclerView.setAdapter(mAdapter);
loadAtividades();
}
Add to your adapter:
public AtividadesAdapter(Context mCtx) {
this.mCtx = mCtx;
}
public void setItems(#NonNull final List<Atividades> items) {
if (atividadesList != null) {
atividadesList.clear();
} else {
atividadesList = new ArrayList<>();
}
atividadesList.addAll(items);
}
onCreate of the activity should be as follows:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.atividadesrecyclerview);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
mAdapter = new AtividadesAdapter(AtividadesActivity.this);
recyclerView.setAdapter(mAdapter);
loadAtividades();
}
In loadAtividades() call to setItems:
mAdapter.setItems(atividadesList);
I'm creating an app similar to the instagram app but only admin can add contents. i used python django for my backend but when i add new item to my django database, it comes last on the recyclerview. I want it to be in a way that, when i add new item, it comes first when you open my app like the way instagram shows recent items first.
This is my custom Adapter class
public class DealAdapter extends RecyclerView.Adapter<DealAdapter.DealHolder> {
Context context;
ArrayList<Deal> arrayList;
public DealAdapter(Context context, ArrayList<Deal> arrayList) {
this.context = context;
this.arrayList = arrayList;
}
#Override
public DealHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.deal_cardview, parent, false);
DealHolder dealHolder = new DealHolder(v);
return dealHolder;
}
#Override
public void onBindViewHolder(DealHolder holder, int position) {
Deal deal = arrayList.get(position);
holder.title.setText(deal.getTitle());
Picasso.with(context).
load(deal.getImage()).
placeholder(R.drawable.loading).
error(android.R.drawable.stat_notify_error).
into(holder.image);
}
#Override
public int getItemCount() {
if(arrayList != null) {
return arrayList.size();
}else {
return 0;
}
}
public class DealHolder extends RecyclerView.ViewHolder {
TextView title;
ImageView image;
public DealHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.tvTitle);
image = (ImageView) itemView.findViewById(R.id.ivImage);
}
}
}
This is my main Activity class
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
String TAG = "MainActivity";
ImageButton ibMore;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.rvRecyclerview);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
String url = "http://192.168.43.2/api/deals/?format=json";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
ArrayList<Deal> userList = new JsonConverter<Deal>().
toArrayList(response, Deal.class);
DealAdapter adapter = new DealAdapter(getApplicationContext(), userList);
recyclerView.setAdapter(adapter);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, error.toString());
Toast.makeText(getApplicationContext(), "Something Went wrong: " + "'" + error + "'", Toast.LENGTH_LONG).show();
}
});
MySingleton.getInstance(getApplicationContext()).addToRequestQueue(stringRequest);
}
}
Okay so this is what worked for me. After getting JSON and converting to ArrayList, i called it in "Collections.reverse(arrayList);" before adding it to the adapter as shown below.
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
ArrayList<Deal> userList = new JsonConverter<Deal>().
toArrayList(response, Deal.class);
Collections.reverse(userList);
DealAdapter adapter = new DealAdapter(getApplicationContext(), userList);
recyclerView.setAdapter(adapter);
}
Believe me, only this single line worked for me. Use this :
Collections.reverse(list);
Where list will be your list containing any type of object
Max Billionaire,
If your "userList" contain single item then do like this
adapter.add(0, userList.get(0));
adapter.notifyItemInserted(0);
if you have adapter instance then just refresh the adapter like this
adapter.notifyDataSetChanged();
instead
DealAdapter adapter = new DealAdapter(getApplicationContext(), userList);
recyclerView.setAdapter(adapter);
To display the recent added data to the top of the list do this
yourArrayListOfData.add(0, newAddedData);
adapter.notifyDataSetChanged();
Full Code link : https://github.com/sudhishkr/Flicks/tree/feature/stackoverflow
I am trying to build a movie information display app. I am trying to use recyclerview and that seems to not load my data after a network call.
My MainActivity :
public class MainActivity extends AppCompatActivity {
TextView textView;
RecyclerView recyclerViewTheMovieDB;
RecyclerViewAdapter recyclerViewAdapterTheMovieDB;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerViewTheMovieDB = (RecyclerView) findViewById(R.id.recyclerViewTheMovieDB);
recyclerViewAdapterTheMovieDB = new RecyclerViewAdapter(getApplicationContext());
recyclerViewTheMovieDB.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
recyclerViewTheMovieDB.setAdapter(recyclerViewAdapterTheMovieDB);
textView = (TextView) findViewById(R.id.test2);
VolleyCallback callback = new VolleyCallback() {
#Override
public void onSuccessResponse(ArrayList<Movie> result) {
try {
recyclerViewAdapterTheMovieDB.setMovieList(result);
textView.setText(result.get(0).getTitle());
} catch (Exception e){
}
return;
}
};
final RequestQueue queue = Volley.newRequestQueue(this);
TheMovieDBApi theMovieDBApiObj = new TheMovieDBApi();
theMovieDBApiObj.getMovieList(queue, getApplicationContext(), callback);
}
}
My RecyclerViewAdapter :
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolderTheMovieDB>{
private ArrayList<Movie> listMovies = new ArrayList<>();
private LayoutInflater layoutInflater;
public void setMovieList(ArrayList<Movie> listMovies){
this.listMovies = listMovies;
notifyDataSetChanged();
notifyItemRangeChanged(0, listMovies.size());
}
public RecyclerViewAdapter(Context context){
layoutInflater = LayoutInflater.from(context);
}
#Override
public ViewHolderTheMovieDB onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.layout_inflater_themoviedb, parent, false);
ViewHolderTheMovieDB viewHolderTheMovieDB = new ViewHolderTheMovieDB(view);
return viewHolderTheMovieDB;
}
#Override
public void onBindViewHolder(ViewHolderTheMovieDB holder, int position) {
Movie currentMovie = listMovies.get(position);
try {
holder.title.setText(currentMovie.getTitle());
holder.overview.setText(currentMovie.getOverview());
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public int getItemCount() {
return listMovies.size();
}
static class ViewHolderTheMovieDB extends RecyclerView.ViewHolder{
private TextView title;
private TextView overview;
public ViewHolderTheMovieDB(View itemView){
super(itemView);
title = (TextView) itemView.findViewById(R.id.textViewTitle);
overview = (TextView) itemView.findViewById(R.id.textViewOverview);
}
}
}
When I run this code - the notifyDataSetChanged or the notifyItemRangeChanged doesn't seem to fill the recycler view.
I am also setting my textview with the first item, and that seems to work. I am having a hard time trying to figure out what is going wrong with my RecyclerView. Any help/direction would be great.
please any one explain RecyclerView in fragment using volley to get json data.
Already i refered below link coding Google recyclerview in fragment
this is my first project in android, so i cannot understand that coding.
Please any one help me.
My fragmnet Coding:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View drawer = inflater.inflate(R.layout.fragment_progress, container, false);
orderLists = new ArrayList<>();
getProgressData();
recyclerView = (RecyclerView) drawer.findViewById(R.id.progress);
adapter = new ProgressOrderListAdapter(orderLists, this);
adapter.clearAdaptor();
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
return recyclerView;
}
private void getProgressData(){
String mobilecustomertoken = SharedPreferencesManager.readPreferenceString("MobileCustomerToken", "D/N");
JSONObject progressData = new JSONObject();
try{
progressData.put("mobilecustomertoken", mobilecustomertoken);
JsonObjectRequest progressObject = new JsonObjectRequest(1, Common.OrderDetails + "progress", progressData, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject progressResponse) {
Log.d("Responseprogress", progressResponse.toString());
try {
int status = progressResponse.getInt("status");
if(status == 1) {
progressOrderProgress(progressResponse);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
Log.d("Response", "PROGRESS ERROR");
}
});
progressObject.setShouldCache(false);
ServiceBellApp.getInstance().addToRequestQueue(progressObject);
}
catch (JSONException localJSONException){
localJSONException.printStackTrace();
return;
}
}
private void progressOrderProgress(JSONObject progressResponse) throws JSONException {
JSONArray result = progressResponse.getJSONArray("orderdata");
OrderList orderListModule = new OrderList();
for(int i=0; i<result.length(); i++){
JSONObject orderData = result.getJSONObject(i);
orderListModule.setPackage_name(orderData.getString("package_name"));
orderListModule.setOrderdate(orderData.getString("orderdate"));
orderListModule.setServicedate(orderData.getString("servicedate"));
orderListModule.setServicetime(orderData.getString("servicetime"));
orderListModule.setOrderid(orderData.getString("orderid"));
orderListModule.setOrdstatus(orderData.getString("ordstatus"));
orderListModule.setOrderamount(orderData.getInt("orderamount"));
}
orderLists.add(orderListModule);
}
My adapter code:
public class OrderListAdapter extends RecyclerView.Adapter<OrderListAdapter.ViewHolder> {
List<OrderList> List;
private FragmentPending mContext;
public OrderListAdapter(List<OrderList> List, FragmentPending context) {
this.mContext = context;
this.List = List;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.order_list_view, null);
ViewHolder holder = new ViewHolder(view);
// this is where the each item is inflated.
return holder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
OrderList orderListsPos = List.get(position);
// this is where the data for each item is assigned
holder.textViewPackageName.setText(orderListsPos.getPackage_name());
holder.textOrderdate.setText(orderListsPos.getOrderdate());
holder.textServicedate.setText(orderListsPos.getServicedate());
holder.textServicetime.setText(orderListsPos.getServicetime());
holder.textOrderid.setText(orderListsPos.getOrderid());
holder.textOrderamount.setText("Rs." + orderListsPos.getOrderamount());
holder.textStatus.setText(orderListsPos.getOrdstatus());
}
#Override
public int getItemCount() {
return List.size();
}
public void clearAdaptor() {
List.clear();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView textViewPackageName;
public TextView textServicedate;
public TextView textServicetime;
public TextView textOrderdate;
public TextView textOrderid;
public TextView textOrderamount;
public TextView textStatus;
public ViewHolder(View itemView) {
super(itemView);
textViewPackageName = (TextView) itemView.findViewById(R.id.productName);
textOrderdate = (TextView) itemView.findViewById(R.id.orderdate);
textOrderid = (TextView) itemView.findViewById(R.id.orderno);
textOrderamount = (TextView) itemView.findViewById(R.id.orderprice);
textStatus = (TextView) itemView.findViewById(R.id.orderstatus);
}
}}
First you need four things
1 ) layout that holds the each recycler view layout item
2 ) A view holder for creating each layout
3 ) A Model Class to holds the data
4 ) Recycler Adaptor which deals with the data for the Each Layout item
FIrst create a layout item
for eample lets create a single view with only TextView in it
XML
each_item.xml
<TextView
android:id="#+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:gravity="start|center_vertical"
android:textColor="#color/white"
android:textSize="18sp" />
and lets now create a view holder
i will post both code for the view holder and RecyclerAdaptor
public class Adaptor extends RecyclerView.Adapter<Adaptor.ViewHolder> {
List<Model> List = Collections.emptyList();
private Context mContext;
private LayoutInflater inflater;
public Adaptor(Context context, List<Model> List) {
inflater = LayoutInflater.from(context);
this.mContext = context;
this.List = List;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.each_item, parent, false);
final ViewHolder holder = new ViewHolder(view);
// this is where the each item is inflated.
return holder;
}
#Override
public void onBindViewHolder(WinnersViewHolder holder, int position) {
Model mModel = List.get(position);
// this is where the data for each item is assigned
holder.nameView.setText("" + mModel.getName());
}
#Override
public int getItemCount() {
return List.size();
}
public void clearAdaptor() {
List.clear();
}
public class ViewHolder extends RecyclerView.ViewHolder {
protected TextView nameView;
public ViewHolder(View itemView) {
super(itemView);
this.nameView = (TextView) itemView.findViewById(R.id.name);
}
}
}
Now the model class
public class Model {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name= name;
}
}
Now the back end is done, Lets implement it on the Fragment
List<Model> List = new ArrayList<>();
private RecyclerView mRecyclerView;
private Adaptor adaptor;
public Fragment() {
// constructor of fragment
// Required empty public constructor
}
in the onCreatView() get the id of recyclerView
View fragmentView = inflater.inflate(R.layout.fragment_layout, container, false);
mRecyclerView = (RecyclerView) fragmentView .findViewById(R.id.recycler_view);
and then pass the data to the Adaptor by creating its object
adaptor = new Adaptor(getContext(), List);
adaptor.clearAdaptor();
mRecyclerView.setAdapter(adaptor);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
You are done now, only thing pending is if you are accessing data form server call notifyDataSetChanged() or adaptor = new Adaptor(getContext(), getList()); where the getList() returns the Model data and do not call adaptor.clearAdaptor() .
hope this helps ..
EDIT
you can two ways infalte the each layout item .. one is above and second is in onCreateViewHolder
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.each_item, null);
Check this link It is really helpful for beginners for understanding concepts from start to mastering the RecyclerView.
https://github.com/codepath/android_guides/wiki/Using-the-RecyclerView
Hope this helps you to understand recycler view concepts.
RecycerView + Fragment + Volley
Fragment Code:
public class DogListFragment extends Fragment{
private RecyclerView rv;
private StaggeredGridLayoutManager llm;
private DogListAdapter adapter;
private ArrayList<DogModel> dogList;
private Context context;
public static DogListFragment getInstance(){
return new DogListFragment();
}
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
dogList = new ArrayList<>();
adapter = new DogListAdapter(context, dogList, this);
getListFromServer();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.fragment_dog_list, parent, false);
rv = view.findViewById(R.id.rv);
llm = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
rv.setLayoutManager(llm);
rv.setAdapter(adapter);
return view;
}
public void getListFromServer(){
String url = "https://dog.ceo/api/breed/hound/images/random/20";
RequestQueue requestQueue = Volley.newRequestQueue(context);
StringRequest request = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);
JSONArray array = jsonObject.getJSONArray("message");
for(int i=0;i<array.length();i++){
String imageUrl = array.getString(i);
dogList.add(new DogModel(imageUrl));
}
adapter.updateDataSet(dogList);
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}
);
requestQueue.add(request);
}
}
Full code
Woof Repository
It has the following implementations
Fragment communication via interface
Reusing fragment by
getSupportFragmentManager().findFragmentByTag(TAG)
Which lifecycle method should have API call so that it is called just
once
How to save RecylcerView state in Fragment (Scroll position + content)
Pagination in RecyclerView
Rest Calls (Volley)
Image Rendering (Glide)
JSON Parsing
I have an adapter which won't get notified after fetching new data by Retrofit however, I'm using notifyDataSetChanged and get success in the logs but nothing works either :(
Also I tried to use local array with this adapter and it works great.
public class alberrClassNews extends Fragment {
private RecyclerView recyclerView;
private List<alberrNewsListContent> alberrNews = new ArrayList<alberrNewsListContent>();
private final String TAG = "Get JSONArray";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.alberrnewsclass, container, false);
getActivity().setTitle("nnnn");
recyclerView = (RecyclerView) view.findViewById(R.id.alberrNewsList);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
layoutManager.setReverseLayout(true);
layoutManager.setStackFromEnd(true);
final alberrNewsAdapter aNA = new alberrNewsAdapter(getActivity(), alberrNews);
recyclerView.setAdapter(aNA);
final ProgressDialog progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("loading");
progressDialog.show();
final Retrofit alberrRetrofit = new Retrofit.Builder()
.baseUrl("http://nn.com/abbn/")
.addConverterFactory(GsonConverterFactory.create()).build();
alberrService service = alberrRetrofit.create(alberrService.class);
Call<JSONArray> call = service.alberrNews();
call.enqueue(new Callback<JSONArray>() {
#Override
public void onResponse(Call<JSONArray> call, Response<JSONArray> response) {
progressDialog.dismiss();
Log.i(TAG, "success");
try{
JSONArray jsonArray = response.body().getJSONArray(0);
for (int i = 0 ; i < jsonArray.length() ; i++){
JSONObject jsonObject = jsonArray.getJSONObject(i);
alberrNewsListContent newsContent = new alberrNewsListContent();
newsContent.setAlberrNewsTitle(jsonObject.getString("title"));
newsContent.setAlberrNewsSubject(jsonObject.getString("subject"));
newsContent.setAlberrNewsImage(jsonObject.getString("image"));
alberrNews.add(newsContent);
}
} catch (JSONException e){
e.printStackTrace();
}
aNA.notifyDataSetChanged();
}
#Override
public void onFailure(Call<JSONArray> call, Throwable t) {
Log.i(TAG, "Failed");
progressDialog.dismiss();
Toast.makeText(getActivity().getApplicationContext(),
"no connection", Toast.LENGTH_SHORT).show();
}
});
return view;
}
Adapter Class
public class alberrNewsAdapter extends RecyclerView.Adapter<alberrNewsAdapter.ViewHolder> {
private List<alberrNewsListContent> newsListContent;
private Context context;
public alberrNewsAdapter(Context ncontext , List<alberrNewsListContent> nnewsListContent ){
this.context = ncontext;
this.newsListContent = nnewsListContent;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater
.from(parent.getContext())
.inflate(R.layout.alberrnewscontent, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(alberrNewsAdapter.ViewHolder holder, int position) {
final alberrNewsListContent newsContent = newsListContent.get(position);
holder.alberrNewsTitle.setText(newsContent.getAlberrNewsTitle());
holder.alberrNewsSubject.setText(newsContent.getAlberrNewsSubject());
Glide.with(context)
.load(newsContent.getAlberrNewsImage())
.override(300, 260)
.into(holder.alberrNewsImage);
}
#Override
public int getItemCount() {
return newsListContent.size();
}
public void replaceDataSet(List<alberrNewsListContent> alberrNews){
this.newsListContent = alberrNews;
notifyDataSetChanged();
}
public static class ViewHolder extends RecyclerView.ViewHolder{
TextView alberrNewsTitle;
TextView alberrNewsSubject;
ImageView alberrNewsImage;
CardView alberrNewsCardView;
public ViewHolder(View itemView) {
super(itemView);
alberrNewsTitle = (TextView)itemView.findViewById(R.id.alberrNewsTitle);
alberrNewsSubject = (TextView)itemView.findViewById(R.id.alberrNewsSubject);
alberrNewsImage = (ImageView)itemView.findViewById(R.id.alberrNewsImage);
alberrNewsCardView = (CardView)itemView.findViewById(R.id.alberrNewsCardView);
}
}
}
In your alberrNewsAdapter, you can create a new method called replaceDataSet() which will replace your dataset in the adapter and call notifyDataSetChanged().
private List<alberrNewsListContent> alberrNews alberrNews;
public void replaceDataSet(List<alberrNewsListContent> alberrNews){
this.alberrNews = alberrNews;
notifyDataSetChanged();
}
And in onResponse() instead of calling aNA.notifyDataSetChanged(); call aNA.replaceDataSet();
Pass new list content to the adapter via public method and call notifyDataSetChanged(); inside that method. Currently, you're not updating the list inside the adapter.