Custom methods in adapter are not resolving in android - android

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.

Related

How to add onClickListener on a RecyclerView in Android?

I am developing a car rental app. When user clicks on the the car, he should be directed to a booking page. I tried everything out there but when I click the view / car, I get the following error :
java.lang.NullPointerException: Attempt to invoke interface method 'void com.cuboid.rentacabs.ViewAdapter$onClickListener.onClick(int)' on a null object reference
Everything in the code looks just fine to me,
here's my viewAdapter.java
public class ViewAdapter extends RecyclerView.Adapter<ViewAdapter.MyViewHolder> {
DatabaseReference ref;
FirebaseDatabase fbRref;
Context context;
ArrayList<Model> model;
private onClickListener mListener;
public ViewAdapter(Context c, ArrayList<Model> listItems, onClickListener onClickListener)
{
this.context = c;
this.model = listItems;
this.mListener = onClickListener;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.car_details, parent, false);
fbRref = FirebaseDatabase.getInstance();
ref = fbRref.getReference();
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
holder.carName.setText(model.get(position).getmCarName());
holder.seatingCapacity.setText(model.get(position).getmSeatingCapacity());
holder.transmission.setText(model.get(position).getmTransmission());
holder.fuelType.setText(model.get(position).getmFuelType());
//holder.rate.setText(model.get(position).getmRate());
}
#Override
public int getItemCount() {
return model.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
public TextView carName,seatingCapacity,transmission,fuelType,rate;
public Button bookBtn;
public onClickListener onClickListener;
public MyViewHolder(#NonNull View itemView)
{
super(itemView);
carName = itemView.findViewById(R.id.car_name);
seatingCapacity = itemView.findViewById(R.id.seating_capacity);
transmission = itemView.findViewById(R.id.transmission_type);
fuelType = itemView.findViewById(R.id.fuel_type);
rate = itemView.findViewById(R.id.rate);
bookBtn =(Button) itemView.findViewById(R.id.book_btn);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
onClickListener.onClick(getAdapterPosition());
}
}
public interface onClickListener
{
void onClick(int position);
}
}
this my home fragment:
public class home extends Fragment implements ViewAdapter.onClickListener{
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public home() {
}
// TODO: Rename and change types and number of parameters
public static home newInstance() {
home fragment = new home();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
//to recycler view.
private RecyclerView recyclerView;
public View view;
private ArrayList<Model> listItem;
ViewAdapter Vadapter;
DatabaseReference dbRef;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_home, container,false);
recyclerView = view.findViewById(R.id.carDetailsContainer);
listItem = new ArrayList<Model>();
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(layoutManager);
dbRef = FirebaseDatabase.getInstance().getReference().child("Cars");
Vadapter = new ViewAdapter(getContext(),listItem,this);
//recyclerView.OnClickListener();
return view;
}
#Override
public void onStart() {
super.onStart();
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren())
{
Model model = new Model(ds.child("Name").getValue().toString(),ds.child("Seating_Capacity").getValue().toString(),ds.child("Fuel").getValue().toString(),ds.child("Transmission").getValue().toString(),ds.child("Rate").getValue().toString());
listItem.add(model);
}
recyclerView.setAdapter(Vadapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
dbRef.addValueEventListener(valueEventListener);
}
#Override
public void onClick(int position) {
listItem.get(position);
Log.d(TAG, "onClick: item"+ position);
startActivity(new Intent(getActivity(), booking.class));
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
thanks in advance.
You did a small mistake.
just replace this
#Override
public void onClick(View v) {
onClickListener.onClick(getAdapterPosition());
}
To this
#Override
public void onClick(View v) {
mListener.onClick(getAdapterPosition());
}
Use it Like this as shown below:
itemView.setOnClickListener(this);
#Override
public void onClick(View v) {
if (v.getId() == id of itemView(R.id.itemview)){
//do not use this
onClickListener.onClick(getAdapterPosition());
//just call the function you need to call on Click of itemview
}
}
Hope this helps

Recyclerview ListAdapter not updating

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

How to getAdapterPositions without getting null in OnClick Adapter on View Holder?

I like to get the positions i try using simple toast and i got it, but when i try to using it for interface i got an error
ListActivity
public class ListActivity extends BaseActivity implements ListAdapter.OnClickListenerAdapterList {
private DatabaseReference databaseReference;
private RecyclerView labelRecycleView;
private ArrayList<DataFirebase> listLabel = new ArrayList<>();
private ListAdapter listAdapter;
private Button bInput;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
findView();
setDataToList();
initListener();
}
private void setDataToList() {
simpleway.progressDialog(ListActivity.this);
databaseReference.child("Username").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnap : dataSnapshot.getChildren()) {
DataFirebase modelClass = dataSnap.getValue(DataFirebase.class);
modelClass.setLabel(dataSnap.getKey());
listLabel.add(modelClass);
}
putLayoutManager();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
System.out.println(databaseError.getDetails() + " " + databaseError.getMessage());
simpleway.stopProgressDialog();
}
});
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
labelRecycleView.setLayoutManager(layoutManager);
labelRecycleView.setItemAnimator(new DefaultItemAnimator());
}
private void putLayoutManager() {
listAdapter = new ListAdapter(ListActivity.this, listLabel, this);
labelRecycleView.setAdapter(listAdapter);
simpleway.stopProgressDialog();
}
#Override
public void findView() {
databaseReference = FirebaseDatabase.getInstance().getReference();
labelRecycleView = findViewById(R.id.listRecyclerVIew);
bInput = findViewById(R.id.inputData);
}
#Override
public void initListener() {
bInput.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
simpleway.startnextActivity(ListActivity.this, InputActivity.class);
}
});
}
#Override
public void OnClickPositionsAndValue(String enough) {
TitleFragment titleFragment = new TitleFragment();
FragmentTransaction fragmentTransaction =
getSupportFragmentManager()
.beginTransaction();
Bundle bundle = new Bundle();
bundle.putString("Check", enough);
titleFragment.setArguments(bundle);
fragmentTransaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_right,
R.anim.enter_from_right, R.anim.exit_to_right)
.replace(R.id.container_layout, titleFragment)
.addToBackStack(null)
.commit();
}
}
ListAdapter
public class ListAdapter extends RecyclerView.Adapter {
private Simpleway simpleway;
private ArrayList<DataFirebase> dataList;
private AppCompatActivity someActivity;
private Fragment fragmentActivity;
private OnClickListenerAdapterList onClickListenerAdapterList;
public ListAdapter(AppCompatActivity someActivity, ArrayList<DataFirebase> dataList,
OnClickListenerAdapterList onClickListenerAdapterList) {
this.dataList = dataList;
this.someActivity = someActivity;
simpleway = new Simpleway();
}
public ListAdapter(Fragment fragmentActivity, ArrayList<DataFirebase> dataList,
OnClickListenerAdapterList onClickListenerAdapterList) {
this.dataList = dataList;
this.fragmentActivity = fragmentActivity;
simpleway = new Simpleway();
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.item_label, viewGroup, false);
return new ViewHolder(view, onClickListenerAdapterList);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder viewHolder, final int positions) {
final DataFirebase labelList = dataList.get(positions);
viewHolder.textLabel.setText(labelList.getLabel());
String enough = labelList.getLabel();
}
#Override
public int getItemCount() {
return dataList.size();
}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
LinearLayout linearLabel;
TextView textLabel;
OnClickListenerAdapterList monClickListenerAdapterList;
ViewHolder(#NonNull View itemView, OnClickListenerAdapterList onClickListenerAdapterList) {
super(itemView);
textLabel = itemView.findViewById(R.id.text_label);
linearLabel = itemView.findViewById(R.id.linearLabel);
monClickListenerAdapterList = onClickListenerAdapterList;
linearLabel.setOnClickListener(this);
}
#Override
public void onClick(View v) {
simpleway.toastMessage(someActivity.getApplicationContext(), String.valueOf(getAdapterPosition()));
monClickListenerAdapterList.OnClickPositionsAndValue(getAdapterPosition());
}
}
public interface OnClickListenerAdapterList{
void OnClickPositionsAndValue(int positions);
}
}
and mostly when i try to getAdapterPositions the error i got is like this.
The Error
java.lang.NullPointerException: Attempt to invoke interface method 'void com.example.parzival.flashcard.adapter.ListAdapter$OnClickListenerAdapterList.OnClickPositionsAndValue(int)' on a null object reference
at com.example.parzival.flashcard.adapter.ListAdapter$ViewHolder.onClick(ListAdapter.java:90)
how do i getAdapter positions? is there something wrong with my interface?
The problem appears to be that your monClickListenerAdapterList is just null.
If you look at the constructor of your ListAdapter class, you'll see:
public ListAdapter(AppCompatActivity someActivity, ArrayList<DataFirebase> dataList,
OnClickListenerAdapterList onClickListenerAdapterList) {
this.dataList = dataList;
this.someActivity = someActivity;
simpleway = new Simpleway();
}
However, notice that although you passed in OnClickListenerAdapterList onClickListenerAdapterList as a parameter, you never called this.onClickListenerAdapterList = onClickListenerAdapterList; inside the constructor.
As such, you're simply passing in the listener, but never storing it... so the ListAdapter's onClickListenerAdapterList is actually still null.
So when you pass in that onClickListenerAdapterList to your ViewHolders, you're actually passing in the onClickListenerAdapterList that's still null.
So to fix your error, simply change your constructor to be:
public ListAdapter(AppCompatActivity someActivity, ArrayList<DataFirebase> dataList,
OnClickListenerAdapterList onClickListenerAdapterList) {
this.dataList = dataList;
this.someActivity = someActivity;
this.onClickListenerAdapterList = onClickListenerAdapterList;
simpleway = new Simpleway();
}

