Android RecyclerView does not work properly with data from retrofit request - java

I have a screen with CardViews inside of a RecyclerView. The data for each card is retrieved from an ArrayList. As soon as I manually add data to the ArrayList, everything works fine. However, when data is added by an API using retrofit, cards are displayed only if at least one element is manually added to the ArrayList. In addition, if I switch to another menu and then return to a list of cards, only the manually added cards are displayed.
List with cards
Only manually added card is visible
Full code
public class CurrencyRates extends Fragment {
ArrayList<CurrencyModel> currencyModelArrayList;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_currency_rates, container, false);
currencyModelArrayList = new ArrayList<>();
getRates("EUR", "USD");
getRates("USD", "AUD");
getRates("EUR", "GBP");
getRates("EUR", "CNY");
currencyModelArrayList.add(new CurrencyModel("EUR", "CZK", 24.8821));
RecyclerView currencyRV;
currencyRV = view.findViewById(R.id.RVCurrency);
CurrencyAdapter currencyAdapter = new CurrencyAdapter(getActivity().getBaseContext(), currencyModelArrayList);
//cardview two columns
RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(getActivity().getBaseContext(), 2);
currencyRV.setLayoutManager(mLayoutManager);
currencyRV.setAdapter(currencyAdapter);
return view;
}
public void getRates(String baseCurrency, String exchangeCurrency) {
RetrofitInterface retrofitInterface = RetrofitClient.getRetrofitInstance().create(RetrofitInterface.class);
Call<JsonObject> call = retrofitInterface.getData(baseCurrency, exchangeCurrency);
call.enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
JsonObject res = response.body();
JsonPrimitive rate = res.getAsJsonObject().getAsJsonPrimitive("conversion_rate");
currencyModelArrayList.add(new CurrencyModel(baseCurrency, exchangeCurrency, Double.parseDouble(rate.toString())));
}
public void onFailure(Call<JsonObject> call, Throwable t) {
}
});
}}
Adapter class:
public class CurrencyAdapter extends RecyclerView.Adapter<CurrencyAdapter.ViewHolder> {
private Context context;
private ArrayList<CurrencyModel> currencyModelArrayList;
public CurrencyAdapter(Context context, ArrayList<CurrencyModel> currencyModelArrayList) {
this.context = context;
this.currencyModelArrayList = currencyModelArrayList;
}
#NonNull
#Override
public CurrencyAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull CurrencyAdapter.ViewHolder holder, int position) {
CurrencyModel model = currencyModelArrayList.get(position);
holder.baseCurrencyTV.setText(model.getBaseCurrency());
holder.exchangeCurrencyTV.setText("/ " + model.getExchangeCurrency());
holder.rateTV.setText(String.valueOf(model.getRate()));
}
#Override
public int getItemCount() {
return currencyModelArrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView baseCurrencyTV, exchangeCurrencyTV, rateTV;
public ViewHolder(#NonNull View itemView) {
super(itemView);
baseCurrencyTV = itemView.findViewById(R.id.TVBaseCurrency);
exchangeCurrencyTV = itemView.findViewById(R.id.TVExchangeCurrency);
rateTV = itemView.findViewById(R.id.TVRate);
}
}}
MainActivity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Navigation
BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView);
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(R.id.currencyRates, R.id.converter).build();
NavController navController = Navigation.findNavController(this, R.id.fragment);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(bottomNavigationView, navController);
}}
Retrofit:
public class RetrofitClient {
private static Retrofit retrofit;
private static RetrofitClient instance;
public static RetrofitInterface myRetrofitInterface;
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(RetrofitInterface.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
public interface RetrofitInterface {
String BASE_URL = "https://v6.exchangerate-api.com/";
#GET("v6/API_KEY/pair/{baseCurrency}/{exchangeCurrency}")
Call<JsonObject> getData(#Path("baseCurrency") String baseCurrency,
#Path("exchangeCurrency") String exchangeCurrency);
}

When you add an item to the list you should notify the adapter
public void getRates(String baseCurrency, String exchangeCurrency) {
RetrofitInterface retrofitInterface = RetrofitClient.getRetrofitInstance().create(RetrofitInterface.class);
Call<JsonObject> call = retrofitInterface.getData(baseCurrency, exchangeCurrency);
call.enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
JsonObject res = response.body();
JsonPrimitive rate = res.getAsJsonObject().getAsJsonPrimitive("conversion_rate");
currencyModelArrayList.add(new CurrencyModel(baseCurrency, exchangeCurrency, Double.parseDouble(rate.toString())));
CurrencyAdapter.notifyDataSetChanged();// add this line
}
});
}}

