My Recyclerview is filled with a list containing links to images. But the images can change (let's say the user can draw something on them), but the link to the image itself does not change. I need to make it so that when the image changes, it is also drawn again in the recycler.
notifyDataSetChanged() does not work in this case, apparently because it reacts to changes in the sheet, and in fact there are no changes in the sheet itself, the links are the same in it. But the images are changed by links.
Maybe somehow you can push the recycler so that it is updated or draws items again?
My Activity:
public class MyDrawing extends Fragment {
private RecyclerView recyclerView;
private RecyclerViewAdapter recyclerViewAdapter;
private View root;
private TextView text;
public MyDrawing() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
root = inflater.inflate(R.layout.fragment_my_drawing, container, false);
recyclerView = root.findViewById(R.id.recyclerViewMyDrawing);
text = root.findViewById(R.id.text);
List<CacheImageModel> cacheImageModels = getCacheImageByState();
recyclerViewAdapter = new RecyclerViewAdapter(cacheImageModels, getContext());
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2));
recyclerView.setAdapter(recyclerViewAdapter);
recyclerViewAdapter.notifyDataSetChanged();
return root;
}
My Adapter:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private List<CacheImageModel> cacheImageModels;
private Context context;
private String imgUrl;
private int imageKey;
private String category;
private String nameImage;
private ProgressBar progressBarItem;
public RecyclerViewAdapter(List<CacheImageModel> cacheImageModels, Context context) {
this.cacheImageModels = cacheImageModels;
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_view_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
imgUrl = cacheImageModels.get(position).getImageCacheUrl();
nameImage = cacheImageModels.get(position).getName();
category = cacheImageModels.get(position).getCategory();
imageKey = cacheImageModels.get(position).getImageKey();
holder.progressBarItem.setVisibility(View.VISIBLE);
holder.relativeLayout.setLayoutParams(new FrameLayout.LayoutParams(MyApp.getScreenWidth(context) / 2,
MyApp.getScreenWidth(context) / 2));
Glide.with(context)
.load(imgUrl)
.listener(new RequestListener<Drawable>() {
#Override
public boolean onLoadFailed(#Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
return false;
}
#Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
holder.progressBarItem.setVisibility(View.GONE);
return false;
}
})
.into(holder.image);
holder.image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int posit = holder.getAdapterPosition();
if (posit < 0 || posit >= cacheImageModels.size()) {
Log.d("POSITION", "Number postition " + posit + " its error");
} else {
String urlImagePosition = cacheImageModels.get(posit).getImageCacheUrl();
String namePosition = cacheImageModels.get(posit).getName();
String categoryPosition = cacheImageModels.get(posit).getCategory();
int imageKeyPosition = cacheImageModels.get(posit).getImageKey();
Uri uri = ContentUris.withAppendedId(MCDataContract.CONTENT_URI, imageKeyPosition);
Intent intent = new Intent(v.getContext(),
ColoringActivity.class);
intent.putExtra("urlImagePosition", urlImagePosition);
intent.putExtra("nameImage", namePosition);
intent.putExtra("keyPosition", imageKeyPosition);
intent.putExtra("categoryPosition", categoryPosition);
intent.setData(uri);
v.getContext().startActivity(intent);
}
}
});
}
#Override
public long getItemId(int position) {
return super.getItemId(position);
}
#Override
public int getItemCount() {
return cacheImageModels.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private ImageView image;
private ProgressBar progressBarItem;
private RelativeLayout relativeLayout;
private CardView cardView;
public ViewHolder(#NonNull View itemView) {
super(itemView);
image = itemView.findViewById(R.id.imageView);
progressBarItem = itemView.findViewById(R.id.progressBarItem);
relativeLayout = itemView.findViewById(R.id.parentItem);
cardView = itemView.findViewById(R.id.cardView);
}
}
}
notifyDataSetChanged() is most likely working as planned. You can set a breakpoint in your view holder binding code to check this.
It is more likely that Glide is pulling the cached versions of the images. You will need a way to get Glide to ignore what's in cache and reload from the URL.
This post addresses the same issue and may be of help to you.
Related
I am building a simple blog feature and using picasso to load images into recyclerview in android studio but the images don't load, Please can someone help me understand why. See the related code section below:
public class BlogRecyclerViewAdapter extends RecyclerView.Adapter {
private Context context;
private List blogList;
// Constructor
public BlogRecyclerViewAdapter(Context context, List<Blog> blogList) {
this.context = context;
this.blogList = blogList;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.post_row, parent, false);
return new ViewHolder(view, context);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
// Now bind the views and the data
Blog blog = blogList.get(position);
String imageUrl = null;
holder.title.setText(blog.getTitle());
holder.desc.setText(blog.getDesc());
DateFormat dateFormat = DateFormat.getDateInstance();
String formattedDate = dateFormat.format(new Date(Long.valueOf(blog.getTimeStamp())).getTime());
holder.timeStamp.setText(formattedDate);
imageUrl = blog.getImage();
//TODO: Use Picasso library to load image
Picasso.get().load(imageUrl).into(holder.image);
}
#Override
public int getItemCount() {
return blogList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView title;
public TextView desc;
public TextView timeStamp;
public ImageView image;
String userId;
public ViewHolder(#NonNull View view, Context ctx) {
super(view);
context = ctx;
title = (TextView) view.findViewById(R.id.postTitleList);
desc = (TextView) view.findViewById(R.id.postTextList);
image = (ImageView) view.findViewById(R.id.postImageList);
timeStamp = (TextView) view.findViewById(R.id.timeStampList);
userId = null;
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// We can go to the next activity
}
});
}
}
}
Im working on a news reader app that uses fragments. I get my data from the newsapi. So far I have managed to pull the data from the api and display it in a recyclerview but when I click on an item, nothing happens!
public class HomeFragment extends Fragment implements RecyclerViewAdapter.OnItemClickListener {
public static final String API_KEY= "c03ceb6a99b14050875f56xxxxxxxx";
private RecyclerView recyclerView;
private List<Article> articles = new ArrayList<>();
private RecyclerViewAdapter recyclerViewAdapter;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home,container,false);
recyclerView = rootView.findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerViewAdapter = new RecyclerViewAdapter(articles,getActivity());
recyclerViewAdapter.setOnItemClickListener(HomeFragment.this);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setNestedScrollingEnabled(false);
LoadJsonData();
return rootView;
}
public void LoadJsonData(){
ApiInterface apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
String country = Utils.getCountry();
Call <News> call;
call = apiInterface.getNews(country,API_KEY);
call.enqueue(new Callback<News>() {
#Override
public void onResponse(Call<News> call, Response<News> response) {
if (response.isSuccessful() && response.body().getArticle() != null){
if (!articles.isEmpty()){
articles.clear();
}
articles = response.body().getArticle();
recyclerViewAdapter = new RecyclerViewAdapter(articles,getActivity());
recyclerView.setAdapter(recyclerViewAdapter);
recyclerViewAdapter.setOnItemClickListener(HomeFragment.this);
recyclerViewAdapter.notifyDataSetChanged();
} else {
Toast.makeText(getActivity(),"No result",Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<News> call, Throwable t) {
}
});
}
#Override
public void onItemClick(int position) {
articles.get(position);
}
}
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private List<Article> articles;
private Context context;
private OnItemClickListener onItemClickListener;
public interface OnItemClickListener {
void onItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public RecyclerViewAdapter(List<Article> articles, Context context) {
this.articles = articles;
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(context).inflate((R.layout.card_view_layout), viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int i) {
final ViewHolder holder = viewHolder;
Article model = articles.get(i);
RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(Utils.getRandomDrawbleColor());
requestOptions.error(Utils.getRandomDrawbleColor());
requestOptions.diskCacheStrategy(DiskCacheStrategy.ALL);
requestOptions.centerCrop();
Glide.with(context)
.load(model.getUrlToImage())
.apply(requestOptions)
.listener(new RequestListener<Drawable>() {
#Override
public boolean onLoadFailed(#Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
holder.progressBar.setVisibility(View.GONE);
return false;
}
#Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
holder.progressBar.setVisibility(View.GONE);
return false;
}
})
.transition(DrawableTransitionOptions.withCrossFade())
.into(holder.imageView);
holder.title.setText(model.getTitle());
holder.desc.setText(model.getDescription());
holder.source.setText(model.getSource().getName());
holder.time.setText(" \u2022 " + Utils.DateToTimeFormat(model.getPublishedAt()));
}
#Override
public int getItemCount() {
return articles.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView title, desc, source, time;
ImageView imageView;
ProgressBar progressBar;
public ViewHolder(#NonNull View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
desc = itemView.findViewById(R.id.description);
source = itemView.findViewById(R.id.source);
time = itemView.findViewById(R.id.time);
imageView = itemView.findViewById(R.id.headline_image);
progressBar = itemView.findViewById(R.id.progress_load);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (onItemClickListener != null){
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION){
onItemClickListener.onItemClick(position);
}
}
}
});
}
}
}
It seems all you are doing inside your onClick is getting the item position. It is now up to you to do something with that position.
So the question comes down to, what do you want to do?
Launch a details activity/fragment to display more info? That is a typical pattern for mobile.
Intent i = new Intent(context,DetailActivity.class);
i.putExtra(Your Data);
startActivity(i);
I'm trying to populate a RecyclerView using data stored in a ArrayList. When the RecyclerView loads each piece of data is repeted 4x in each row.
I've tried a whole variety of solutions I've found, but none seem to resolve the issue.
After some debugging the data in 'mData', appears to be correct, so that would lead me to believe that this issue is 'onBindViewHolder'?
Adapter
public class EventsRecyclerViewAdapter extends RecyclerView.Adapter<EventsRecyclerViewAdapter.ViewHolder> {
private List<String> mData;
private LayoutInflater mInflater;
private ItemClickListener mClickListener;
// data is passed into the constructor
public EventsRecyclerViewAdapter(List<String> data) {
this.mInflater = LayoutInflater.from(MainActivity.mainActivity);
this.mData = data;
}
// inflates the row layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recyclerview_row, parent, false);
return new ViewHolder(view);
}
// binds the data to the TextView in each row
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.keyID.setText(mData.get(position));
holder.lockID.setText(mData.get(position));
holder.eventTime.setText(mData.get(position));
holder.eventType.setText(mData.get(position));
}
// total number of rows
#Override
public int getItemCount() {
return mData.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView keyID;
TextView lockID;
TextView eventTime;
TextView eventType;
ViewHolder(View itemView) {
super(itemView);
keyID = itemView.findViewById(R.id.keyIDTV);
lockID = itemView.findViewById(R.id.lockIDTV);
eventTime = itemView.findViewById(R.id.eventDateTV);
eventType = itemView.findViewById(R.id.eventTypeTV);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
Fragment
public class KeyEvents extends Fragment {
public static KeyInfo newInstance() {
KeyInfo fragment = new KeyInfo();
return fragment;
}
EventsRecyclerViewAdapter adapter;
ArrayList<String> eventsList;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EventsOperationHandler ev = new EventsOperationHandler();
eventsList = new ArrayList<>();
for (int i=0; i<ev.getEvents().size(); i++) {
eventsList.add(ev.getEvents().get(i).get(0));
eventsList.add(ev.getEvents().get(i).get(1));
eventsList.add(ev.getEvents().get(i).get(2));
eventsList.add(ev.getEvents().get(i).get(3));
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_event_info, container, false);
RecyclerView recyclerView = view.findViewById(R.id.rvEvents);
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.mainActivity));
adapter = new EventsRecyclerViewAdapter(eventsList);
recyclerView.setAdapter(adapter);
return view;
}
}
In your 'onBindViewHolder' you are setting same data in every textView of yours
// binds the data to the TextView in each row
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.keyID.setText(mData.get(position));
holder.lockID.setText(mData.get(position));
holder.eventTime.setText(mData.get(position));
holder.eventType.setText(mData.get(position));
}
Here you are setting mData.get(position) to every textView in the holder
A solution would be creating a Pojo class for your recyclerView
Create Pojo Event class
class Event{
public String keyID;
public String lockID;
public String eventTime;
public String eventType;
}
Create a list of 'Event' in your fragment
public class KeyEvents extends Fragment {
public static KeyInfo newInstance() {
KeyInfo fragment = new KeyInfo();
return fragment;
}
EventsRecyclerViewAdapter adapter;
ArrayList<Event> eventsList;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EventsOperationHandler ev = new EventsOperationHandler();
eventsList = new ArrayList<>();
for (int i=0; i<ev.getEvents().size(); i++) {
Event event = new Event();
event.keyID = ev.getEvents().get(i).get(0);
event.lockID = ev.getEvents().get(i).get(1);
event.eventTime = ev.getEvents().get(i).get(2);
event.eventType = ev.getEvents().get(i).get(3);
eventsList.add(event);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_event_info, container, false);
RecyclerView recyclerView = view.findViewById(R.id.rvEvents);
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.mainActivity));
adapter = new EventsRecyclerViewAdapter(eventsList);
recyclerView.setAdapter(adapter);
return view;
}
}
Modify your recyclerView to handle to 'Event' class
public class EventsRecyclerViewAdapter extends RecyclerView.Adapter<EventsRecyclerViewAdapter.ViewHolder> {
private List<Event> mData;
private LayoutInflater mInflater;
private ItemClickListener mClickListener;
// data is passed into the constructor
public EventsRecyclerViewAdapter(List<Event> data) {
this.mInflater = LayoutInflater.from(MainActivity.mainActivity);
this.mData = data;
}
// inflates the row layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recyclerview_row, parent, false);
return new ViewHolder(view);
}
// binds the data to the TextView in each row
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Event event = mData.get(position);
holder.keyID.setText(event.keyID);
holder.lockID.setText(event.lockId);
holder.eventTime.setText(event.eventTime);
holder.eventType.setText(event.eventType);
}
// total number of rows
#Override
public int getItemCount() {
return mData.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView keyID;
TextView lockID;
TextView eventTime;
TextView eventType;
ViewHolder(View itemView) {
super(itemView);
keyID = itemView.findViewById(R.id.keyIDTV);
lockID = itemView.findViewById(R.id.lockIDTV);
eventTime = itemView.findViewById(R.id.eventDateTV);
eventType = itemView.findViewById(R.id.eventTypeTV);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
That's it, this should work perfectly.
I am having problems updating my RecyclerView with new data. If I press a confirmation button on a CardView in the first tab, the card should get added to the second tab but it won't update it there until I rotate the screen. I get the data for the card from reading a text file. Please advise me how to call the notifyDataSetChange method after I have added the new data to my text file. I have tried everything and all I get is NullPointerExceptions. The RecyclerViews are in fragments and I use FragementStatePagerAdapter.
I'll put some of my classes here. Ask if you need more information.
RecyclerViewAdapter.java
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
private List<String> mListTitle;
private List<String> mListDesc;
private List<String> mListPoints;
private List<String> mListDates;
private String fragment_tag;
public RecyclerViewAdapter() {
}
public RecyclerViewAdapter(List<List<String>> super_list, String tag) {
this.mListTitle = super_list.get(0);
this.mListDesc = super_list.get(1);
this.mListPoints = super_list.get(2);
this.mListDates = super_list.get(3);
fragment_tag = tag;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new RecyclerViewHolder(inflater, parent, fragment_tag);
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
holder.mTitleText.setText(mListTitle.get(position));
holder.mDescText.setText(mListDesc.get(position));
holder.mPointsText.setText(mListPoints.get(position));
if (fragment_tag.equals("completed")) {
holder.mDateText.setText(mListDates.get(position));
}
}
#Override
public int getItemCount() {
return mListTitle.size();
}
}
class RecyclerViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerView;
RecyclerViewAdapter mAdapter;
public TextView mTitleText, mDescText, mDateText, mPointsText, popupTitle;
public Button mConfButton, popCancelBtn, popAcceptBtn;
public RecyclerViewHolder(View itemView) {
super(itemView);
}
public RecyclerViewHolder(final LayoutInflater inflater, final ViewGroup container, String tag) {
// Inflating the card layout depending on the tag parameter.
super(inflater.inflate
((tag.equals("challenges")) ? R.layout.card_view_chall : R.layout.card_view_comp, container,
false));
mTitleText = itemView.findViewById(R.id.title_holder);
mDescText = itemView.findViewById(R.id.desc_holder);
mPointsText = itemView.findViewById(R.id.points_holder);
mDateText = itemView.findViewById(R.id.date_holder);
if (tag.equals("challenges")) {
mConfButton = itemView.findViewById(R.id.card_conf_button);
mConfButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Setting the layout inflater for popup window.
LayoutInflater pInflater = (LayoutInflater) itemView.getContext().getSystemService(LAYOUT_INFLATER_SERVICE);
ViewGroup container1 = (ViewGroup) pInflater.inflate(R.layout.confirmation_popup, null);
final PopupWindow popupWindow = new PopupWindow(container1, 700, 600, true);
popupTitle = container1.findViewById(R.id.popuptext);
popAcceptBtn = container1.findViewById(R.id.accept_button);
popCancelBtn = container1.findViewById(R.id.cancel_button);
popupTitle.setText(mTitleText.getText().toString());
// Dismisses the popup window
popCancelBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
popupWindow.dismiss();
}
});
// Click listener for dialog accept button.
popAcceptBtn.setOnClickListener(new View.OnClickListener() {
String date;
#Override
public void onClick(View view) {
List<String> list = new ArrayList<>();
list.add(mTitleText.getText().toString());
list.add(mDescText.getText().toString());
list.add(mPointsText.getText().toString());
list.add(date = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date()));
// Saving data from current card into the completed challenges list.
TempDataReader reader = new TempDataReader(itemView.getContext());
new TempDataReader(itemView.getContext()).saveFile(list);
// I want to notify the dataset change here if possible!
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(itemView, Gravity.CENTER, 25, 100);
}
});
}
}
}
SectionsPagerAdapter.java
public class SectionsPagerAdapter extends FragmentStatePagerAdapter{
private ViewPager viewPager;
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public void addFragment(Fragment fragment, String title){
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
}
CompletedFragment.java
public class CompletedFragment extends Fragment {
RecyclerView recyclerView;
RecyclerViewAdapter adapter;
public Fragment newInstance() {
return new CompletedFragment();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.completed_fragment, container, false);
recyclerView = view.findViewById(R.id.completed_frag);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
TempDataReader reader = new TempDataReader(getActivity());
List<List<String>> super_list = reader.readCompFile();
if(super_list == null || super_list.size() < 1){
return null;
} else{
adapter = new RecyclerViewAdapter(super_list,"completed");
recyclerView.setAdapter(adapter);
return view;
}
}
}
EDIT:
Added the code for the second fragment, which is the one that should be updated after the onClick at RecyclerViewHolder-class.
You have to add a function in your adapter for adding data:
public void addData(String title, String desc, String point, String date) {
this.mListTitle.add(title);
this.mListDesc.add(desc);
this.mListPoints.add(point);
this.mListDates.add(date);
notifyDataSetChanged();
}
If you want to enable animations call notifyItemInserted() instead of notifyDataSetChanged();
It is important that you add a String to every list because in your onBindViewHolder() you get the item to display from every list with list.get(position). Otherwise you'll get a IndexOutOfBoundsException.
You can create an interface and use as a callback. Send it as a parameter of the RecyclerViewAdapter and then to your RecyclerViewHolder. When the item should be added you call the callback that will get you back to your fragment. There you can read the file again and call notifyDataSetChanged.
I know i explain pretty bad so i will try to change your code so that it does what i said:
this will be your RecyclerViewAdapter:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
private List<String> mListTitle;
private List<String> mListDesc;
private List<String> mListPoints;
private List<String> mListDates;
private String fragment_tag;
private Runnable callback;
public RecyclerViewAdapter() {
}
public RecyclerViewAdapter(List<List<String>> super_list, String tag, Runnable callBack) {
//add the callback here(Runnable) and save it into a local variable
this.callback=callback;
this.mListTitle = super_list.get(0);
this.mListDesc = super_list.get(1);
this.mListPoints = super_list.get(2);
this.mListDates = super_list.get(3);
fragment_tag = tag;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new RecyclerViewHolder(inflater, parent, fragment_tag, callback);
//send the callback to your viewHolder
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
holder.mTitleText.setText(mListTitle.get(position));
holder.mDescText.setText(mListDesc.get(position));
holder.mPointsText.setText(mListPoints.get(position));
if (fragment_tag.equals("completed")) {
holder.mDateText.setText(mListDates.get(position));
}
}
#Override
public int getItemCount() {
return mListTitle.size();
}
}
class RecyclerViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerView;
RecyclerViewAdapter mAdapter;
public TextView mTitleText, mDescText, mDateText, mPointsText, popupTitle;
public Button mConfButton, popCancelBtn, popAcceptBtn;
public RecyclerViewHolder(View itemView) {
super(itemView);
}
public RecyclerViewHolder(final LayoutInflater inflater, final ViewGroup container, String tag, Runnable callback) {
//ADD the callback to the parameters list here
// Inflating the card layout depending on the tag parameter.
super(inflater.inflate
((tag.equals("challenges")) ? R.layout.card_view_chall : R.layout.card_view_comp, container,
false));
mTitleText = itemView.findViewById(R.id.title_holder);
mDescText = itemView.findViewById(R.id.desc_holder);
mPointsText = itemView.findViewById(R.id.points_holder);
mDateText = itemView.findViewById(R.id.date_holder);
if (tag.equals("challenges")) {
mConfButton = itemView.findViewById(R.id.card_conf_button);
mConfButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Setting the layout inflater for popup window.
LayoutInflater pInflater = (LayoutInflater) itemView.getContext().getSystemService(LAYOUT_INFLATER_SERVICE);
ViewGroup container1 = (ViewGroup) pInflater.inflate(R.layout.confirmation_popup, null);
final PopupWindow popupWindow = new PopupWindow(container1, 700, 600, true);
popupTitle = container1.findViewById(R.id.popuptext);
popAcceptBtn = container1.findViewById(R.id.accept_button);
popCancelBtn = container1.findViewById(R.id.cancel_button);
popupTitle.setText(mTitleText.getText().toString());
// Dismisses the popup window
popCancelBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
popupWindow.dismiss();
}
});
// Click listener for dialog accept button.
popAcceptBtn.setOnClickListener(new View.OnClickListener() {
String date;
#Override
public void onClick(View view) {
List<String> list = new ArrayList<>();
list.add(mTitleText.getText().toString());
list.add(mDescText.getText().toString());
list.add(mPointsText.getText().toString());
list.add(date = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date()));
// Saving data from current card into the completed challenges list.
TempDataReader reader = new TempDataReader(itemView.getContext());
new TempDataReader(itemView.getContext()).saveFile(list);
// I want to notify the dataset change here if possible!
//call the callback
callback.run();
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(itemView, Gravity.CENTER, 25, 100);
}
});
}
}
}
And this will be your fragment:
public class CompletedFragment extends Fragment {
RecyclerView recyclerView;
RecyclerViewAdapter adapter;
public Fragment newInstance() {
return new CompletedFragment();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.completed_fragment, container, false);
recyclerView = view.findViewById(R.id.completed_frag);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
TempDataReader reader = new TempDataReader(getActivity());
List<List<String>> super_list = reader.readCompFile();
if(super_list == null || super_list.size() < 1){
return null;
} else{
adapter = new RecyclerViewAdapter(super_list,"completed", new Runnable() {
#Override
public void run() {
//here read the list again and call notifyDataSetChanged on your recycler
}
});
);
recyclerView.setAdapter(adapter);
return view;
}
}
}
Hope it helps and it works for you. If i did anything wrong, let me know, i can't run the code right now so...
edited, i forgot to add code in the callback
I have few images in the json API, and I managed to fetch those images using volley Library. I used recyclerview with an image adapter to display image views vertically in two columns, but I want to make one image big and display it as the first image that user can click on. Also that image will be changed each interval of time. Basically, the API will do all the backend task like setting the time and telling which image to be displayed on the top of the recyclerview if not all images must have the same size and be shown in 2 columns vertically.
I have square layout class for recyclerview. I just want to know how I can do this. Even the concept will be fine.
you will have to create two view one for small item other for the header item and in onBindViewHolder have to bind those accordingly the following code is an example of a news article app and should help.
public class AdapterNewsArticlesListWithHeader extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<NewsArticles> items = new ArrayList<>();
private Context ctx;
private NewsArticles header;
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
private OnItemClickListener mOnItemClickListener;
public interface OnItemClickListener {
void onItemClick(View view, NewsArticles obj, int position);
}
public void setOnItemClickListener(final OnItemClickListener mItemClickListener) {
this.mOnItemClickListener = mItemClickListener;
}
// Provide a suitable constructor (depends on the kind of dataset)
public AdapterNewsArticlesListWithHeader(Context context, NewsArticles header, List<NewsArticles> items) {
this.items = items;
this.header = header;
ctx = context;
}
public class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView title;
public TextView short_content;
public TextView date;
public ImageView image;
public LinearLayout lyt_parent;
public ViewHolder(View v) {
super(v);
title = (TextView) v.findViewById(R.id.title);
short_content = (TextView) v.findViewById(R.id.short_content);
date = (TextView) v.findViewById(R.id.date);
image = (ImageView) v.findViewById(R.id.image);
lyt_parent = (LinearLayout) v.findViewById(R.id.lyt_parent);
}
}
class ViewHolderHeader extends RecyclerView.ViewHolder {
public TextView title;
public TextView date;
public ImageView image;
public LinearLayout lyt_parent;
public ViewHolderHeader(View v) {
super(v);
title = (TextView) v.findViewById(R.id.title);
date = (TextView) v.findViewById(R.id.date);
image = (ImageView) v.findViewById(R.id.image);
lyt_parent = (LinearLayout) v.findViewById(R.id.lyt_parent);
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_header, parent, false);
return new ViewHolderHeader(v);
} else if (viewType == TYPE_ITEM) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_news, parent, false);
return new ViewHolder(v);
}
return null;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof ViewHolderHeader) {
ViewHolderHeader vHeader = (ViewHolderHeader) holder;
vHeader.title.setText(header.getTitle());
vHeader.date.setText(header.getDate());
Picasso.with(ctx).load(header.getImage()).into(vHeader.image);
vHeader.lyt_parent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//TODO: do your thing
}
});
} else if (holder instanceof ViewHolder) {
final NewsArticles c = items.get(position);
ViewHolder vItem = (ViewHolder) holder;
vItem.title.setText(c.getTitle());
vItem.short_content.setText(c.getShort_content());
vItem.date.setText(c.getDate());
Picasso.with(ctx).load(c.getImage()).into(vItem.image);
vItem.lyt_parent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//TODO: do your thing
}
});
}
}
// need to override this method
#Override
public int getItemViewType(int position) {
if (isPositionHeader(position)) {
return TYPE_HEADER;
}
return TYPE_ITEM;
}
private boolean isPositionHeader(int position) {
return position == 0;
}
public NewsArticles getItem(int position) {
return items.get(position);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return items.size();
}
}