notifyDataSetChanged(); not working in android

This is my code.
#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);
adapter = new FragmentBrandList.MyAdapter(Utility.getBrandMap(), getActivity());
recyclerView.setAdapter(adapter);
// asynchronous call
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.notifyDataSetChanged();
}
#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;
}
Initially Utility.getBrandMap() is null. so noting is displaying. but in asynchronous call I am getting and updating the value and calling adapter.notifyDataSetChanged(); but still it doesn't update UI.
What is wrong here?
Edit: Adapter code
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;
}
#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();
}
}
Try this:
#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);
adapter = new FragmentBrandList.MyAdapter(Utility.getBrandMap(), getActivity());
recyclerView.setAdapter(adapter);
// asynchronous call
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);
}
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;
}
And in adapter code:
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();
}
#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're passing an empty Map to the constructor of your MyAdapter. Once the asynchronous query is finished the Map is filled however the brandList in your adapter doesn't know anything about the new data. So what you want to do is to add the new items to the List inside the adapter.
Add the following method to the adapter:
public void addValues(Map<String, Brand> brands){
brandList.clear();
brandList.addAll(brands.values());
notifyDataSetChanged();
}
and call it once the asynchronous query is finished.

RecyclerView not showing anything after updating Adapter data

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();
}

Categories

Resources