Related

How can I assign a different OnClickListener to different items in a recyclerview?

I'm doing my final project that due tomorrow and I only have one thing left to do. But I already lost a lot of time on it. I am creating a recyclerview from a JSON that I obtain through Volley from the Adafruit API and everything is fine, the only thing i need is that when I clicking on the items different Intents are opened. I would greatly appreciate if someone could help me. I have to say that I am working on a fragment and there things are a little different.
The code of my Adapter:
public class AdafruitFeedAdapter extends RecyclerView.Adapter<AdafruitFeedAdapter.viewholder> {
ArrayList<FeedData> feedData;
public AdafruitFeedAdapter(ArrayList<FeedData> feedData) {
this.feedData = feedData;
}
#NonNull
#Override
public viewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_feed, parent, false);
return new viewholder(v);
}
#Override
public void onBindViewHolder(#NonNull viewholder holder, int position) {
holder.setData(feedData.get(position));
}
#Override
public int getItemCount() {
return feedData.size();
}
public class viewholder extends RecyclerView.ViewHolder implements View.OnClickListener {
Button btnMisFeeds;
FeedData dataHolder;
public viewholder(#NonNull View itemView) {
super(itemView);
btnMisFeeds = itemView.findViewById(R.id.btnMisFeeds);
btnMisFeeds.setOnClickListener(this);
}
public void setData(FeedData feedData) {
dataHolder = feedData;
btnMisFeeds.setText(dataHolder.getName());
}
#Override
public void onClick(View v) {
}
}
The code of my fragment:
public class FragmentInicio extends Fragment {
Button btnControlar, btnAddFeed;
View view;
String temperatura, distancia, infrarrojo, polvo;
// 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 static final String USER_PREFERENCES = "userPreferences";
private static final String TOKEN_KEY = "token";
private RequestQueue nQueue;
ArrayList<AdafruitFeed> adF;
AdafruitFeedAdapter adapterFeed;
RecyclerView recyclerView;
SharedPreferences userPreferences;
SharedPreferences.Editor userEditor;
String token;
public FragmentInicio() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment FragmentInicio.
*/
// TODO: Rename and change types and number of parameters
public static FragmentInicio newInstance(String param1, String param2) {
FragmentInicio fragment = new FragmentInicio();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_inicio, container, false);
btnControlar = view.findViewById(R.id.btnControlar);
btnAddFeed = view.findViewById(R.id.btnAddFeed);
btnControlar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(v.getContext(), ControlActivity.class));
}
});
btnAddFeed.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(v.getContext(), AgregarFeedActivity.class));
}
});
nQueue = SingletonRequest.getInstance(view.getContext()).getRequestQueue();
adF = new ArrayList<>();
userPreferences = view.getContext().getSharedPreferences(USER_PREFERENCES, Context.MODE_PRIVATE);
userEditor = userPreferences.edit();
token = userPreferences.getString(TOKEN_KEY, null);
getFeeds();
return view;
}
public void getFeeds() {
String url = "https://cleanbotapi.live/api/v1/feeds";
final JsonObjectRequest getFeeds = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerFeed);
recyclerView.setHasFixedSize(true);
LinearLayoutManager linearManager = new LinearLayoutManager(view.getContext());
recyclerView.setLayoutManager(linearManager);
final Gson gson = new Gson();
final AdafruitFeed adafruitFeed = gson.fromJson(response.toString(), AdafruitFeed.class);
adapterFeed = new AdafruitFeedAdapter(adafruitFeed.getListFeedData());
temperatura = adafruitFeed.getListFeedData().get(0).getName();
distancia = adafruitFeed.getListFeedData().get(1).getName();
infrarrojo = adafruitFeed.getListFeedData().get(2).getName();
polvo = adafruitFeed.getListFeedData().get(3).getName();
recyclerView.setAdapter(adapterFeed);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.i("errorPeticion", error.toString());
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Authorization", "Bearer " + token);
return headers;
}
};
nQueue.add(getFeeds);
}
}
I trying to create an OnClickListener for everyone of my Adafruit feeds but i cant.
First of all the naming convention of a class should be in "PascalCase".
You need to define an interface that contains a method for your listener and pass it to the constructor of the adapter. And then also pass this listener to your ViewHolder by constructor.
Example:
public class AdafruitFeedAdapter extends RecyclerView.Adapter<AdafruitFeedAdapter.viewholder> {
public interface OnClickListener {
void onClick(FeedData data, int position);
}
ArrayList<FeedData> feedData;
OnClickListener clickListener;
public AdafruitFeedAdapter(ArrayList<FeedData> feedData,OnClickListener clickListener) {
this.feedData = feedData;
this.clickListener = clickListener;
}
...
#NonNull
#Override
public viewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_feed, parent, false);
return new viewholder(v,clickListener);
}
}
And in your viewholder modify it like below:
...
OnClickListener clickListener;
public viewholder(#NonNull View itemView,OnClickListener clickListener) {
super(itemView);
this.clickListener = clickListener;
btnMisFeeds = itemView.findViewById(R.id.btnMisFeeds);
btnMisFeeds.setOnClickListener(this);
}
...
#Override
public void onClick(View v) {
clickListener.onClick(dataHolder,getBindingAdapterPosition());
}
...
And your fragment:
public class FragmentInicio extends Fragment implements AdafruitFeedAdapter.OnClickListener {
...
#override
public void onClick(FeedData data, int position){
// TODO: implement your intent action
}
...
}
And your adapter: adapterFeed = new AdafruitFeedAdapter(adafruitFeed.getListFeedData(),FragmentInicio.this);

