I'm loading ads in onClick of RecyclerView's adapter.
In fragment it is perfectly working in this code:
interstitialAd.loadAd(GDPR.getAdRequest(getActivity()));
But in adapter it is not working in these method I tried:
mInterstitialAd.loadAd(GDPR.getAdRequest(context));
I also tried this but it is not working:
mInterstitialAd.loadAd(GDPR.getAdRequest(this));
GDPR.getAdRequest's code is:
public static AdRequest getAdRequest(Activity activity) {
return new AdRequest.Builder()
.addNetworkExtrasBundle(AdMobAdapter.class, GDPR.getBundleAd(activity))
.build();
}
this is adapter's code:
public class VideosAdapter extends RecyclerView.Adapter<VideosAdapter.VideosViewHolder> {
private Context context;
private Video[] data;
private int layout;
private InterstitialAd mInterstitialAd;
public VideosAdapter(Context context, Video[] data, int layout) {
this.context = context;
this.data = data;
this.layout = layout;
}
#NonNull
#Override
public VideosViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(layout,null);
return new VideosViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull VideosViewHolder holder, final int position) {
final Video selectedItem = data[position];
holder.videoTitle.setText(selectedItem.getVideoTitle());
holder.videoCategoryTitle.setText(selectedItem.getCategoryName());
if (selectedItem.getVideoType().equals("0")){
String thumbImg = Constants.SERVER_IMG_FIRST + selectedItem.getVideoThumb();
Glide.with(context).load(Uri.parse(thumbImg)).into(holder.videoThumb);
}else {
// Get V and display img
Uri uri = Uri.parse(selectedItem.getVideoUrl());
String videoId = uri.getQueryParameter("v");
String thumbYtImg = Constants.YOUTUBE_IMG_FIRST + videoId + Constants.YOUTUBE_IMG_BACK;
Glide.with(context).load(Uri.parse(thumbYtImg)).into(holder.videoThumb);
}
String thumbCat = Constants.SERVER_IMG_FIRST + selectedItem.getCategoryThumb();
Glide.with(context).load(Uri.parse(thumbCat)).into(holder.videoCategoryThumb);
holder.videoInfoBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (Constants.SETTINGS.getAdmob().equals("1")){
Constants.ADS_COUNT++;
if (Constants.ADS_COUNT>=Integer.valueOf(Constants.SETTINGS.getAdmobIntrestitialAdDisplayAfter())){
Constants.ADS_COUNT = 0;
mInterstitialAd = new InterstitialAd(context);
mInterstitialAd.setAdUnitId(Constants.SETTINGS.getAdmobIntrestitialId());
mInterstitialAd.loadAd(GDPR.getAdRequest(context));
mInterstitialAd.setAdListener(new AdListener() {
#Override
public void onAdLoaded() {
super.onAdLoaded();
if(mInterstitialAd.isLoaded()){
mInterstitialAd.show();
}
}
#Override
public void onAdFailedToLoad(int errorCode) {
// Code to be executed when an ad request fails.
toDoOnInfoBtnClicked(position,data);
}
#Override
public void onAdClosed() {
// Code to be executed when the interstitial ad is closed.
toDoOnInfoBtnClicked(position,data);
}
});
}else{
toDoOnInfoBtnClicked(position,data);
}
}else{
toDoOnInfoBtnClicked(position,data);
}
}
});
}
#Override
public int getItemCount() {
return data.length;
}
public class VideosViewHolder extends RecyclerView.ViewHolder {
TextView videoTitle,videoCategoryTitle;
public VideosViewHolder(#NonNull View itemView) {
super(itemView);
videoTitle = itemView.findViewById(R.id.video_title);
videoCategoryTitle = itemView.findViewById(R.id.video_category_title);
}
}
}
It's just because you are sending Context object to the method getAdRequest(Activity activity) which needs Activity object. So you can fix it in 2 ways
Change adapter to take Activity not Context. like below
public class VideosAdapter extends RecyclerView.Adapter<VideosAdapter.VideosViewHolder> {
private Activity activity;
..
public VideosAdapter(Activity activity, Video[] data, int layout) {
this.activity = activity;
...
}
The second way to fix this is, change getAdRequest(Activity activity), like below
public static AdRequest getAdRequest(Context context) {
return new AdRequest.Builder()
.addNetworkExtrasBundle(AdMobAdapter.class, GDPR.getBundleAd(context))
.build();
}
But in the second way, I am not sure if GDPR.getBundleAd() can take context. So better to go with 1st way
3rd way is to typecast context as Activity as you commented. Like
mInterstitialAd.loadAd(GDPR.getAdRequest((Activity) context));
But there is one problem in this approach. As the constructor of your adapter take Context parameter, any Activity which using this adapter can create the object like new VideosAdapter(activity, ...) BUT can create the object like new VideosAdapter(applicationContext, ...) or new VideosAdapter(objectOfcontext, ...). So in the last 2 cases, you will get a typecast exception.
You should pass an Activity object to your adapter. otherwise you'll face with that error.
use like this :
adapter = new VideosAdapter(YourActivity.this,yourData,R.layout.some_layout);
Related
I need some help for a summer project
This is my Events fragment
This is my MyList fragment
I'm using a RecyclerView+Cardview to display the Events. The idea is that the user can click the big plus on the right side of each card, and the card would be displayed in the MyList fragment. I would like to ask if it's possible to transfer a card directly from one fragment to another? Also, both fragments are contained within the same activity, which makes it a little trickier(I haven't found any available solutions).
If that is not possible, another way is to transfer the reference type object contained in the CardView to the MyList fragment. However, this is even less straightforward. This is because the button is inflated in the adapter, but there is no reference type object created here. I have seen many tutorials on using the Parcelable interface, however, I don't know how to implement it here when I'm unable to even create the object in the adapter. The reference object is created in another activity and stored in Firebase before it is read and displayed.
I'm going to attach my EventsAdapter.java and EventsItem.java and EventsFragment.java code below, but please let me know if I should include more code to describe the problem.
Thanks for reading my very long post!!
public class EventsAdapter extends RecyclerView.Adapter<EventsAdapter.EventsViewHolder> implements Filterable {
private ArrayList<EventsItem> mEventsList;
private ArrayList<EventsItem> mEventsListFull;
private EventsAdapter.OnItemClickListener mListener;
private Context mContext;
private DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.UK);
public interface OnItemClickListener {
void onItemClick(int position);
}
//the ViewHolder holds the content of the card
public static class EventsViewHolder extends RecyclerView.ViewHolder {
public ImageView mImageView;
public ImageView mAddButton;
public TextView mTextView1;
public TextView mTextView2;
public TextView mTextView3;
public TextView mTextView4;
public TextView mTextView5;
public EventsViewHolder(Context context, View itemView, final EventsAdapter.OnItemClickListener listener) {
super(itemView);
final Context context1 = context;
mImageView = itemView.findViewById(R.id.imageView);
mAddButton = itemView.findViewById(R.id.image_add);
mTextView1 = itemView.findViewById(R.id.title);
mTextView2 = itemView.findViewById(R.id.event_description);
mTextView3 = itemView.findViewById(R.id.date);
mTextView4 = itemView.findViewById(R.id.location);
mTextView5 = itemView.findViewById(R.id.time);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position);
}
}
}
});
mAddButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String str1 = mTextView1.getText().toString();
String str2 = mTextView2.getText().toString();
String str3 = mTextView3.getText().toString();
String str4 = mTextView4.getText().toString();
String str5 = mTextView5.getText().toString();
Bundle bundle = new Bundle();
bundle.putString("title", str1);
bundle.putString("event description", str2);
bundle.putString("date", str3);
bundle.putString("location", str4);
bundle.putString("time", str5);
MylistFragment mlf = new MylistFragment();
mlf.setArguments(bundle);
}
});
}
}
//Constructor for EventsAdapter class. This ArrayList contains the
//complete list of items that we want to add to the View.
public EventsAdapter(Context context, ArrayList<EventsItem> EventsList) {
mEventsList = EventsList;
mContext = context;
mEventsListFull = new ArrayList<>(EventsList); // copy of EventsList for SearchView
}
//inflate the items in a EventsViewHolder
#NonNull
#Override
public EventsAdapter.EventsViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.event_item, parent, false);
EventsAdapter.EventsViewHolder evh = new EventsAdapter.EventsViewHolder(mContext, v, mListener);
return evh;
}
#Override
public void onBindViewHolder(#NonNull EventsAdapter.EventsViewHolder holder, int position) {
EventsItem currentItem = mEventsList.get(position);
holder.mImageView.setImageResource(currentItem.getProfilePicture());
holder.mTextView1.setText(currentItem.getTitle());
holder.mTextView2.setText(currentItem.getDescription());
holder.mTextView3.setText(df.format(currentItem.getDateInfo()));
holder.mTextView4.setText(currentItem.getLocationInfo());
holder.mTextView5.setText(currentItem.getTimeInfo());
}
#Override
public int getItemCount() {
return mEventsList.size();
}
public class EventsItem implements Occasion, Parcelable {
//fields removed for brevity
//constructor removed for brevity
}
public EventsItem() {
}
public EventsItem(Parcel in) {
profilePicture = in.readInt();
timeInfo = in.readString();
hourOfDay = in.readInt();
minute = in.readInt();
locationInfo = in.readString();
title = in.readString();
description = in.readString();
}
public static final Creator<EventsItem> CREATOR = new Creator<EventsItem>() {
#Override
public EventsItem createFromParcel(Parcel in) {
return new EventsItem(in);
}
#Override
public EventsItem[] newArray(int size) {
return new EventsItem[size];
}
};
//getter methods have been removed for brevity
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(profilePicture);
dest.writeString(timeInfo);
dest.writeString(locationInfo);
dest.writeString(title);
dest.writeString(description);
dest.writeString(df.format(dateInfo));
dest.writeInt(hourOfDay);
dest.writeInt(minute);
}
}
public class EventsFragment extends Fragment {
ArrayList<EventsItem> EventsItemList;
FirebaseDatabase mDatabase;
DatabaseReference mDatabaseReference;
ValueEventListener mValueEventListener;
private RecyclerView mRecyclerView;
private RecyclerView.LayoutManager mLayoutManager;
private EventsAdapter mAdapter;
private View rootView;
public FloatingActionButton floatingActionButton;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_events, container, false);
mDatabase = FirebaseDatabase.getInstance();
mDatabaseReference = mDatabase.getReference().child("Events");
createEventsList();
buildRecyclerView();
floatingActionButton = rootView.findViewById(R.id.fab);
floatingActionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), EventsAdder.class);
startActivity(intent);
}
});
mValueEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
EventsItemList.add(snapshot.getValue(EventsItem.class));
}
EventsAdapter eventsAdapter = new EventsAdapter(getActivity(), EventsItemList);
mRecyclerView.setAdapter(eventsAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
mDatabaseReference.addValueEventListener(mValueEventListener);
setHasOptionsMenu(true);
Toolbar toolbar = rootView.findViewById(R.id.events_toolbar);
AppCompatActivity activity = (AppCompatActivity) getActivity();
activity.setSupportActionBar(toolbar);
return rootView;
}
public void createEventsList() {
EventsItemList = new ArrayList<>();
}
public void buildRecyclerView() {
mRecyclerView = rootView.findViewById(R.id.recyclerview);
mLayoutManager = new LinearLayoutManager(getContext());
mAdapter = new EventsAdapter(getActivity(), EventsItemList);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
}
}
If you would like to see the same CardView within the MyListFragment, you could have the MyListFragment contain a RecyclerView, and reuse the same EventsAdapter and EventsViewHolder. The only difference is that rather than populating the adapter with all the children of the "Events" from your database, you would only populate it with the single Event that you want.
Also, since you have made your Event class implement parcelable, you do not need to manually create the bundle when clicking the plus button.
I am assuming you have a single Activity, and you simply want to replace the EventsFragment with the MyListFragment. Checkout the docs for replacing one fragment with another.
Step 1:
Extend your onItemClickListener to look like:
public interface OnItemClickListener {
void onItemClick(int position);
void onPlusButtonClick(int position);
}
and adjust the code in your EventsViewHolder constructor to look like this when the plus button is clicked:
mAddButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
// no need to manually create the bundle here
// you already have all the information you need
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onPlusButtonClick(position);
}
}
}
});
Step 2:
Implement our new method onPlusButtonClick. As per our discussion in the comments, it seems you do not implement this interface anywhere. You can implement it inside the constructor to your EventsAdapter:
public EventsAdapter(Context context, ArrayList<EventsItem> EventsList) {
mEventsList = EventsList;
mContext = context;
mEventsListFull = new ArrayList<>(EventsList); // copy of EventsList for SearchView
mListener = new OnItemClickListener() {
#Override
public void onItemClick() {
// handle clicking the entire view holder
// NOTE: inside your EventsViewHolder, it looks like you call this method on the entire itemView. This could 'swallow' the click on the plus button. You may need to adjust your code to handle this.
}
#Override
public void onPlusButtonClick(int position) {
MyListFragment myListFragment = new MyListFragment();
Event event = mEventsList.get(position);
Bundle bundle = new Bundle();
bundle.putExtra("event", event); // this will work due to implementing parcelable
myListFragment.setArguments(bundle);
// use mContext since im assuming we areinside adapter
// if in an Activity, no need to use context to get the fragment manager
FragmentTransaction transaction = mContext.getSupportFragmentManager().beginTransaction();
// Replace the EventsFragment with the MyListFragment
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, myListFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
Step 3:
Inside your MyListFragments onCreateView() method:
#Override
public View onCreateView (
LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState
) {
Bundle bundle = getArguments();
Event event = bundle.getExtra("event"); // again, will work due to implementing parcelable
// from here you should bind to a recycler view, and you can even reuse your adapter like so:
List<EventsItem> singleEventList = new List<EventsItem>();
singleEventList.add(event);
EventsAdapter adapter = new EventsAdapter(getActivity(), singleEventList);
// be sure to inflate and return your view here...
}
and you should be good to go!
I have left out bits of code here and there for simplicity.. but I hope this is understandable.
As a side note.. in your firebase database listener, it is bad practice to create a new EventsAdapter every single time your data is updated. Instead, you should update the data in the adapter with the new values. Do this by creating a public method inside the adapter such as replaceEvents(List<EventsItem> newEvents), and inside, replace mEventsList with the new events, then call notifyDataSetChanged().
I have 3 RecyclerView to display most visited market, close by markets and favorite markets.
I have created 3 difference instance of MarketAdapter class for the three RecyclerView
Everything works fine, but my Activity implements one OnClickListener and I cant figure out which adapter was clicked. Is it possible to programmatically determine the Adapter that was clicked from the OnClickListener?
Here is my MarketAdapter Class
public class MarketAdapter extends RecyclerView.Adapter<MarketAdapter.ViewHolder> {
ArrayList<Markets> mMarket = new ArrayList<>();
Context mContext;
private final MarketsItemsClickListener mItemsClickListener;
private final MarketLongClickListener mLongClickListener;
private final MarketClickListener mClickListener;
public MarketAdapter(Context context, MarketsItemsClickListener itemsClickListener, MarketClickListener clickListener, MarketLongClickListener longClickListener){
mContext = context;
mItemsClickListener = itemsClickListener;
mLongClickListener = longClickListener;
mClickListener = clickListener;
}
public interface MarketLongClickListener{
void onLongClick(int position);
}
public interface MarketClickListener{
void onClick(int position);
}
public interface MarketsItemsClickListener{
void imageViewOnClickListener(View view, int position);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
Context context = viewGroup.getContext();
int layoutForListItem = R.layout.list_market;
LayoutInflater inflater = LayoutInflater.from(context);
boolean shouldAttachToParentImmediately = false;
View view = inflater.inflate(layoutForListItem, viewGroup, shouldAttachToParentImmediately);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int i) {
viewHolder.bindView(i);
}
#Override
public int getItemCount() {
if(mMarket != null) return mMarket.size();
return 0;
}
public void setData(ArrayList<Markets> markets){
mMarket = markets;
notifyDataSetChanged();
}
public void addData(Markets market, int position){
mMarket.add(0, market);
notifyDataSetChanged();
}
public Markets getItem(int position){return mMarket.get(position);}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener, View.OnClickListener{
ImageView mImageView;
TextView mNameTextView, mCityTextView;
public ViewHolder(#NonNull View itemView) {
super(itemView);
mImageView = itemView.findViewById(R.id.image_view);
mNameTextView = itemView.findViewById(R.id.name_text_view);
mCityTextView = itemView.findViewById(R.id.city_text_view);
itemView.setOnLongClickListener(this);
itemView.setOnClickListener(this);
}
void bindView(int position){
Markets market = getItem(position);
mCityTextView.setText(market.getCity());
mNameTextView.setText(market.getName());
}
#Override
public void onClick(View v) {
//Get position of Adapter
int position = getAdapterPosition();
//Handle the click
mClickListener.onClick(position);
}
#Override
public boolean onLongClick(View v) {
return false;
}
}
}
and OnClickListener from Activity
#Override
public void onClick(int position) {}
You can pass a tag in the constructor and get that tag back via a click listener to identify the click as
private final MarketsItemsClickListener mItemsClickListener;
private final MarketLongClickListener mLongClickListener;
private final MarketClickListener mClickListener;
private final String mTag;
public MarketAdapter(Context context, MarketsItemsClickListener itemsClickListener, MarketClickListener clickListener, MarketLongClickListener longClickListener, String tag){
mTag = tag
mContext = context;
mItemsClickListener = itemsClickListener;
mLongClickListener = longClickListener;
mClickListener = clickListener;
}
Modify the listener as
public interface MarketClickListener{
void onClick(int position, String tag);
}
and the listener code in activity as
#Override
public void onClick(int position, String tag) {
switch(tag){
case "adapter1":
break;
case "adapter2":
break;
case "adapter3":
break;
}
}
and create adapter object as
MarketAdapter adapter = new MarketAdapter("adapter1"....);
MarketAdapter adapter1 = new MarketAdapter("adapter2"....);
MarketAdapter adapter2 = new MarketAdapter("adapter3"....);
and use
mClickListener.onClick(position, mTag);
Note: You can use enums as well
You can add a attribute inside MarketAdapter so that you can tell what instance is that adapter.
Change your custom click listener to receive the adapter type:
public interface MarketClickListener {
//You can change this to receive any data you want from the adapter
void onClick(int position, int adapterType);
}
Add the constants, the identifier attribute and change the listener in your adatper:
public class MarketAdapter extends RecyclerView.Adapter<MarketAdapter.ViewHolder> {
//The constants types
public static int MOST_VISITED_MARKETS = 1;
public static int CLOSE_BY_MARKETS = 2;
public static int FAVORITE_MARKETS = 3;
//New attribute
private int adapterType;
...
//Keep the listener
private final MarketClickListener mClickListener;
public MarketAdapter(Context context, MarketsItemsClickListener itemsClickListener, MarketClickListener clickListener, MarketLongClickListener longClickListener, int adapterType){
...
//Set the type
adapterType = adapterType;
}
...
}
In your activity:
mostVisitedRecyclerView.setAdapter(new MarketAdapter(this,itemsClickListener,clickListener,longClickListener,MarketAdapter.MOST_VISITED_MARKETS ));
closeByRecyclerView.setAdapter(new MarketAdapter(this,itemsClickListener,clickListener,longClickListener,MarketAdapter.CLOSE_BY_MARKETS));
favoritesRecyclerView.setAdapter(new MarketAdapter(this,itemsClickListener,clickListener,longClickListener,MarketAdapter.FAVORITE_MARKETS));
In your view holder, change the onClick:
#Override
public void onClick(View v) {
//Get position of Adapter
int position = getAdapterPosition();
//Handle the click
mClickListener.onClick(position,adapterType);
}
I didn't test this but I think it will do the trick. Try it out.
If you want to do it this way, I would add a new variable to the adapters constructor, and then use a case/if statement to determine what you want to do in your onbindviewholder.
I've have an arraylist that is not displaying in RecyclerView. The arraylist has data but my RecyclerView Adapter shows no error, nor is my fragment activity showing no errors. I am at a complete loss where the programming error is. The getItemCount seems correct, the holder seems correct and the Fragment seems to be correct but I know there is a mistake somewhere. Here is my code:
Fragment:
public class TestFragment extends Fragment {
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
List<PlanetData> items = new ArrayList<>();
RecyclerView mRecyclerView;
PlanetRecyclerViewAdapter adapter;
private OnFragmentInteractionListener mListener;
public TestFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
planetList();
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_test, container, false);
mRecyclerView = (RecyclerView)view.findViewById(R.id.planet_recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecyclerView.addItemDecoration(new DividerItemDecoration(mRecyclerView.getContext(),DividerItemDecoration.VERTICAL));
adapter = new PlanetRecyclerViewAdapter(items, mRecyclerView.getContext());
mRecyclerView.setAdapter(adapter);
return view;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
private List<PlanetData> planetList() {
List<PlanetData> planetvalues = new ArrayList<>();
planetvalues.add(new com.ksburneytwo.planetmathtest.PlanetData("12"));
planetvalues.add(new com.ksburneytwo.planetmathtest.PlanetData(Double.toString(Mercury.getMercuryRA())));
planetvalues.add(new com.ksburneytwo.planetmathtest.PlanetData(Double.toString(Venus.getVenusRA())));
planetvalues.add(new com.ksburneytwo.planetmathtest.PlanetData(Double.toString(Moon.getMoonRA())));
planetvalues.add(new com.ksburneytwo.planetmathtest.PlanetData(Double.toString(Mars.getMarsRA())));
planetvalues.add(new com.ksburneytwo.planetmathtest.PlanetData(Double.toString(Jupiter.getJupiterRA())));
planetvalues.add(new com.ksburneytwo.planetmathtest.PlanetData(Double.toString(Saturn.getSaturnRA())));
planetvalues.add(new com.ksburneytwo.planetmathtest.PlanetData(Double.toString(Uranus.getUranusRA())));
planetvalues.add(new com.ksburneytwo.planetmathtest.PlanetData(Double.toString(Neptune.getNeptuneRA())));
planetvalues.add(new com.ksburneytwo.planetmathtest.PlanetData(Double.toString(Pluto.getPlutoRA())));
System.out.println("This is Arraylist:" + planetvalues);
return planetvalues;
}
}
Here is the PlanetData class:
public class PlanetData {
private String PlanetRA;
public PlanetData(String PlanetRA) {
this.PlanetRA = PlanetRA;
}
#Override
public String toString() {
return PlanetRA;
}
public String getPlanetRA (){
return PlanetRA;
}
public void setPlanetRA(String PlanetRA){
this.PlanetRA = PlanetRA;
}
}
Here is my RecyclerView Adapter:
public class PlanetRecyclerViewAdapter extends RecyclerView.Adapter<PlanetRecyclerViewAdapter.ViewHolder> {
private List<PlanetData> mPlanetDataList;
Context mContext;
public static class ViewHolder extends RecyclerView.ViewHolder{
public TextView currentRA;
public ViewHolder(View itemView) {
super(itemView);
currentRA = (TextView) itemView.findViewById(R.id.planet_location);
}
}
public PlanetRecyclerViewAdapter(List<PlanetData> mPlanetDataList, Context mContext){
this.mPlanetDataList = mPlanetDataList;
this.mContext = mContext;
}
#Override
public PlanetRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.planet_recycler_item,parent, false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder( PlanetRecyclerViewAdapter.ViewHolder holder, int position) {
holder.currentRA.setText(mPlanetDataList.get(position).getPlanetRA());
}
#Override
public int getItemCount() {
return mPlanetDataList.size();
}
}
I don't see you ever actually adding anything to the items list.
You call planetList() in onCreateView(), but you aren't using the result of it, and planetList() doesn't affect items in any way: it makes its own ArrayList and returns that.
Either remove planetValues from the planetList() method and reference items directly:
private void planetList() { //changed signature to "void"
items.add(...);
items.add(...);
//etc
}
Or set the result of planetList() to items when you call it:
items.addAll(planetList());
You haven't populated items.
items = planetList();
What i'm trying to do is that, I have an adapter which I'm using for many different activities each having their own ViewHolder. So I'm firstly making an abstract recycler adapter named DimRecyclerAbstractAdapter without a ViewHolder. Then for each different activity I'm making a static inner class named DimCustomAdapter which extends DimRecyclerAbstractAdapter having it's own ViewHolder. But I'm getting this error.
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.get(ArrayList.java:411)
This is the abstract adapter class -
public abstract class DimRecyclerAbstractAdapter<VHA extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VHA> {
private List<tbl_dim_1> mtbldimList1;
public DimRecyclerAbstractAdapter(List<tbl_dim_1> tblDimList1) {
this.mtbldimList1 = tblDimList1;
}
#Override
public int getItemCount() {
return mtbldimList1.size();
}
public void addItems(List<tbl_dim_1> tblDimList1) {
this.mtbldimList1 = tblDimList1;
notifyDataSetChanged();
}
#Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
mtbldimList1 = null;
super.onDetachedFromRecyclerView(recyclerView);
}
}
This is the activity in which I've implemented custom ViewHolder -
public class DetailActivity1 extends LifecycleActivity{
DimListViewModel dmvmodel;
RecyclerView rcView;
DimCustomAdapter rcAdapter;
public static final String LOG_TAG = "In DetailActivity1 ";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycler_view);
Intent receivedIntent = getIntent();
int rid_int = receivedIntent.getIntExtra("mRId",0);
Log.v(LOG_TAG,"Rid value int == " + rid_int);
rcView = (RecyclerView) findViewById(R.id.recyclerView);
rcAdapter = new DimCustomAdapter(new ArrayList<tbl_dim_1>());
rcView.setLayoutManager(new LinearLayoutManager(DetailActivity1.this));
Log.v(LOG_TAG, "Layout manager set");
rcView.setAdapter(rcAdapter);
dmvmodel = ViewModelProviders.of(this).get(DimListViewModel.class);
Log.v(LOG_TAG, "View model returned");
dmvmodel.getDimList2con1(rid_int).observe(DetailActivity1.this, new Observer<List<tbl_dim_1>>() {
#Override
public void onChanged(#Nullable List<tbl_dim_1> changedItems) {
Log.v(LOG_TAG, "onChanged called, items will be added");
rcAdapter.addItems(changedItems);
}
});
}
#Override
protected void onDestroy() {
rcAdapter = null;
rcView.setAdapter(null);
rcView.setLayoutManager(null);
rcView = null;
dmvmodel = null;
super.onDestroy();
RefWatcher refWatcher = LeakCheckApplication.getRefWatcher(this);
refWatcher.watch(this);
}
public static class DimCustomAdapter extends DimRecyclerAbstractAdapter<DimCustomAdapter.RecyclerViewHolder> {
private static List<tbl_dim_1> mtbldimCustom;
DimCustomAdapter(List<tbl_dim_1> tblDimListPassed) {
super(mtbldimCustom);
mtbldimCustom = tblDimListPassed;
}
#Override
public DimCustomAdapter.RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View vw = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_item, parent, false);
// vw.setOnClickListener(vwOnClickListener);
return new DimCustomAdapter.RecyclerViewHolder(vw);
}
#Override
public void onBindViewHolder(final RecyclerViewHolder holder, int position) {
// Log.v(LOG_TAG, "Inside onBindViewHolder - ");
if (holder.dataTextView.getText() != null) {
String LOG_TAG = "DimCustomAdapter:";
Log.d(LOG_TAG, "holder is not null, i was right");
holder.dataTextView.setText(null);
holder.dataTextView.setOnClickListener(null);
}
final tbl_dim_1 dimAtPosition = mtbldimCustom.get(position);
holder.dataTextView.setText(dimAtPosition.mCONTENT);
holder.dataTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg) {
Intent dw = new Intent(arg.getContext(), DetailActivity2.class);
dw.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
dw.putExtra("mRId", dimAtPosition.mR_ID);
arg.getContext().startActivity(dw);
}
});
}
class RecyclerViewHolder extends RecyclerView.ViewHolder {
private TextView dataTextView;
RecyclerViewHolder(View view) {
super(view);
dataTextView = (TextView) view.findViewById(R.id.data_text_view);
}
}
}
}
And this is how I'm calling this inner class from outer class within same activity -
DimCustomAdapter rcAdapter = new DimCustomAdapter(new ArrayList<tbl_dim_1>());
Its because of empty list that you are passing while creating the adapter.
DimCustomAdapter rcAdapter = new DimCustomAdapter(new ArrayList<tbl_dim_1>());
Just add a null or empty check in onBindViewHolder method before calling
final tbl_dim_1 dimAtPosition = mtbldimCustom.get(position);
Hope this will stop crashing your application.
You can try like below,
ArrayList<tbl_dim_1> list = new ArrayList<>()
rcAdapter = new DimCustomAdapter(list);
then in observe method,
dmvmodel.getDimList2con1(rid_int).observe(DetailActivity1.this, new Observer<List<tbl_dim_1>>() {
#Override
public void onChanged(#Nullable List<tbl_dim_1> changedItems) {
Log.v(LOG_TAG, "onChanged called, items will be added");
list.addAll(changedItems);
rcAdapter.notifyDataSetChanged()
}
});
This is the solution i worked out for my problem( In case anyone face the same problem ).
Modyfying Durga's answer -
Firstly i added the isEmpty() check that he mentioned in comment.
Then in the activity i changed the code to this -
a) Added this new method in DimCustomAdapter -
public void changeList(List<tbl_dim_1> addedList){
mtbldimCustom = addedList;
}
b) Called this method in observe method -
dmvmodel.getDimList2con1(rid_int).observe(DetailActivity1.this, new Observer<List<tbl_dim_1>>() {
#Override
public void onChanged(#Nullable List<tbl_dim_1> changedItems) {
Log.v(LOG_TAG, "onChanged called, items will be added");
rcAdapter.changeList(changedItems);
rcAdapter.addItems(changedItems);
}
});
I implement another activity which needs to be open when click on card but i getting Error:(56, 48) error: incompatible types: anonymous Callback JSONResponse cannot be converted to Context even if i convert to JSONResponse then there is another error. Problem is in that JSONResponse but i can't solve it.
DataAdapter.java
public class DataAdapter extends RecyclerView.Adapter<DataAdapter.ViewHolder> {
private ArrayList<AndroidVersion> android;
Context ctx;
public DataAdapter(ArrayList<AndroidVersion> android, Context ctx)
{
this.android = android;
this.ctx = ctx;
}
#Override
public DataAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_row, viewGroup, false);
return new ViewHolder(view,ctx,android);
}
#Override
public void onBindViewHolder(DataAdapter.ViewHolder viewHolder, int i) {
viewHolder.tv_name.setText(android.get(i).getName());
viewHolder.tv_version.setText(android.get(i).getVer());
viewHolder.tv_api_level.setText(android.get(i).getApi());
}
#Override
public int getItemCount() {
return android.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
private TextView tv_name,tv_version,tv_api_level;
ArrayList<AndroidVersion> android = new ArrayList<AndroidVersion>();
Context ctx;
public ViewHolder(View view, Context ctx, ArrayList<AndroidVersion> android)
{
super(view);
this.android = android;
this.ctx = ctx;
view.setOnClickListener(this);
tv_name = (TextView)view.findViewById(R.id.tv_name);
tv_version = (TextView)view.findViewById(R.id.tv_version);
tv_api_level = (TextView)view.findViewById(R.id.tv_api_level);
}
#Override
public void onClick(View v) {
int i = getAdapterPosition();
AndroidVersion android = this.android.get(i);
Intent intent = new Intent(this.ctx, ContactDetails.class);
intent.putExtra("name_id",android.getName());
intent.putExtra("version_id",android.getVer());
intent.putExtra("api_level_id",android.getApi());
((Context) this.ctx).startActivity(intent);}
}
}
JSONResponse.java
public class JSONResponse {
private AndroidVersion[] android;
public AndroidVersion[] getAndroid() {
return android;}
}
mainActivity when i write this getting error
main
First issue,
to this:
adapter = new DataAdapter(data,MainActivity.this);
is giving error because: if you put this inside a callback, you are refering to the onResponse scope, you cannot use this, because is outside scope, for that reason you have to you use MainActivity.this or getApplicationContext();