I have implemented a basic ListAdapter in RecyclerView as I am using View Model. The data I am getting is from networkManager to Viewmodel by calling API. Even when I did got the data the submitList is not Working and thus no data is getting inflated.
UpcomingGroupFragment
public class UpcomingGroupFragment extends Fragment {
private UpcomingViewModel mViewModel;
private RecyclerView recyclerView;
private GroupAdapter_new adapter;
public static UpcomingGroupFragment newInstance() {
return new UpcomingGroupFragment();
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_chatgroups, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
recyclerView = view.findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
adapter = new GroupAdapter_new();
recyclerView.setAdapter(adapter);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = ViewModelProviders.of(this).get(UpcomingViewModel.class);
mViewModel.getMutableLiveData().observe(this, new Observer<List<ChatGroups_New>>() {
#Override
public void onChanged(#Nullable List<ChatGroups_New> chatGroups_news) {
adapter.submitList(chatGroups_news);
Log.e("Upcoming", String.valueOf(chatGroups_news.size()));
}
});
}
}
The Adapter Class extends the ListAdapter.
Link for overriding submitlist: https://stackoverflow.com/a/50062174
The Code is as follows:
GroupAdapter_new
public class GroupAdapter_new extends ListAdapter<ChatGroups_New,GroupAdapter_new.ViewHolder> {
public GroupAdapter_new() {
super(DIFF_CALLBACK);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
Context context = parent.getContext();
int layoutID = R.layout.ongoing_group;
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(layoutID,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
ChatGroups_New currentGroup = getItem(position);
holder.text_flightarrival.setText(currentGroup.getFlightNameArrival());
}
class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
//... Finding ID's for various Views
}
}
/****ADDED THIS FROM CODE*****/
#Override
public void submitList(List<ChatGroups_New> list) {
super.submitList(list != null ? new ArrayList<ChatGroups_New>() : null);
}
/***********/
private static final DiffUtil.ItemCallback<ChatGroups_New> DIFF_CALLBACK =
new DiffUtil.ItemCallback<ChatGroups_New>() {
#Override
public boolean areItemsTheSame(ChatGroups_New oldItem, ChatGroups_New newItem) {
Log.e("areItemsTheSame", String.valueOf(oldItem.getMergedLogId() == newItem.getMergedLogId()));
return oldItem.getMergedLogId() == newItem.getMergedLogId();
}
#Override
public boolean areContentsTheSame(ChatGroups_New oldItem, ChatGroups_New newItem) {
if(oldItem.getFlightIcon().equals(newItem.getFlightIcon()) && oldItem.getFlightNameArrival().equals(newItem.getFlightNameArrival())){
if(oldItem.getGateValue().equals(newItem.getGateValue()) && oldItem.getEtaValue().equals(newItem.getEtaValue())){
if(oldItem.getAlertValue().equals(newItem.getAlertValue()) && oldItem.getTaskcompletedValue().equals(newItem.getTaskcompletedValue())){
Log.e("areContentsTheSame", "true");
return true;
}
}
}
return false;
}
};
}
If you want to see my ViewModel Class then:
UpcomingViewModel
public class UpcomingViewModel extends AndroidViewModel
implements I_NetworkResponse {
private NetworkManager networkManager;
private SharedPrefService prefService;
private HashMap<String, String> header;
private final String TAG = "UpcomingViewModel";
private List<ChatGroups_New> upcomingList;
private MutableLiveData<List<ChatGroups_New>> mutableLiveData;
public UpcomingViewModel(#NonNull Application application) {
super(application);
prefService = SharedPrefService.getInstance(application);
networkManager = new NetworkManager(application,this);
upcomingList = new ArrayList<>();
mutableLiveData = new MutableLiveData<>();
mutableLiveData.setValue(upcomingList);
header = new HashMap<>();
header.put("authorizationcode",prefService.getStringValue(Keys.getPreferenceAuthKey()));
if(upcomingList.isEmpty()){
networkManager.Volley_JsonObjectRequest(Keys.getBaseUrl()+"AviLeap/flights/upcoming",
header,null,TAG,"AviLeap/flights/upcoming");
}
}
public MutableLiveData<List<ChatGroups_New>> getMutableLiveData() { return mutableLiveData; }
#Override
public void getNetworkSuccessResponse(String TAG, String successResponse, String TAGforApi) {
Log.e(TAGforApi,successResponse);
parseUpcomingFlight(successResponse, upcomingList);
mutableLiveData.setValue(upcomingList);
}
#Override
public void getNetworkFailResponse(String TAG, VolleyError failResponse, String TAGforApi) { }
#Override
protected void onCleared() {
super.onCleared();
networkManager.stopNetworkCallsWithTag(TAG);
}
private void parseUpcomingFlight(String successResponse, List<ChatGroups_New> upcomingList) {
try {
JSONObject rootObject = new JSONObject(successResponse);
if(rootObject.has("upcomingflights") && rootObject.opt("upcomingflights") instanceof JSONArray){
JSONArray flightsArray = rootObject.optJSONArray("upcomingflights");
for(int flightIndex = 0; flightIndex < flightsArray.length(); flightIndex++){
JSONObject flightObject = flightsArray.optJSONObject(flightIndex);
int mergedLogId = flightObject.optInt("logid");
upcomingList.add(new ChatGroups_New(mergedLogId));
Log.e("parseUpcomingFlight", String.valueOf(upcomingList.size()));//..... Log Point
}
}
}
catch (JSONException e) { e.printStackTrace(); }
}
}
Initially the Size of the List is zero, so the Error is coming for as
AviLeap/flights/upcoming: //.... API CALL
2019-03-02 13:25:53.652 8477-8477/com.avileapconnect.com E/parseUpcomingFlight: 1 2019-03-02 13:25:53.652 8477-8477/com.avileapconnect.com E/parseUpcomingFlight: 2
2019-03-02 13:25:53.653 8477-8477/com.avileapconnect.com E/Upcoming: 2
The above logs show that the data is being added to the arraylist, but it is not updating. Also after all these logs when I go back to my Fragment I get the following error.
no adapter Attached, Skipping Layout
One more thing to add is that the adapter's getItemCount is getting updated properly. But even after that I am getting error:
no adapter Attached, Skipping Layout
EDIT: I fixed the error by commenting out the code for overriding the SubmitList method. I am also setting the adapter in the observer method in the fragment Class
Related
I am creating an app which can retrieve data from my own database. I'm using Retrofit to connect with my API. I'm creating a Bottom Navigation Activity so i could add some fragments to it. I'm using a Recycler View to show the list but it won't let me attach the adapter when i retrieve the data, it always shows this error in the log :
04-11 14:29:19.461 1912-1912/com.siscaproject.sisca E/RecyclerView: No adapter attached; skipping layout
Usually i use a single activity to create a list activity with a recycler view and it ran perfectly, but now that i use a fragment to do the same, it always gave me the error. Here is the fragment code :
public class SearchAssetFragment extends Fragment {
private static final String TAG = "SearchAssetFragment";
#BindView(R.id.search_view) SearchView searchView;
#BindView(R.id.swprefresh) SwipeRefreshLayout refresh;
#BindView(R.id.rv_list_asset) RecyclerView recyclerView;
#BindView(R.id.progress_bar) ProgressBar progressBar;
private MaterialDialog createDialog;
private AssetsAdapter adapter;
private ArrayList<Asset> listData = new ArrayList<>();
private UserService userService;
private OnFragmentInteractionListener mListener;
private AssetsAdapter.OnButtonClickListener listener = new AssetsAdapter.OnButtonClickListener() {
#Override
public void showDeleteDialog(int id) {
// TODO: Complete showDeleteDialog()
}
#Override
public void showEditDialog(Asset asset) {
// TODO: Complete showEditDialog()
}
};
public SearchAssetFragment() {
// Required empty public constructor
}
public static SearchAssetFragment newInstance() {
SearchAssetFragment fragment = new SearchAssetFragment();
return fragment;
}
#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_search_asset, container, false);
ButterKnife.bind(this, view);
userService = APIProperties.getUserService();
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
// The method to retrieve the data from the DB and set the recycler view adapter
getAsset();
refresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
getAsset();
}
});
return view;
}
private void showCreateDialog(){
// creating a dialog
}
private void showProgressBar(){
// showing a progress bar
}
private void hideProgressBar(){
// hiding a progress bar
}
// The method to retrieve the data from the DB and set the recycler view adapter
private void getAsset(){
showProgressBar();
Call<ResponseIndex<Asset>> call = userService.indexFixed(Header.auth, Header.accept);
call.enqueue(new Callback<ResponseIndex<Asset>>() {
#Override
public void onResponse(Call<ResponseIndex<Asset>> call, Response<ResponseIndex<Asset>> response) {
if(response.isSuccessful()){
int total = response.body().getTotal();
Log.i(TAG, "onResponse: total " + total);
// Initializing the adapter and set it to the recycler view
ArrayList<Asset> rows = response.body().getRows();
adapter = new AssetsAdapter(rows, getActivity(), userService, listener);
recyclerView.setAdapter(adapter);
}
else{
Log.i(TAG, "onResponse: else");
}
hideProgressBar();
refresh.setRefreshing(false);
}
#Override
public void onFailure(Call<ResponseIndex<Asset>> call, Throwable t) {
Log.e(TAG, "onFailure: " + t.getMessage() );
}
});
}
}
I'm not sure what i did wrong nor how to fix it, any answer would be appreciated. Thank you.
--Edit-- AssetsAdapter class :
public class AssetsAdapter extends RecyclerView.Adapter<AssetsAdapter.ItemHolder> implements Filterable{
private static final String TAG = "AssetsAdapter";
private OnButtonClickListener listener;
private ArrayList<Asset> listData;
private ArrayList<Asset> listDataFull;
private Context activityContext;
private UserService userService;
private MaterialDialog dialog;
public AssetsAdapter(ArrayList<Asset> listData, Context activityContext, UserService userService, OnButtonClickListener listener) {
this.listData = listData;
listDataFull = new ArrayList<>(listData);
this.activityContext = activityContext;
this.userService = userService;
this.listener = listener;
}
public AssetsAdapter(Context activityContext) {
this.activityContext = activityContext;
}
public void setListData(ArrayList<Asset> listData) {
this.listData = listData;
notifyDataSetChanged();
}
#NonNull
#Override
public ItemHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.layout_item_assets, parent, false);
return new ItemHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ItemHolder holder, final int position) {
// holder.iv_asset.setImageDrawable(); On progress
holder.tv_name.setText(listData.get(position).getName());
holder.tv_manufacturer.setText(listData.get(position).getAsset_id());
holder.tv_quantity.setText(listData.get(position).getPurchase_cost());
//holder.tv_status.setText(listData.get(position).getModel_no()); // Still on Progress
holder.btn_delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listener.showDeleteDialog(listData.get(position).getId());
}
});
holder.btn_edit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Toast.makeText(activityContext, "Edit", Toast.LENGTH_SHORT).show();
listener.showEditDialog(listData.get(position));
}
});
}
#Override
public int getItemCount() {
if(listData.isEmpty()) return 0;
else return listData.size();
}
#Override
public Filter getFilter() {
return dataFilter;
}
private Filter dataFilter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
ArrayList<Asset> filteredList = new ArrayList<>();
if(charSequence == null || charSequence.length() == 0){
filteredList.addAll(listDataFull);
}
else{
String filterPattern = charSequence.toString().toLowerCase().trim();
for(Asset item : listDataFull){
if(item.getName().toLowerCase().contains(filterPattern)){
filteredList.add(item);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
listData.clear();
listData.addAll((List) filterResults.values);
notifyDataSetChanged();
}
};
public class ItemHolder extends RecyclerView.ViewHolder{
private ImageView iv_asset;
private TextView tv_name;
private TextView tv_manufacturer;
private TextView tv_quantity;
private TextView tv_status;
private ImageButton btn_edit;
private ImageButton btn_delete;
public ItemHolder(View itemView) {
super(itemView);
iv_asset = itemView.findViewById(R.id.iv_asset);
tv_name = itemView.findViewById(R.id.tv_name);
tv_manufacturer = itemView.findViewById(R.id.tv_manufacturer);
tv_quantity = itemView.findViewById(R.id.tv_quantity);
tv_status = itemView.findViewById(R.id.tv_status);
btn_edit = itemView.findViewById(R.id.btn_edit);
btn_delete = itemView.findViewById(R.id.btn_delete);
}
}
public interface OnButtonClickListener {
void showDeleteDialog(final int id);
void showEditDialog(Asset asset);
}
}
First, initialize the model class and the adapter and attach to recyclerview and than get the data after retrieving data put notifydatasetchanged() or notifydatainserted() method, I think it should work,
please initialize adapter in fragment oncreateview method and set adapter to recycleview
adapter = new AssetsAdapter(rows, getActivity(), userService, listener);
recyclerView.setAdapter(adapter);
recyclerView.setAdapter(adapter);
after get response from api you can update adapter. please refer
this question
homepageThis is my fragment class
public class Premiums extends Fragment {
private RecyclerView recyclerPremium;
private RecyclerView.LayoutManager mLayoutManager;
private List<FeaturedAddDetails> featuredAddDetailsList = new ArrayList<>();
private List<PremiumDetails> premiumDetailslist = new ArrayList<>();
private NewestAdapter newestAdapter;
private PremiumAdapter premiumAdapter;
private String jsonResponse;
private PremiumDetails premiumDetails;
private JSONObject jsonobject;
public Premiums() {
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View mainView = inflater.inflate(R.layout.premium_fragment, container, false);
recyclerPremium = (RecyclerView) mainView.findViewById(R.id.recycler_premium);
premiumAdd();
premiumAdapter = new PremiumAdapter(getActivity().getApplicationContext(), premiumDetailslist);
recyclerPremium.setAdapter(premiumAdapter);
return mainView;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
recyclerPremium.setLayoutManager(mLayoutManager);
recyclerPremium.setHasFixedSize(true);
}
private void premiumAdd() {
PremiumRequestHandler premiumHandler = new PremiumRequestHandler("premiumADD");
premiumHandler.executeAsStringRequest(new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.e("response", response);
JSONArray jsonarray = null;
try {
jsonarray = new JSONArray(response);
} catch (JSONException e) {
e.printStackTrace();
}
for (int i = 0; i < jsonarray.length(); i++) {
try {
jsonobject = jsonarray.getJSONObject(i);
Log.e("id", String.valueOf(jsonobject.getInt("id")));
premiumDetails = new PremiumDetails(jsonobject.getInt("id"),
jsonobject.getInt("userid"),
jsonobject.getInt("mobile"),
jsonobject.getInt("cityid"),
jsonobject.getInt("price"),
jsonobject.getInt("comments"),
jsonobject.getInt("created"),
jsonobject.getInt("categoryid"),
jsonobject.getInt("MainCategoryID"),
jsonobject.getInt("views"),
jsonobject.getInt("ImageCount"),
jsonobject.getInt("storeid"),
jsonobject.getString("title"),
jsonobject.getString("default_photo"),
jsonobject.getString("CityName"),
jsonobject.getString("CategoryName"),
jsonobject.getString("currency"),
jsonobject.getString("description"));
premiumDetailslist.add(premiumDetails);
premiumAdapter.setPremiumDetails(premiumDetailslist);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}, new BaseRequest.ErrorResponseCallback() {
#Override
public void onError(Exception exception) {
}
});
}
This is my adapter class
public class PremiumAdapter extends RecyclerView.Adapter<PremiumAdapter.MyViewHolderPremium> {
private List<PremiumDetails> premiumDetailsList;
private ImageLoader imageLoader;
private Context context;
public PremiumAdapter(Context context, List<PremiumDetails> premiumDetailsList) {
this.premiumDetailsList = premiumDetailsList;
this.context = context;
notifyDataSetChanged();
}
public void setPremiumDetails(List<PremiumDetails> premiumDetailsList) {
this.premiumDetailsList = premiumDetailsList;
notifyDataSetChanged();
}
public class MyViewHolderPremium extends RecyclerView.ViewHolder {
private TextView txtTitle,txtDescription,txtCityName,txtPrice,txtCategory,txtHour,txtPhotoNo;
private NetworkImageView imgPhoto;
public MyViewHolderPremium(View itemView) {
super(itemView);
txtTitle = (TextView)itemView.findViewById(R.id.txt_title_fad);
txtDescription = (TextView)itemView.findViewById(R.id.description_fad);
txtCityName = (TextView)itemView.findViewById(R.id.city_name_fad);
txtPrice = (TextView)itemView.findViewById(R.id.price_fad);
txtCategory = (TextView)itemView.findViewById(R.id.category_fad);
txtHour = (TextView)itemView.findViewById(R.id.hours_fad);
txtPhotoNo = (TextView)itemView.findViewById(R.id.txt_photo_no_fad);
imgPhoto=(NetworkImageView)itemView.findViewById(R.id.img_photo_lod_fad);
}
}
#Override
public MyViewHolderPremium onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.featured_ad_adapter_layout,parent,false);
final MyViewHolderPremium myViewHolderPremium = new MyViewHolderPremium(itemView);
return myViewHolderPremium;
}
#Override
public void onBindViewHolder(MyViewHolderPremium holder, int position) {
PremiumDetails premiumDetails = premiumDetailsList.get(position);
holder.txtTitle.setText(premiumDetails.getTitle());
holder.txtDescription.setText(premiumDetails.getDescription());
holder.txtCityName.setText(premiumDetails.getCityName());
holder.txtPrice.setText(Integer.toString(premiumDetails.getPrice()));
holder.txtCategory.setText(premiumDetails.getCategoryName());
holder.txtHour.setText(Integer.toString(premiumDetails.getCreated()));
holder.txtPhotoNo.setText(Integer.toString(premiumDetails.getImageCount())+" photos " );
try {
imageLoader= VolleyHandler.getImageLoader();
} catch (Exception e) {
e.printStackTrace();
}
//imageLoader = CustomVolleyRequest.getInstance(context).getImageLoader();
//imageLoader.get(featuredAddDetails.getDefault_photo(), ImageLoader.getImageListener(holder.imgPhoto, R.mipmap.ic_launcher, android.R.drawable.ic_dialog_alert));
holder.imgPhoto.setImageUrl(premiumDetails.getDefault_photo(),imageLoader);
}
#Override
public int getItemCount() {
Log.e("size", String.valueOf(premiumDetailsList.size()));
return premiumDetailsList.size();
}}
I am getting error on showing values but I got values from json and I can't add it to adapter and model class, plz help me I look stackoverflow whole day but I can't find my issue
my getItemCount() is showing as 0"
You are setting the adapter and then you are calling premiumAdd() method.First call that method and then set the adapter.
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View mainView = inflater.inflate(R.layout.premium_fragment, container, false);
recyclerPremium = (RecyclerView) mainView.findViewById(R.id.recycler_premium);
premiumAdd();
premiumAdapter = new PremiumAdapter(getActivity().getApplicationContext(), premiumDetailslist);
recyclerPremium.setAdapter(premiumAdapter);
return mainView;
Try notifyDataSetChanged() after setting data in the Constructor of your Adapter
[EDIT] Whenever your data changes, you need to inform your Adapter about it also, then call notifyDataSetChanged() on it.
You are probably setting empty data into the Adapter, your List changes, but the Adapter does not know about it.
[Update]
In addition to your Adapter constructor, add a setData(List) to your adapter to change your dataset at runtime.
public void setPremiumDetails(List<PremiumDetails> premiumDetailsList) {
this.premiumDetailsList = premiumDetailsList;
notifyDataSetChanged();
}
When your request in premiumAdd() returns, and you receive a new set of data, you call setPremiumDetails on your Adapter with the new data and the List will update.
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View mainView = inflater.inflate(R.layout.premium_fragment, container, false);
recyclerPremium = (RecyclerView) mainView.findViewById(R.id.recycler_premium);
mLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
recyclerPremium.setLayoutManager(mLayoutManager);
recyclerPremium.setHasFixedSize(true);
premiumAdd();
premiumAdapter = new PremiumAdapter(getActivity().getApplicationContext(), premiumDetailslist);
recyclerPremium.setAdapter(premiumAdapter);
return mainView;
}
and remove premiumAdapter.notifyDataSetChanged();
added adapter code:
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.ViewHolder> {
ArrayList<Model> dataset;
public RVAdapter(ArrayList<Model> dataset) {
this.dataset = dataset;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_item,parent,false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Model model = dataset.get(position);
holder.name.setText(model.name) ;
holder.status.setText(model.status);
if (model.status.equalsIgnoreCase("good"))
holder.ivStatus.setImageResource(R.drawable.ic_tick_48);
else
holder.ivStatus.setImageResource(R.drawable.ic_delete_48);
}
#Override
public int getItemCount() {
Log.e("TAG","SIZE: "+dataset.size());
return dataset.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView name;
TextView status;
ImageView ivStatus;
RelativeLayout parent;
public ViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.rv_item_name);
status = (TextView) itemView.findViewById(R.id.rv_item_status);
ivStatus = (ImageView) itemView.findViewById(R.id.rv_item_iv);
parent = (RelativeLayout) itemView.findViewById(R.id.rv_item_parent);
}
}
}
your notifiy adapter on every single add
for (...){
....
premiumDetailslist.add(premiumDetails);
premiumAdapter.notifyDataSetChanged();// called every time wrong
}
also provide what exact error log says
and move the notifyDataSetChanged() after the for not in the loop
if no data is showing try recyclerview.invalidate , but i wont particularly do that way, would try debugging, log every step, inspect with method in the expected sequence isnt working
I have 2 methods inside of adapter class.
addValues(brandMap);
setBrandMap(brandMap);
that I'm trying to call after async call. However, the compiler is complaining that it cannot resolve these methods. What is the issue?
This is complete class.
public class FragmentBrandList extends ListFragment {
private String TAG = getClass().getSimpleName();
private Map<String, Brand> brandMap = new ConcurrentHashMap<>();
private RecyclerView.Adapter adapter;
private FirebaseDatabase database = FirebaseDatabase.getInstance();
private RecyclerView recyclerView;
private Query query = database.getReference("brands").orderByChild("name");
public FragmentBrandList() {
}
public static FragmentBrandList newInstance(int num) {
FragmentBrandList f = new FragmentBrandList();
// Supply num input as an argument.
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.recycler_list, container, false);
recyclerView = (RecyclerView) v.findViewById(R.id.recycler_view);
RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(getActivity(), 3);
RecyclerView.setLayoutManager(mLayoutManager);
adapter = new FragmentBrandList.MyAdapter(Utility.getBrandMap(), getActivity());
recyclerView.setAdapter(adapter);
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new ClickListener() {
#Override
public void onClick(View view, int position) {
Brand brand = Utility.getBrands().get(position);
Intent intent = new Intent(getActivity(), ActivityProductList.class);
intent.putExtra("BrandId", brand.getId());
startActivity(intent);
}
#Override
public void onLongClick(View view, int position) {
}
}));
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
Brand brand = dataSnapshot1.getValue(Brand.class);
brandMap.put(brand.getId(), brand);
}
Utility.setBrandMap(brandMap);
adapter.addValues(brandMap);
adapter.setBrandMap(brandMap);
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
Utility.displayToast("Failed to read value." + error.toException());
}
});
return v;
}
Adapter class
private class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private List<Brand> brandList = new ArrayList<>();
private Context context;
public class MyViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
public MyViewHolder(View view) {
super(view);
imageView = (ImageView) view.findViewById(R.id.thumbnail);
}
}
public MyAdapter(Map<String, Brand> brands, Context context) {
//public MyAdapter(List<Brand> brands, Context context) {
this.brandList = new ArrayList<>(brandMap.values());
//this.brandList = brands;
this.context = context;
}
public void setBrandMap(Map<String, Brand> brandMap){
this.brandList = new ArrayList<>(brandMap.values());
notifyDataSetChanged();
}
public void addValues(Map<String, Brand> brands){
brandList.clear();
brandList.addAll(brands.values());
notifyDataSetChanged();
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_brand, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
if (brandList != null && brandList.size() > 0) {
Brand brand = brandList.get(position);
Glide.with(context).load(String.valueOf(brand.getImage()))
.error(R.drawable.placeholder)
.placeholder(R.drawable.placeholder)
.into(holder.imageView);
}
}
#Override
public int getItemCount() {
return brandList.size();
}
}
You have declared your adapter field as:
private RecyclerView.Adapter adapter;
That means wherever you use it, you'll see it as just a RecyclerView.Adapter, which doesn't have your custom methods on it. It doesn't matter that you've assigned there a subclass of RecyclerView.Adapter that has extra methods. It is because you might've assigned there a different subclass that didn't have those methods.
If you want to use your custom methods then change the declaration to:
private MyAdapter adapter;
Then you can use all methods declared in MyAdapter and inherited from superclasses. The tradeoff is that you cannot assign there any other subclass of RecyclerView.Adapter, but thanks to that compiler can know you can always use your extra methods.
The problem is this line.
private RecyclerView.Adapter adapter;
As you are holding your custom adapter object in the Base reference, hence those methods of your custom adapter is not visible to you. Change the reference to the type of your Custom Adapter and it should work fine.
guys i need help with this matter i have been going through my code for a couple of days to figure whats going wrong but i couldn't figure it out.
I have a fragment with a RecyclerView i initialize the Adapter data with an image place holder and some default text and the fragment shows them as expected then using a loader i fetch data from the internet and parse and pass the new data to the Adapter (all of this happens as required) until the data reaches the Adapter then Taaadaaaa the initial data disappears and the new data is not showing actually the fragment shows a blank screen definitely i am doing something wrong please advise.
This is the fragment code
public class fragment_MovieStartGridlayout extends android.support.v4.app.Fragment implements MyGridAdapter.MyGridAdapterListener{
private static RecyclerView myRecyclerView;
private static MyGridAdapter myGridAdapter;
private static RecyclerView.LayoutManager rvLayoutManager;
private LoaderManager.LoaderCallbacks<ArrayList<HashMap>> dataLoaderCallbacks;
private OnFragmentInteractionListener mListener;
public fragment_MovieStartGridlayout() {
}
#Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dataLoaderCallbacks = new LoaderManager.LoaderCallbacks<ArrayList<HashMap>>() {
#Override
public Loader<ArrayList<HashMap>> onCreateLoader(int id, Bundle args) {
return new DataLoader(getActivityContext(), MyUriBuilder.DISCOVER, null);
}
#Override
public void onLoadFinished(Loader<ArrayList<HashMap>> loader,ArrayList<HashMap> data) {
myGridAdapter.setMyAdapterData(data);
}
#Override
public void onLoaderReset(Loader<ArrayList<HashMap>> loader) {
loader.reset();
}
};
getLoaderManager().initLoader(0, null, dataLoaderCallbacks);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragGridLayout = inflater.inflate(R.layout.fragment_gridlayout_movie_start, container, false);
myRecyclerView = (RecyclerView) fragGridLayout.findViewById(R.id.myViewRecycler);
rvLayoutManager = new GridLayoutManager(getActivityContext(),2);
myRecyclerView.setLayoutManager(rvLayoutManager);
myGridAdapter = new MyGridAdapter(getActivityContext());
myRecyclerView.setAdapter(myGridAdapter);
return fragGridLayout;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDataSetChanged(boolean state) {
if (state){
myGridAdapter.notifyDataSetChanged();
}
}
public interface OnFragmentInteractionListener {
public void onFragmentInteraction(Uri uri);
}
public Context getActivityContext(){
return this.getActivity();
}
}
and this is the Adapter for the RecyclerView
public class MyGridAdapter extends RecyclerView.Adapter<MyGridAdapter.MyViewHolder> {
LayoutInflater layoutInflater;
private static ArrayList<HashMap> data=null;
private Context mContext;
public static Bitmap placeHolder;
public MyGridAdapter(Context context){
mContext = context;
setInitialData();
placeHolder = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.android_blue);
}
public interface MyGridAdapterListener{
public void onDataSetChanged(boolean state);
}
private MyGridAdapterListener listener = null;
public void registerListener(MyGridAdapterListener newListener){
listener = newListener;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
layoutInflater = LayoutInflater.from(context);
View v = layoutInflater.inflate(R.layout.gridlayout_item_movie_start, parent, false);
MyViewHolder vHolder=new MyViewHolder(v);
return vHolder;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
HashMap singleData = data.get(position);
String movieRate = String.valueOf(singleData.get(MyJSONDataParser.TAG_VOTE_AVERAGE)) ;
holder.movieTitle.setText((String)singleData.get(MyJSONDataParser.TAG_TITLE));
holder.moviePoster.setImageBitmap(placeHolder);
holder.movieRating.setRating(Float.valueOf(movieRate));
}
#Override
public int getItemCount() {
return data.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView movieTitle;
RoundedImageView moviePoster;
RatingBar movieRating;
public MyViewHolder(View v) {
super(v);
movieTitle = (TextView) v.findViewById(R.id.movieTitleTextView);
moviePoster = (RoundedImageView) v.findViewById(R.id.roundImageView);
movieRating = (RatingBar) v.findViewById(R.id.ratingBar);
}
}
private boolean dataChanged = false;
public void setMyAdapterData(ArrayList<HashMap> data){
this.data = data;
dataChanged = true;
if (listener != null){
listener.onDataSetChanged(dataChanged);
}
}
protected void setInitialData(){
HashMap initialItem = new HashMap();
ArrayList<HashMap> initialData = new ArrayList<>(20);
initialItem.put(MyJSONDataParser.TAG_TITLE, "Loading...");
initialItem.put(MyJSONDataParser.TAG_MOVIE_BITMAP, placeHolder);
initialItem.put(MyJSONDataParser.TAG_VOTE_AVERAGE, 3.3);
for (int i = 0;i<20;i++){
initialData.add(initialItem);
}
this.data = initialData;
}
}
I did call notifyDataSetChanged
but this was not the issue after alooooooooot of testing and Logging the problem was with setAdapterData method where i just passed the data reference from the loader to the adapter but this didn't work and i had to clone the arraylist instead of just passing the reference which sounds strange to me and i still don't understand why I had to do that if you can take a look at the setAdapterData method in MyGridAdapter class and tell me what do you think
Try invoking notifyDataSetChanged() when you modify your adapter data:
public void setMyAdapterData(ArrayList<HashMap> data){
this.data = data;
dataChanged = true;
notifyDataSetChanged();
if (listener != null){
listener.onDataSetChanged(dataChanged);
}
}
I see that you attempt to do this in the callback on your listener, but perhaps it is null and therefore never firing the notification?
[COMMENT]
When I want to replace the entire collection of data in my adapter I often write a method similar to this:
public void setData(List<MyData> newData) {
this.data.clear();
this.data.addAll(newData);
this.notifyDataSetChanged();
}
I'm not familiar with rx java. Trying to use it with recycleview. For some reason my code is not working Here is my code.
Fragment with recycle view
public class CheeseListFragment extends Fragment {
private final CompositeSubscription subscriptions = new CompositeSubscription();
private PublishSubject<String> timespanSubject;
private final Func1<String, Observable<LiveInfo>> trendingSearch =
new Func1<String, Observable<LiveInfo>>() {
#Override
public Observable<LiveInfo> call(String s) {
RadioLiveInfoObservableService radioLiveInfoObservableService=ApiProvider.getInstance().getRadioObserverInfo();
return radioLiveInfoObservableService.radioInfo(Type.INTERVAL)
.observeOn(AndroidSchedulers.mainThread())
.doOnError(trendingError)
.onErrorResumeNext(Observable.<LiveInfo>empty());
}
};
private final Action1<Throwable> trendingError = new Action1<Throwable>() {
#Override public void call(Throwable throwable) {
Timber.e(throwable, "Failed to get trending repositories");
}
};
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
timespanSubject = PublishSubject.create();
final RecyclerView rv = (RecyclerView) inflater.inflate(
R.layout.fragment_cheese_list, container, false);
setupRecyclerView(rv);
subscriptions.add(timespanSubject
.flatMap(trendingSearch)
.map(SearchResultToRepositoryList.instance())
.subscribe(adapter));
return rv;
}
private SimpleStringRecyclerViewAdapter adapter;
private void setupRecyclerView(RecyclerView recyclerView) {
recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
adapter=new SimpleStringRecyclerViewAdapter(getActivity(), new SimpleStringRecyclerViewAdapter.CurrentShowClickListener() {
#Override
public void onCurrentShowClick(Current currentShow) {
Intent intent = new Intent(CApplication.getAppContext(), CheeseDetailActivity.class);
intent.putExtra(CheeseDetailActivity.EXTRA_NAME, currentShow.getName());
CApplication.getAppContext().startActivity(intent);
}
});
recyclerView.setAdapter(adapter);
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
#Override
public void onChanged() {
Toast.makeText(getActivity(),"data changed",Toast.LENGTH_SHORT).show();
}
});
}
private List<String> getRandomSublist(String[] array, int amount) {
ArrayList<String> list = new ArrayList<>(amount);
Random random = new Random();
while (list.size() < amount) {
list.add(array[random.nextInt(array.length)]);
}
return list;
}
public static class SimpleStringRecyclerViewAdapter
extends RecyclerView.Adapter<SimpleStringRecyclerViewAdapter.ViewHolder> implements Action1<List<Current>> {
private List<Current> currentShows = Collections.emptyList();
public interface CurrentShowClickListener {
void onCurrentShowClick(Current currentShow);
}
private final CurrentShowClickListener currentShowClickListener;
private final TypedValue mTypedValue = new TypedValue();
private int mBackground;
#Override
public void call(List<Current> currentShows) {
this.currentShows = currentShows;
notifyDataSetChanged();
}
public SimpleStringRecyclerViewAdapter(Context context,CurrentShowClickListener currentShowClickListener) {
context.getTheme().resolveAttribute(R.attr.selectableItemBackground, mTypedValue, true);
mBackground = mTypedValue.resourceId;
this.currentShowClickListener = currentShowClickListener;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ListItemView view = (ListItemView)LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
view.setBackgroundResource(mBackground);
return new ViewHolder(view);
}
#Override public void onBindViewHolder(ViewHolder viewHolder, int i) {
viewHolder.bindTo(currentShows.get(i));
}
#Override public long getItemId(int position) {
return position;
}
#Override public int getItemCount() {
return currentShows.size();
}
public final class ViewHolder extends RecyclerView.ViewHolder {
public final ListItemView itemView;
private Current currentShow;
public ViewHolder(ListItemView itemView) {
super(itemView);
this.itemView = itemView;
this.itemView.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v) {
currentShowClickListener.onCurrentShowClick(currentShow);
}
});
}
public void bindTo(Current currentShow) {
this.currentShow = currentShow;
itemView.bindTo(currentShow);
}
}
}
}
SearchToResultRepositoryList
public final class SearchResultToRepositoryList implements Func1<LiveInfo, List<Current>> {
private static volatile SearchResultToRepositoryList instance;
public static SearchResultToRepositoryList instance() {
if (instance == null) {
instance = new SearchResultToRepositoryList();
}
return instance;
}
#Override public List<Current> call(LiveInfo repositoriesResponse) {
List<Current> currents=new ArrayList<>();
currents.add(repositoriesResponse.getCurrent());
return currents;
}
}
REST
public interface RadioLiveInfoObservableService {
#GET("/api/live-info/")
Observable<LiveInfo> radioInfo(
#Query("type") Type type);
}
It's just doing nothing. I tried to debug it trendingSearch.call is not called at all.
I can make it work only this way. But still i want to know how to it with subscription
RadioLiveInfoObservableService radioLiveInfoObservableService=ApiProvider.getInstance().getRadioObserverInfo();
radioLiveInfoObservableService.commits(Type.INTERVAL)
.observeOn(AndroidSchedulers.mainThread())
.doOnError(trendingError)
.onErrorResumeNext(Observable.<LiveInfo>empty()).subscribe(new Action1<LiveInfo>() {
#Override
public void call(LiveInfo liveInfo) {
List<Current> currents=new ArrayList<Current>();
currents.add(liveInfo.getCurrent());
adapter.currentShows=currents;
adapter.notifyDataSetChanged();
rv.setAdapter(adapter);
}
});
That's a lot of code to digest looking for errors, but off the top of my head nothing will happen until timeSpanSubject.onNext() is called. I don't see this called anywhere but maybe there is some missing code you are not showing.
If there is no missing code that calls timeSpanSubject.onNext(), then you could use either a BehaviorSubject which will emit an item when first subscribed to or another Observable such as timer or interval depending on what you are trying to do. timer would subscribe to your trendingSearch Observable a single time whereas using an interval would subscribe multiple times.