I can't make my OnClick method work in a RecyclerView

I've been trying to delete data from firebase with an OnClick RecyclerView method, but nothing works. I can't even make my OnClick method works. I have watched videos and tutorials, I've tried so much stuff and nothing helps...
Here is my adapter class:
public class myadapter extends RecyclerView.Adapter<myadapter.myviewholder>{
ArrayList<datamodel> dataholder;
public myadapter(ArrayList<datamodel> dataholder) {
this.dataholder = dataholder;
}
#NonNull
#Override
public myviewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false);
return new myviewholder(view);
}
#Override
public void onBindViewHolder(#NonNull myviewholder holder, int position) {
Glide.with(holder.itemView.getContext()).load(dataholder.get(position).getImageurl()).into(holder.CircleImg);
holder.header.setText(dataholder.get(position).getHeader());
holder.descr.setText(dataholder.get(position).getDescr());
holder.price.setText(dataholder.get(position).getPrec());
}
#Override
public int getItemCount() {
return dataholder.size();
}
class myviewholder extends RecyclerView.ViewHolder{
CircleImageView CircleImg;
TextView header, descr, price;
public myviewholder(#NonNull View itemView) {
super(itemView);
CircleImg = itemView.findViewById(R.id.circle1);
header = itemView.findViewById(R.id.txtheader1);
descr = itemView.findViewById(R.id.txtdescr1);
price = itemView.findViewById(R.id.txtprecio1);
}
}
And my fragment (the one that have the recyclerView):
public class articulos extends Fragment {
private FirebaseUser firebaseUser;
private String uid;
// 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 DatabaseReference myRef;
private Context mContext;
private myadapter myadapter;
RecyclerView recyclerView;
ArrayList<datamodel> dataholder;
public articulos() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment articulos.
*/
// TODO: Rename and change types and number of parameters
public static articulos newInstance(String param1, String param2) {
articulos fragment = new articulos();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_articulos, container, false);
recyclerView = view.findViewById(R.id.rv);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
myRef = FirebaseDatabase.getInstance().getReference();
dataholder= new ArrayList<>();
getDataFromFirebase();
//datamodel ob1 = new datamodel("Esta nueva", "5000MXN", "wwsad.adasd", "asdasdsa");
// dataholder.add(ob1);
//recyclerView.setAdapter(new myadapter(dataholder));
return view;
}
private void getDataFromFirebase() {
firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
uid = firebaseUser.getUid();
Query query = myRef.child("Usuarios").child(uid).child("articulos");
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
ClearAll();
for(DataSnapshot snapshot1 : snapshot.getChildren()){
datamodel datamodel = new datamodel();
datamodel.setImageurl(snapshot1.child("imageurl").getValue(String.class));
datamodel.setDescr(snapshot1.child("descripcion").getValue(String.class));
datamodel.setHeader(snapshot1.child("nombre").getValue(String.class));
datamodel.setPrec(snapshot1.child("precio").getValue(String.class));
dataholder.add(datamodel);
}
myadapter = new myadapter(dataholder);
recyclerView.setAdapter(new myadapter(dataholder));
myadapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
private void ClearAll(){
if(dataholder != null){
dataholder.clear();
if(myadapter != null){
myadapter.notifyDataSetChanged();
}
}
dataholder = new ArrayList<>();
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button mbtnNuevoArticulo = view.findViewById(R.id.btnNuevoArticulo);
mbtnNuevoArticulo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Navigation.findNavController(v).navigate(R.id.agregarart);
}
});
}
If anyone can tell me what to do and how to do it, please.. I need it so bad
Try set onclicklistener on viewholder class
class myviewholder extends RecyclerView.ViewHolder implements View.OnClickListener {
CircleImageView CircleImg;
TextView header, descr, price;
public myviewholder(#NonNull View itemView) {
super(itemView);
CircleImg = itemView.findViewById(R.id.circle1);
header = itemView.findViewById(R.id.txtheader1);
descr = itemView.findViewById(R.id.txtdescr1);
price = itemView.findViewById(R.id.txtprecio1);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
//do something when clicked
}
}
You can apply onclick listener by using following code :
holder.header.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//do something.
}
});
add this code in your onBindViewHolder of Adapter. Just make sure to change the id of holder.
full code :
#Override
public void onBindViewHolder(#NonNull myviewholder holder, int position) {
Glide.with(holder.itemView.getContext()).load(dataholder.get(position).getImageurl()).into(holder.CircleImg);
holder.header.setText(dataholder.get(position).getHeader());
holder.descr.setText(dataholder.get(position).getDescr());
holder.price.setText(dataholder.get(position).getPrec());
holder.header.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//do something.
}
});
}
Create object of view inside your view holder and also initialize button.setOnClickListener(this) inside viewHolder itself and setting on click inside onBinfViewHolder(...)(only in JAVA). In kotlin you just need to set on click method inside onBindViewHolder(...).
Example:
class YourAdapter():RecyclerView.Adapter<YourAdapter.YourViewHolder>() {
class YourViewHolder(view: View):RecyclerView.ViewHolder(view){
val yourButton:Button = view.findViewById(R.id.landingViewBtn)
}
override fun onBindViewHolder(holder: YourViewHolder, position: Int) {
holder.yourButton.setOnClickListener {
//do Something
val intent = Intent(context,nextActivity::class.java)
context.startActivity(intent)
}
}
}

list is not updating after first call from get API

get API link using retrofit and live data call the first time after some time not updating itself
Call the function on resume in fragment
LiveDataReport used in call retrofit and set the value mutable live
data
Model Fragment used in RecyclerView and adapter
I want get change on anything or updating in get API
immediate change updating RecyclerView list
here my code
Java
public class LiveDataReport {
private static LiveDataReport liveDataReport;
private MutableLiveData<ArrayList<Model>> modelLiveData = new MutableLiveData<>();
private ApiService apiService;
private LiveDataReport() {
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new BasicAuth("user", "pass")).build();
Retrofit retrofit = new Retrofit.Builder()
.client(client)
.baseUrl("http://someipaddress")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create()).build();
apiService = retrofit.create(ApiService.class);
getModelLiveData();
}
public synchronized static LiveDataReport getInstance() {
if (liveDataReport == null)
liveDataReport = new LiveDataReport();
return liveDataReport;
}
public LiveData<ArrayList<Model>> getModelLiveData() {
Call<ArrayList<Model>> arrayListCall = apiService.getLiveDataJson();
arrayListCall.enqueue(new Callback<ArrayList<Model>>() {
#Override
public void onResponse(#NotNull Call<ArrayList<Model>> call, #NotNullResponse<ArrayList<Model>> response) {
if (response.isSuccessful() && response.body() != null) {
System.out.println("//report change success Model");
modelLiveData.postValue(response.body());
}
}
#Override
public void onFailure(#NotNull Call<ArrayList<Model>> call, #NotNull Throwable t) {
System.out.println("//report change failure " + t.toString());
}
});
return modelLiveData;
}
}
public class MainViewModel extends AndroidViewModel {
private LiveData<ArrayList<Model>> liveData ;
public MainViewModel(#NonNull Application application) {
super(application);
liveData=LiveDataReport.getInstance().getModelLiveData();
}
public LiveData<ArrayList<Model>> getLiveData() {
System.out.println("//report call last update : getModelLiveData");
liveData=LiveDataReport.getInstance().getModelLiveData();
return liveData;
}
}
public class ModelFragment extends Fragment implements LifecycleOwner {
private MainViewModel mainViewModel;
private RecyclerView recyclerView;
private FragmentBinding binding;
private LiveDataAdapter adapter;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment, container, false);
mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
recyclerView = binding.myRecycleView;
adapter = new LiveDataAdapter();
recyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
recyclerView.setHasFixedSize(false);
return binding.getRoot();
}
#Override
public void onResume() {
super.onResume();
if (Utils.isNetWorkConnected(requireContext())) {
mainViewModel.getLiveData().observe(getViewLifecycleOwner(),new Observer<ArrayList<Model>>() {
#Override
public void onChanged(ArrayList<Model> models) {
recyclerView.setAdapter(adapter);
adapter.setModel(models,requireContext());
}
});
} else
Utils.alertCheckNetwork(requireContext());
}
}
public class LiveDataAdapter extends AdapterSkeleton<Model, LiveDataAdapter.CustomViewHolder> {
public LiveDataAdapter(Context context, ArrayList<Model> model, RecyclerView recyclerView, IsCanSetAdapterListener canSetAdapterListener){
this.context=context;
this.items=model;
this.isCanSetAdapterListener=canSetAdapterListener;
measureHeightRecyclerViewAndItem(recyclerView,R.layout.list_model);
}
#NonNull
#Override
public CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
ListModelBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.list_model, parent, false);
return new CustomViewHolder(binding);
}
#Override
public void onBindViewHolder(#NonNull CustomViewHolder holder, int position) {
if(skeletonConfig.isSkeletonIsOn()){
return;
}
else{
holder.binding.appSkeleton.setShowSkeleton(false);
holder.binding.appSkeleton.finishAnimation();
}
Model model = items.get(position);
holder.binding.setModel(reportStatus);
setAnimation(holder.itemView, position);
}
private void setAnimation(View viewToAnimate, int position) {
Animation animation = AnimationUtils.loadAnimation(context, R.anim.item_animation_fall_down);
viewToAnimate.startAnimation(animation);
}
class CustomViewHolder extends RecyclerView.ViewHolder {
ListModelBinding binding;
public CustomViewHolder(#NonNull ListModelBinding itemView) {
super(itemView.getRoot());
binding = itemView;
}
}
}
updating list does not means it will shown into RecyclerView immediately . you have to manually update RecyclerView as well .
to implement this concept , create a method into your RecyclerView Adapter something like this one below
void updateList(List<POJO> newList) {
oldList = newList;
notifyDataChange();
}
so you will see that your RecyclerView will update , i know that we use livedata to do it automatically but in order to update recyclerView you have to approach this concept .

Cannot cast onItem clicklistener inside Fragment Class form Adapter Class

I have an Fragment with recycleview where I populate it with json items from internet.
It load fine and Next step I want to is open new Activity when any row is clicked. It works in activity, thus I modified the same code for fragment but for fragment it throws exception in line
mExampleAdapter.setOnItemClickListener(getActivity());
with errror setOnItemClickListener of refrence adatper cannot be applied to Fragment activty and thus when I change line to
(ExampleAdapter.OnItemClickListener)
and when i build and run . Then app crashes with error that Mainactivity which holds framgnet cannot be cast in to .ExampleAdapter$OnItemClickListener
Here is my whole Fragment class
public class Mynotes extends Fragment implements ExampleAdapter.OnItemClickListener{
public static final String YTD_LINK = "link";
private RecyclerView mRecyclerView;
private ExampleAdapter mExampleAdapter;
private ArrayList<ExampleItem> mExampleList;
private RequestQueue mRequestQueue;
String url="https://api.myjson.com/bins/16mecx";
public Mynotes() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.activity_jsonfeed, container, false);
mRecyclerView = view.findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecyclerView.addItemDecoration(new MyDividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL, 36));
mExampleList = new ArrayList<>();
mExampleAdapter = new ExampleAdapter(getActivity(), mExampleList);
mRecyclerView.setAdapter(mExampleAdapter);
mExampleAdapter.setOnItemClickListener((ExampleAdapter.OnItemClickListener) getActivity());
parseJSON();
return view;
}
private void parseJSON() {
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
myProgressBar.setVisibility(View.GONE);
try {
JSONArray jsonArray = response.getJSONArray("hits");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject hit = jsonArray.getJSONObject(i);
String videoTitle = hit.getString("title");
String link = hit.getString("link");
mExampleList.add(new ExampleItem(videoTitle, link));
mExampleAdapter.notifyDataSetChanged();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
});
mRequestQueue.add(request);
}
#Override
public void onItemClick(int position) {
Intent intent = new Intent(getActivity(), NewActiviyt.class);
ExampleItem clickedItem = mExampleList.get(position);
intent.putExtra(YTD_LINK, clickedItem.getmLink());
startActivity(intent);
}
#Override
public void onRefresh() {
}
}
and my Adapter Class is
public class ExampleAdapter extends RecyclerView.Adapter<ExampleAdapter.ExampleViewHolder> {
private Context mContext;
private ArrayList<ExampleItem> mExampleList;
private OnItemClickListener mListener;
public interface OnItemClickListener {
void onItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
public ExampleAdapter(Context context, ArrayList<ExampleItem> exampleList) {
mContext = context;
mExampleList = exampleList;
}
#Override
public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(mContext).inflate(R.layout.example_item, parent, false);
return new ExampleViewHolder(v);
}
#Override
public void onBindViewHolder(ExampleViewHolder holder, int position) {
ExampleItem currentItem = mExampleList.get(position);
String title = currentItem.getTitle();
// int likeCount = currentItem.getLikeCount();
// String imageUrl = currentItem.getImageUrl();
holder.mTextViewCreator.setText(title);
// holder.mTextViewLikes.setText("Likes: " + likeCount);
// Glide.with(mContext).load(imageUrl).apply(RequestOptions.circleCropTransform()).into(holder.mImageView);
}
#Override
public int getItemCount() {
return mExampleList.size();
}
public class ExampleViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public TextView mTextViewCreator;
// public TextView mTextViewLikes;
// public ImageView mImageView;
public ExampleViewHolder(View itemView) {
super(itemView);
// mTextViewLikes = itemView.findViewById(R.id.text_view_likes);
// mImageView = itemView.findViewById(R.id.image_view);
mTextViewCreator = itemView.findViewById(R.id.text_title);
}
#Override
public void onClick(View view) {
if (mListener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
mListener.onItemClick(position);
}
}
}
}
}
Thanks in advance.
replace getActivity with getContext when you work in fragment,
You can read more here
What is different between getContext and getActivity from Fragment in support library?
Your activity should implement ExampleAdapter.OnItemClickListener

RecyclerView isn't attached to Adapter

I have this strage error. I'm downloading data from API and I want to print it in RecyclerView nested in Fragment called ListFragment. This fragment is one of three which I use in ViewPager. ViewPager works fine. For now, I want to display only two textViews. Layout for them has name single_data_layout. List<Feature> features is my DataResponse. Project builds normaly without issues and I receive in Log that "Data is successfully downloaded". When I run app in DebugMode I get message that my RecyclerView isn't attached to adapter. Any ideas?
ApiClient:
public interface ApiClient {
#GET("/query?format=geojson&starttime&minsig=700")
Call<DataResponse> getData();
}
ApiClientFactory:
public class ApiClientFactory {
public static final String baseURL = "https://earthquake.usgs.gov/fdsnws/event/1/";
public ApiClient createApiClient(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseURL)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit.create(ApiClient.class);
}
}
DataAdapter:
public class DataAdapter extends RecyclerView.Adapter<DataAdapter.DataViewHolder> {
private List<Feature> features;
private ListFragment listFragment;
private Context context;
private LayoutInflater inflater;
public DataAdapter(List<Feature> features) {
this.features = features;
}
#Override
public DataViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
inflater = LayoutInflater.from(context);
View contractView = inflater.inflate(R.layout.single_data_layout, parent, false);
return new DataViewHolder(contractView);
}
#Override
public void onBindViewHolder(DataViewHolder holder, int position) {
holder.place.setText(features.get(position).getProperties().getPlace());
holder.alert.setText(features.get(position).getProperties().getAlert());
}
#Override
public int getItemCount() {
return features.size();
}
public static class DataViewHolder extends RecyclerView.ViewHolder {
private final TextView place;
private final TextView alert;
public DataViewHolder(View view) {
super(view);
place = (TextView) view.findViewById(R.id.place_text_view);
alert = (TextView) view.findViewById(R.id.alert_text_view);
}
}
}
ListFragment:
public class ListFragment extends Fragment {
private RecyclerView recyclerView;
private static final String TAG = ListFragment.class.getSimpleName();
private ApiClient apiClient;
private List<Feature> features;
private RecyclerView.LayoutManager layoutManager;
private DataAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_list, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
getData();
return view;
}
private void getData() {
apiClient = new ApiClientFactory().createApiClient();
apiClient.getData().enqueue(new Callback<DataResponse>() {
#Override
public void onResponse(Call<DataResponse> call, Response<DataResponse> response) {
if (response.isSuccessful()) {
features = response.body().getFeatures();
adapter = new DataAdapter(features);
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(layoutManager);
}
Log.d(TAG, "Data successfully downloaded");
}
#Override
public void onFailure(Call<DataResponse> call, Throwable t) {
Log.e(TAG, t.toString());
}
});
}
}
You should change the way you inflate the layout. This should do the trick.
public class DataAdapter extends RecyclerView.Adapter<DataAdapter.DataViewHolder> {
private List<Feature> features;
public DataAdapter(List<Feature> features) {
this.features = features;
}
#Override
public DataAdapter.DataViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.single_data_layout, parent, false);
return new DataViewHolder(view);
}
#Override
public void onBindViewHolder(DataViewHolder holder, int position) {
holder.place.setText(features.get(position).getProperties().getPlace());
holder.alert.setText(features.get(position).getProperties().getAlert());
}
#Override
public int getItemCount() {
return features.size();
}
public static class DataViewHolder extends RecyclerView.ViewHolder {
private final TextView place;
private final TextView alert;
public DataViewHolder(View view) {
super(view);
place = (TextView) view.findViewById(R.id.place_text_view);
alert = (TextView) view.findViewById(R.id.alert_text_view);
}
}
}
I see that the adapter class don't have a context , I guess if you add to the adapter constructor Context c as a second parameter your problem will be solved
try to replase
public DataAdapter(List<Feature> features) {
this.features = features;
}
by this
public DataAdapter(List<Feature> features, Context c) {
this.features = features;
this.context = c;
}
and replace this line in the fragment class
adapter = new DataAdapter(features);
by this
adapter = new DataAdapter(features,getActivity());
hope this will help you :)

Categories

Resources