I cannot sort the RecyclerView in descending order by date. There are headers and items. I can only sort items, but no headers.
I tried to sort the SQL Database in descending order (" DESC"), but not successful.
private static final String EVENTS_CREATE_TABLE =
"create table "
+ EVENTS.TABLE + " ("
+ EVENTS.EVENTS_ID + " integer primary key, "
+ EVENTS.COL_TITLE + " text, "
+ EVENTS.COL_DATE + " long" + ");";
``
public List<EventModel> getAllEvents() {
List<EventModel> eventModelList = new ArrayList<>();
openToRead();
String orderBy = DBHelper.EVENTS.COL_DATE + " DESC";
Cursor cursor = database.query(DBHelper.EVENTS.TABLE,
null, null, null, null, null, orderBy);
if (cursor.moveToFirst()) {
do {
String title = cursor.getString(cursor.getColumnIndex(DBHelper.EVENTS.COL_TITLE));
long date = cursor.getLong(cursor.getColumnIndex(DBHelper.EVENTS.COL_DATE));
EventModel eventModel = new EventModel(title, date);
eventModelList.add(eventModel);
} while (cursor.moveToNext());
}
cursor.close();
return eventModelList;
}
There is my fragment:
private void getList() {
List<ListEvent> items = new ArrayList<>();
Map<Long, List<EventModel>> events = toMap(loadEvents());
for (long date : events.keySet()) {
HeaderEvent header = new HeaderEvent(date);
items.add(header);
for (EventModel eventModel : events.get(date)) {
EventItem item = new EventItem(itemModel);
items.add(item);
}
}
adapterEvent = new EventRVAdapter(getContext(), items);
mRecyclerView.setAdapter(adapterEvent);
}
private List<EventModel> loadEvents() {
List<EventModel> events = new ArrayList<>(mDBAdapter.getAllEvents());
return events;
}
private Map<Long, List<EventModel>> toMap(List<EventModel> events) {
Map<Long, List<EventModel>> map = new TreeMap<>();
for (EventModel eventModel : events) {
List<EventModel> value = map.get(eventModel.getDate());
if (value == null) {
value = new ArrayList<>();
map.put(eventModel.getDate(), value);
}
value.add(eventModel);
}
return map;
}
This is ListEvent class:
public abstract class ListEvent {
public static final int TYPE_HEADER = 0;
public static final int TYPE_ITEM = 1;
abstract public int getType();
}
This is EventItem.class
public class EventItem extends ListEvent{
private EventModel eventModel;
public EventItem(EventModel eventModel) {
this.eventModel = eventModel;
}
public EventModel getEventModel() {
return eventModel;
}
#Override
public int getType() {
return TYPE_ITEM;
}
}
This is HeaderEvent class:
public class HeaderEvent extends ListEvent {
private long date;
public HeaderEvent(long date) {
this.date = date;
}
public long getDate() {
return date;
}
#Override
public int getType() {
return TYPE_HEADER;
}
}
This is my Model - EventModel class:
public class EventModel {
private String title;
private long date;
public EventModel(String title, long date) {
this.title = title;
this.date = date;
}
public String getTitle(){
return title;
}
public long getDate(){
return date;
}
}
And my RecyclerView adapter:
public class EventRVAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<ListEvent> items;
public EventRVAdapter(List<ListEvent> items) {
this.items = items;
}
public class ItemViewHolder extends RecyclerView.ViewHolder {
private TextView tvName, tvDate;
public ItemViewHolder(#NonNull View itemView) {
super(itemView);
tvName = itemView.findViewById(R.id.tvTitle);
tvDate = itemView.findViewById(R.id.tvDate);
}
}
public class HeaderViewHolder extends RecyclerView.ViewHolder {
private TextView tvHeaderDate;
public HeaderViewHolder(#NonNull View itemView) {
super(itemView);
tvHeaderDate = itemView.findViewById(R.id.tvHeader);
}
}
#Override
public int getItemCount() {
return items.size();
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case ListEvent.TYPE_HEADER: {
View itemView = inflater.inflate(R.layout.row_header, parent, false);
return new HeaderViewHolder(itemView);
}
case ListEvent.TYPE_ITEM: {
View itemView = inflater.inflate(R.layout.row_item, parent, false);
return new ItemViewHolder(itemView);
}
default:
throw new IllegalStateException("unsupported item type");
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
int viewType = getItemViewType(position);
switch (viewType) {
case ListEvent.TYPE_HEADER: {
HeaderEvent header = (HeaderEvent) items.get(position);
HeaderViewHolder headerHolder = (HeaderViewHolder) holder;
headerHolder.tvHeaderDate.setText(Utils.getDayAndTime(header.getDate()));
break;
}
case ListEvent.TYPE_ITEM: {
EventItem event = (EventItem) items.get(position);
ItemViewHolder itemHolder = (ItemViewHolder) holder;
itemHolder.tvName.setText(event.getEventModel().getTitle());
itemHolder.tvDate.setText(Utils.getDateWithoutTime(event.getEventModel().getDate()));
break;
}
default:
throw new IllegalStateException("unsupported item type");
}
}
#Override
public int getItemViewType(int position) {
return items.get(position).getType();
}
}
Could you help me to find solution or give advice?
keySet() method documentation claims:
The set's iterator returns the keys in ascending order.
And this is just the behaviour you have.
There is no need to use Map to prepare list of items with headers. It's better to just iterate the sorted list of events and store last date to compare to at the next step. Here is a code sample:
List<EventModel> events = loadEvents();
List<ListEvent> items = new ArrayList<>();
long date = -1L;
for (EventModel event : events) {
if (event.getDate() != date) {
date = event.getDate();
items.add(new HeaderEvent(date));
}
items.add(new EventItem(event));
}
Related
I am a newbie in recyclerview. I have created my generic adapter for different properties by following the #SebastienRieu's answer, i.e. This link. The problem is that I want to instantiate the adapter and set it to my recyclerview. How Do I do that?
Here, 2nd parameter is context. What should replace the 1st paramenter with?
GenericModelAdapter adapter= new GenericModelAdapter(??, this)
recyclerView.setAdapter(adapter);
Any help is appreciated.
My PostModelClass:
public class PostsModelClass {
int userId;
int id;
String title;
#SerializedName("body")
String textBody;
public int getUserId() {
return userId;
}
public int getId() {
return id;
}
public String getTitle() {
return title;
}
public String getTextBody() {
return textBody;
}
}
Similarly, here's my CommentsModelclass:
public class CommentsModelClass {
String postId;
String id;
String name;
String email;
#SerializedName("body")
String textBody;
public String getPostId() {
return postId;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public String getTextBody() {
return textBody;
}
And here's my adapter:
public class GenericModelAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mContext;
private static final int TYPE_POSTS = 10;
private static final int TYPE_COMMENTS = 11;
private static final int TYPE_PHOTOS = 12;
private static final int TYPE_USERS = 13;
private List<GenericViewModel> mItems;
public GenericModelAdapter(List<GenericViewModel> items, Context context) {
this.mItems = items;
this.mContext = context;
}
#Override
public int getItemViewType(int position) {
GenericViewModel genericItems = mItems.get(position);
if (genericItems.isPostsModel()) {
return TYPE_POSTS;
} else if (genericItems.isCommentsModel()) {
return TYPE_COMMENTS;
} else if (genericItems.isPhotosModel()) {
return TYPE_PHOTOS;
} else {
return TYPE_USERS;
}
}
public static class PostViewHolder extends RecyclerView.ViewHolder {
TextView textViewResult;
PostViewHolder(#NonNull View itemView) {
super(itemView);
textViewResult = itemView.findViewById(R.id.textViewResult);
}
}
public static class CommentsViewHolder extends RecyclerView.ViewHolder {
TextView textViewResult;
CommentsViewHolder(#NonNull View itemView) {
super(itemView);
textViewResult = itemView.findViewById(R.id.textViewResult);
}
}
public static class PhotosViewHolder extends RecyclerView.ViewHolder {
TextView textViewResult;
PhotosViewHolder(#NonNull View itemView) {
super(itemView);
textViewResult = itemView.findViewById(R.id.textViewResult);
}
}
public static class UsersViewHolder extends RecyclerView.ViewHolder {
TextView textViewResult;
UsersViewHolder(#NonNull View itemView) {
super(itemView);
textViewResult = itemView.findViewById(R.id.textViewResult);
}
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mContext);
if (viewType == TYPE_POSTS) {
View rootView = inflater.inflate(R.layout.single_item, parent, false);
return new PostViewHolder(rootView);
} else if (viewType == TYPE_COMMENTS) {
View rootView = inflater.inflate(R.layout.single_item, parent, false);
return new CommentsViewHolder(rootView);
} else if (viewType == TYPE_PHOTOS) {
View rootView = inflater.inflate(R.layout.single_item, parent, false);
return new PhotosViewHolder(rootView);
} else {
View rootView = inflater.inflate(R.layout.single_item, parent, false);
return new UsersViewHolder(rootView);
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
GenericViewModel genericViewModel = mItems.get(position);
if (genericViewModel.isPostsModel()) {
onBindPost(holder, genericViewModel.getPostsModelClass());
} else if (genericViewModel.isCommentsModel()) {
//onBindComments(holder, genericViewModel.getCommentsModelClass());
} else if (genericViewModel.isPhotosModel()) {
//onBindPhotos(holder, genericViewModel.getPhotosModelClass());
} else if (genericViewModel.isUsersModel()) {
//onBindUsers(holder, genericViewModel.getUsersModelClass());
}
}
private void onBindPost(RecyclerView.ViewHolder holder, PostsModelClass postsModelClass) {
String content = "User ID: " + postsModelClass.getUserId() +
"\nID: " + postsModelClass.getId() +
"\nTitle: " + postsModelClass.getTitle() +
"\nBody: " + postsModelClass.getTextBody();
((PostViewHolder) holder).textViewResult.setText(content);
}
#Override
public int getItemCount() {
return mItems.size();
}
}
And lastly, My GenericViewModel:
public class GenericViewModel {
private PostsModelClass mPostsModelClass;
private CommentsModelClass mCommentsModelClass;
private PhotosModelClass mPhotosModelClass;
private UsersModelClass mUsersModelClass;
private GenericViewModel(PostsModelClass postsModelClass, CommentsModelClass commentsModelClass, PhotosModelClass photosModelClass, UsersModelClass usersModelClass) {
this.mPostsModelClass = postsModelClass;
this.mCommentsModelClass = commentsModelClass;
this.mPhotosModelClass = photosModelClass;
this.mUsersModelClass = usersModelClass;
}
public boolean isPostsModel() {
return mPostsModelClass != null;
}
public boolean isCommentsModel() {
return mCommentsModelClass != null;
}
public boolean isPhotosModel() {
return mPhotosModelClass != null;
}
public boolean isUsersModel() {
return mUsersModelClass != null;
}
public static GenericViewModel getPostsInstance(PostsModelClass modelClass) {
return new GenericViewModel(modelClass, null, null, null);
}
public static GenericViewModel getCommentsInstance(CommentsModelClass modelClass) {
return new GenericViewModel(null, modelClass, null, null);
}
public static GenericViewModel getPhotosInstance(PhotosModelClass modelClass) {
return new GenericViewModel(null, null, modelClass, null);
}
public static GenericViewModel getUsersInstance(UsersModelClass modelClass) {
return new GenericViewModel(null, null, null, modelClass);
}
public PostsModelClass getPostsModelClass() {
return mPostsModelClass;
}
public CommentsModelClass getCommentsModelClass() {
return mCommentsModelClass;
}
public PhotosModelClass getPhotosModelClass() {
return mPhotosModelClass;
}
public UsersModelClass getUsersModelClass() {
return mUsersModelClass;
}
}
Yes, I haven't shared the model classes for Posts and Users. They are similar to these model classes and I'd implement them later.
Here's the error I'm facing:
Based on the reference you gave in the question, you need a model that contains all your different properties like EventViewModel in the link and populate the list based on the viewType.
ArrayList<EventViewModel> eventList = "YOUR LIST"
GenericModelAdapter adapter= new GenericModelAdapter(eventList, this)
It must be ArrayList of different collected properties:
GenericModelAdapter adapter= new GenericModelAdapter(ArrayList<YourModel> eventList, this)
Your model:
public class YourModel() {
private Property1 mProperty1;
private Property2 mProperty2;
private YourModel(Property1 property1, Property2 property2) {
this.mProperty1 = property1;
this.mProperty2 = property2;
}
public boolean isProperty1() {
return mProperty1 != null
}
public boolean isProperty2() {
return mProperty2 != null
}
public static YourModel getProperty1Instance(Property1 property1) {
return new YourModel(property1, null);
}
public static EventViewModel getProperty2Instance(Property1 property2) {
return new YourModel(null, property2);
}
public Property1 getProperty1() {
return mProperty1;
}
public Property2 getProperty2() {
return mProperty2;
}
}
I would like to update panel wise items in inner adapter item android recyclerview. When we pass the data dynamically.Data displaying is working fine. When we go to update the inner adapter item, it's not getting updated. But last item was getting update fine.
Activity.
public class PannelCreation extends AppCompatActivity {
RecyclerView userPanelRecycler;
List<String> roomPanels = new ArrayList<>();
List<JSONObject> roomItemObject = new ArrayList<JSONObject>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pannel_creation);
userPanelRecycler = findViewById(R.id.user_panel_recycler);
for(int i=0; i<=5;i++){
roomPanels.add("Panels "+i)
}
PanelAdapter panelAdapter = new PanelAdapter(getApplicationContext(),roomPanels);
userPanelRecycler.setLayoutManager(new LinearLayoutManager(this));
userPanelRecycler.setHasFixedSize(true);
userPanelRecycler.setAdapter(panelAdapter);
}
}
// OuterAdapter
class PanelAdapter extends RecyclerView.Adapter<PanelAdapter.ViewHolder>{
Context context;
List<String> roomPanelList;
RecyclerView.RecycledViewPool recycledViewPool;
List<ItemData> itemDataList = new ArrayList<>();
public PanelAdapter(Context context, List<String> roomPanels) {
this.context = context;
this.roomPanelList = roomPanels;
recycledViewPool = new RecyclerView.RecycledViewPool();
}
#NonNull
#Override
public PanelAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.panel_wise_layout,parent,false);
ViewHolder viewHolder = new ViewHolder(view);
viewHolder.itemsRecycler.setRecycledViewPool(recycledViewPool);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull PanelAdapter.ViewHolder holder, int position) {
holder.userPanelName.setText(roomPanelList.get(position));
String cur_panelName = roomPanelList.get(position);
itemsAdapter = new ItemsAdapter(context);
holder.itemsRecycler.setLayoutManager(new GridLayoutManager(context,3));
holder. itemsRecycler.setHasFixedSize(true);
holder.itemsRecycler.setAdapter(itemsAdapter);
holder.itemsRecycler.setNestedScrollingEnabled(false);
try {
roomItemObject.clear();
JSONArray metaArray = new JSONArray(metaData);
int count = 0;
for(int i = 0;i<metaArray.length();i++){
JSONObject object = metaArray.getJSONObject(i);
String name = object.getString("name");
String[] rNum = name.split("_");
if(rNum[0].equalsIgnoreCase(roomNumber)){
roomItemObject.add(object);
}
count = count+1;
}
if(count == metaArray.length()){
int count1 = 0;
itemDataList.clear();
for(int i =0; i < roomItemObject.size();i++){
JSONObject itemObject1 = roomItemObject.get(i);
String groupNames = itemObject1.getString("groupNames");
String types = itemObject1.getString("type");
String metaValue = itemObject1.getString("metadata");
JSONObject panelObject = new JSONObject(metaValue);
String panel_name = panelObject.getString("panelName");
JSONObject valueObject = new JSONObject(panel_name);
String value = valueObject.getString("value");
if(value.equalsIgnoreCase(cur_panelName)){
String labels = itemObject1.getString("label");
String names = itemObject1.getString("name");
String state = itemObject1.getString("state");
String groupName = itemObject1.getString("groupNames");
String tags = itemObject1.getString("tags");
ItemData itemData = new ItemData();
itemData.setLabelName(labels);
itemData.setState(state);
itemData.setItemName(names);
itemData.setTags(tags);
itemData.setTypes(types);
itemData.setGroup(groupName);
itemDataList.add(itemData);
itemsAdapter.addItems(itemDataList);
itemsAdapter.notifyDataSetChanged();
}
}
}
}catch (JSONException e){
e.printStackTrace();
}
}
#Override
public int getItemCount() {
return roomPanelList.size();
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
public class ViewHolder extends RecyclerView.ViewHolder{
RecyclerView itemsRecycler;
TextView userPanelName;
Button deletePanel;
public ViewHolder(#NonNull View itemView) {
super(itemView);
itemsRecycler = itemView.findViewById(R.id.panel_item_recycler);
userPanelName = itemView.findViewById(R.id.test_panel_name);
deletePanel = itemView.findViewById(R.id.delete_panel);
}
}
}
//Inner Adapter
class ItemsAdapter extends RecyclerView.Adapter<ItemsAdapter.ItemHolder>{
Context mContext;
List<ItemData> innerItemDataList = new ArrayList<>();
List<JSONObject> itemObjectList = new ArrayList<JSONObject>();
List<JSONObject> recObjectList = new ArrayList<>();
ItemData itemData;
public ItemsAdapter(Context context) {
this.mContext = context;
this.itemData = new ItemData();
}
public void addItems(List<ItemData> itemData){
this.innerItemDataList.clear();
this.innerItemDataList.addAll(itemData);
notifyDataSetChanged();
}
#NonNull
#Override
public ItemsAdapter.ItemHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(mContext).inflate(R.layout.panel_wise_item,parent,false);
return new ItemHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull ItemHolder holder, int position) {
itemData = innerItemDataList.get(position);
if(itemData != null){
holder.itemNames.setText(itemData.getLabelName());
}
#Override
public int getItemCount() {
return innerItemDataList.size();
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
public class ItemHolder extends RecyclerView.ViewHolder {
TextView itemNames;
LinearLayout itemLayout;
ImageView itemImg;
public ItemHolder(#NonNull View itemView) {
super(itemView);
itemNames = itemView.findViewById(R.id.panel_item_name);
itemLayout = itemView.findViewById(R.id.panel_light_linear);
itemImg = itemView.findViewById(R.id.panel_item_img);
}
}
public void updateItem(String itemName,String state){
for(int j=0;j<innerItemDataList.size();j++){
if(itemName.equalsIgnoreCase(innerItemDataList.get(j).getItemName())){
innerItemDataList.get(j).setState(state);
notifyDataSetChanged();
}
}
}
}
//Inner adapter data model class
public class ItemData {
String labelName;
String itemName;
String state;
String group;
String tags;
String types;
public String getTypes() {
return types;
}
public void setTypes(String types) {
this.types = types;
}
public String getTags() {
return tags;
}
public void setTags(String tags) {
this.tags = tags;
}
public String getLabelName() {
return labelName;
}
public void setLabelName(String labelName) {
this.labelName = labelName;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
}
How to update specific item in inner adapter android nested recycler view.Can anyone guide me how to deal with update specific item. One more thing have observed inner adapter returns last position of array list only. Items are updating fine in last position of array list. When trying to updating the rest of position array list items, not getting updated.
Thanks in Advance.
Amar.
In outer adapter when ever data changes need to notify. Try this code
panelAdapter.notifyDataSetChanged();
How can I get the first adapter position inside another adapter to set value in SQLite Database
I want to select a value from the radio button onClick of the item and save it to SQLite database
it's working fine but it takes onClick last position of the item
So I need First Adapter position in the inside adapter to save a proper value of radio button in SQLite Database
Globally Declare
int pos = 0;
Here is my first adapter code
public class CartCustomAdapter extends RecyclerView.Adapter<CartCustomAdapter.MyViewHolder> {
private List<Cart> moviesList;
public CartCustomAdapter(List<Cart> moviesList) {
this.moviesList = moviesList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_cart_details, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
final List<Cart> datum = moviesList;
pos = holder.getAdapterPosition();
Log.e("POSI1", pos + "");
if (loginModel != null) {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("option_name", TextUtils.join(",", Collections.singleton(datum.get(position).getShippingOption() + "")));
hashMap.put("weight", datum.get(position).getWeight() + "");
hashMap.put("zip", loginModel.getResultLogin().getZip() + "");
Log.e("Parms", hashMap + "");
showProgressDialog();
Call<CheckOutShippingInfoModel> checkOutShippingInfoModelCall = RetrofitHelper.createService(RetrofitHelper.Service.class).CheckOutShippingInfoModel(hashMap);
checkOutShippingInfoModelCall.enqueue(new Callback<CheckOutShippingInfoModel>() {
#Override
public void onResponse(#NonNull Call<CheckOutShippingInfoModel> call, #NonNull Response<CheckOutShippingInfoModel> response) {
CheckOutShippingInfoModel object = response.body();
hideProgressDialog();
if (object != null && object.getError() == false) {
Log.e("TAG", "Shipping_Response : " + new Gson().toJson(response.body()));
holder.resultCheckoutShippingInfo = object.getResultCheckoutShippingInfo();
holder.resultCheckoutShippingInfo = object.getResultCheckoutShippingInfo();
holder.shippingCustomAdapter = new ShippingCustomAdapter(holder.resultCheckoutShippingInfo,
new ResultCallback() {
#Override
public void onItemClick(int position) {
//Do, what you need...
pos = holder.getAdapterPosition();
Log.e("postion", pos + "");
}
});
holder.recyclerViewShippingInfo.setAdapter(holder.shippingCustomAdapter);
} else {
}
}
#Override
public void onFailure(#NonNull Call<CheckOutShippingInfoModel> call, #NonNull Throwable t) {
hideProgressDialog();
t.printStackTrace();
Log.e("Shipping_Response", t.getMessage() + "");
}
});
} else {
Toast.makeText(getContext(), "Please Login", Toast.LENGTH_SHORT).show();
}
}
private int grandTotal() {
int totalPrice = 0;
for (int i = 0; i < moviesList.size(); i++) {
totalPrice += moviesList.get(i).getSubtotal();
// notifyDataSetChanged();
}
return totalPrice;
}
#Override
public int getItemCount() {
return moviesList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerViewShippingInfo;
private ShippingCustomAdapter shippingCustomAdapter;
private List<ResultCheckoutShippingInfo> resultCheckoutShippingInfo;
public MyViewHolder(View view) {
super(view);
recyclerViewShippingInfo = view.findViewById(R.id.recyclerViewShippingInfo);
recyclerViewShippingInfo.setLayoutManager(new GridLayoutManager(getContext(), 1));
recyclerViewShippingInfo.setHasFixedSize(true);
recyclerViewShippingInfo.setNestedScrollingEnabled(false);
}
}
}
Here is Another Adapter Code which inside the first adapter
public class ShippingCustomAdapter extends RecyclerView.Adapter<ShippingCustomAdapter.MyViewHolder> {
private List<ResultCheckoutShippingInfo> moviesList;
private RadioGroup lastCheckedRadioGroup = null;
private int lastSelectedPosition = 0;
boolean isSelected = false;
int previousSelectedPosition = -1;
ResultCallback callback;
public ShippingCustomAdapter(List<ResultCheckoutShippingInfo> moviesList, ResultCallback callback) {
this.moviesList = moviesList;
this.callback = callback;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_shipping_info, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
final List<ResultCheckoutShippingInfo> datum = moviesList;
Log.e("POSI", pos + "--" + position + "");
holder.shipping_name.setText(datum.get(position).getType() + "");
RadioButton rb = new RadioButton(getContext());
holder.radio.addView(rb);
if (cartId.equals("Standard")) {
rb.setChecked(true);
}
if (cartId.equals("Economy")) {
rb.setChecked(true);
}
if (cartId.equals("Free")) {
rb.setChecked(true);
}
}
#Override
public int getItemCount() {
return moviesList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView shipping_name, shipping_price;
RadioGroup radio;
RadioButton radioShipping;
public MyViewHolder(View view) {
super(view);
shipping_name = view.findViewById(R.id.shipping_name);
shipping_price = view.findViewById(R.id.shipping_price);
radio = view.findViewById(R.id.price_grp);
radio.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
if (lastCheckedRadioGroup != null
&& lastCheckedRadioGroup.getCheckedRadioButtonId()
!= radioGroup.getCheckedRadioButtonId()
&& lastCheckedRadioGroup.getCheckedRadioButtonId() != -1) {
lastCheckedRadioGroup.clearCheck();
databaseHelper.updateShippingInfo(cartModel.get(pos).getId(), shipping_price.getText().toString() + "", ShippingCustomAdapter.this.moviesList.get(i).getTypeId() + "");
label_subTotal.setText("Shipping : " + shipping_value + "\n" + "Total Amount : " + mSubTotal);
}
lastCheckedRadioGroup = radioGroup;
callback.onItemClick(i);
}
});
}
}
}
Here is a database Query for updating value after radio button change
public void updateShippingInfo(String id, String shipping, String current_option) {
SQLiteDatabase db = this.getWritableDatabase();
String sql = "UPDATE " + TABLE_NAME + " SET " + " shipping" + " = " + "'" + shipping + "'" + ", current_option" + " = " + "'" + current_option + "'" + " WHERE " + "id" + " = '" + id + "'";
Log.e("QUERY", sql);
db.execSQL(sql);
}
Here is ResultCheckoutShippingInfo
public class ResultCheckoutShippingInfo {
#SerializedName("type")
#Expose
private String type;
#SerializedName("type_id")
#Expose
private String typeId;
#SerializedName("days")
#Expose
private String days;
#SerializedName("price")
#Expose
private String price;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getTypeId() {
return typeId;
}
public void setTypeId(String typeId) {
this.typeId = typeId;
}
public String getDays() {
return days;
}
public void setDays(String days) {
this.days = days;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
Here I want to update database value
shipping charges = price
current_option = TypeId
using its position
You need to create: one RecyclerView.Adapter with item, that contains: photo, price, + | - buttons, delete button and radioGroup, which have dynamic radioButtons count, created using cycle by List<ResultCheckoutShippingInfo>.
public class CartCustomAdapter extends RecyclerView.Adapter<CartCustomAdapter.MyViewHolder> {
private List<Cart> moviesList;
public CartCustomAdapter(List<Cart> moviesList) {
this.moviesList = moviesList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_cart_details, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
final List<Cart> datum = moviesList;
pos = holder.getAdapterPosition();
Log.e("POSI1", pos + "");
if (loginModel != null) {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("option_name", TextUtils.join(",", Collections.singleton(datum.get(position).getShippingOption() + "")));
hashMap.put("weight", datum.get(position).getWeight() + "");
hashMap.put("zip", loginModel.getResultLogin().getZip() + "");
Log.e("Parms", hashMap + "");
showProgressDialog();
Call<CheckOutShippingInfoModel> checkOutShippingInfoModelCall = RetrofitHelper.createService(RetrofitHelper.Service.class).CheckOutShippingInfoModel(hashMap);
checkOutShippingInfoModelCall.enqueue(new Callback<CheckOutShippingInfoModel>() {
#Override
public void onResponse(#NonNull Call<CheckOutShippingInfoModel> call, #NonNull Response<CheckOutShippingInfoModel> response) {
CheckOutShippingInfoModel object = response.body();
hideProgressDialog();
if (object != null && object.getError() == false) {
Log.e("TAG", "Shipping_Response : " + new Gson().toJson(response.body()));
holder.resultCheckoutShippingInfo = object.getResultCheckoutShippingInfo();
//List<String> resultCheckoutShippingInfo = new ArrayList<>();
//resultCheckoutShippingInfo.add("Standard");
//resultCheckoutShippingInfo.add("Big cost");
for (ResultCheckoutShippingInfo info : holder.resultCheckoutShippingInfo){
RadioButton radioButton = new RadioButton(this);
radioButton.setText(info.name);
holder.radioShippingGroup.addView(radioButton);
//Check, if this element of radioGroup was checked in database and set checked it in radioGroup
if (info.isChecked()){
radioButton.setChecked(true);
}
}
holder.radioShippingGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
View radioButton = holder.radioShippingGroup.findViewById(checkedId);
int idx = holder.radioShippingGroup.indexOfChild(radioButton);
Log.i("TEST", "checkedId = " + Integer.toString(idx) + "; cartPosition = " + Integer.toString(position) + "; arraySize = " + Integer.toString(holder.resultCheckoutShippingInfo.size()));
databaseHelper.updateShippingInfo(
datum.get(position).getCartID,
holder.resultCheckoutShippingInfo.get(idx).getPrice() + "",
holder.resultCheckoutShippingInfo.get(idx).getTypeId() + "");
}
});
} else {
}
}
#Override
public void onFailure(#NonNull Call<CheckOutShippingInfoModel> call, #NonNull Throwable t) {
hideProgressDialog();
t.printStackTrace();
Log.e("Shipping_Response", t.getMessage() + "");
}
});
} else {
Toast.makeText(getContext(), "Please Login", Toast.LENGTH_SHORT).show();
}
}
private int grandTotal() {
int totalPrice = 0;
for (int i = 0; i < moviesList.size(); i++) {
totalPrice += moviesList.get(i).getSubtotal();
// notifyDataSetChanged();
}
return totalPrice;
}
#Override
public int getItemCount() {
return moviesList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
//RecyclerView recyclerViewShippingInfo;
//private ShippingCustomAdapter shippingCustomAdapter;
//private List<ResultCheckoutShippingInfo> resultCheckoutShippingInfo;
RadioGroup radioShippingGroup;
public MyViewHolder(View view) {
super(view);
radioShippingGroup = view.findViewById(R.id.radioShippingGroup);
//recyclerViewShippingInfo = view.findViewById(R.id.recyclerViewShippingInfo);
//recyclerViewShippingInfo.setLayoutManager(new GridLayoutManager(getContext(), 1));
//recyclerViewShippingInfo.setHasFixedSize(true);
//recyclerViewShippingInfo.setNestedScrollingEnabled(false);
}
}
}
I would suggest to use Listener pattern with few onChange callbacks. And pass it to one adapter to another. This would be cleaner solution.
I have a recyclerview list of items and in the adapter, I have a button for adding an item as favorite to an active android database like below code:
viewholder.favoriteWP_IV.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Favorites favorites = new Favorites(); // Model class for db crud
favorites.setFavoritesId(UUID.randomUUID().toString());
favorites.setLargeImgURL(pixaImages.getLargeImgURL());
favorites.setPreviewImgURL(pixaImages.getPreviewImgURL());
favorites.setImageId(favorites.getImageId());
favorites.save();
Log.d(TAG, "Fav_id:\t" + favorites.getId());
Log.d(TAG, "Favorites Id:\t" + favorites.getFavoritesId());
//TODO: 6/13/2018 Fix Duplicate Favorite WP
Toast.makeText(context, "Added to Favorites", Toast.LENGTH_SHORT).show();
}
});
and in my FavoritesActivity, I have retrieved all the items and shown them in a recyclerview like below code:
public List<Favorites> getAllFavorites() {
return new Select()
.all()
.from(Favorites.class)
.orderBy("favorites_id ASC")
.execute();
}
private void getFavorites() {
favsRV.setHasFixedSize(true);
favsRV.setLayoutManager(new LinearLayoutManager(this));
AdapterHeaderItem headerItem = new AdapterHeaderItem();
headerItem.setHeaderIcon(R.drawable.drawer_header_trimmed);
headerItem.setHeaderTitle("you can toggle through your favorite wallpapers using the wallpaper widget on your home screen");
objectList.add(headerItem);
//itemsList = getAllFavorites();
Favorites favorites = new Favorites();
for (int i = 0; i < getAllFavorites().size(); i++) {
favorites.setFavoritesId(getAllFavorites().get(i).getFavoritesId());
favorites.setLargeImgURL(getAllFavorites().get(i).getLargeImgURL());
favorites.setPreviewImgURL(getAllFavorites().get(i).getPreviewImgURL());
favorites.setImageId(getAllFavorites().get(i).getImageId());
Log.d(TAG, "All Favs Ids:\t" + getAllFavorites().get(i).getFavoritesId());
objectList.add(favorites);
}
Log.d(TAG, "Favorites List Size:\t" + objectList.size());
adapter = new FavoritesAdapter(this, objectList);
favsRV.setAdapter(adapter);
}
The problem here is that the item clicked on to be saved is not the one actually saved and when the list has multiple items, it retrieves duplicate copies of same item.
Previously, my adapter wasn't having a header and it was working fine but when I added the header to adapter, I had to change from List<Favorites> to List<Object> to enable me add the header items to the view.
In my activity, I have retrieved all the records while using old adapter code by this line itemsList = getAllFavorites(); but with the new adapter code, I have to use an object to store items in list.
I have tried this Favorites favs = (Favorites) itemsList = getAllFavorites(); but the app crashed, only other option I had was to do this and save in object list:
Favorites favorites = new Favorites();
for (int i = 0; i < getAllFavorites().size(); i++) {
favorites.setFavoritesId(getAllFavorites().get(i).getFavoritesId());
favorites.setLargeImgURL(getAllFavorites().get(i).getLargeImgURL());
favorites.setPreviewImgURL(getAllFavorites().get(i).getPreviewImgURL());
favorites.setImageId(getAllFavorites().get(i).getImageId());
Log.d(TAG, "All Favs Ids:\t" + getAllFavorites().get(i).getFavoritesId());
objectList.add(favorites);
}
Here's my model class:
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
#Table(name = "favorites")
public class Favorites extends Model{
#Column(name = "favorites_id")
public String favoritesId;
#Column(name = "image_id")
public int imageId;
#Column(name = "large_img_url")
public String largeImgURL;
#Column(name = "preview_img")
public String previewImgURL;
public Favorites() { }
public Favorites(String favoritesId, int imageId, String largeImgURL, String previewImgURL) {
this.favoritesId = favoritesId;
this.imageId = imageId;
this.largeImgURL = largeImgURL;
this.previewImgURL = previewImgURL;
}
public String getFavoritesId() {
return favoritesId;
}
public void setFavoritesId(String favoritesId) {
this.favoritesId = favoritesId;
}
public int getImageId() {
return imageId;
}
public void setImageId(int imageId) {
this.imageId = imageId;
}
public String getLargeImgURL() {
return largeImgURL;
}
public void setLargeImgURL(String largeImgURL) {
this.largeImgURL = largeImgURL;
}
public String getPreviewImgURL() {
return previewImgURL;
}
public void setPreviewImgURL(String previewImgURL) {
this.previewImgURL = previewImgURL;
}
}
but this code block gives me for a list of three items, one item duplicated three times. I think it's because of the change in code. The adapter works well but in activity, I am fetching wrong results.
Here's my adapter code:
public class FavoritesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = FavoritesAdapter.class.getSimpleName();
private final Context context;
private List<Object> itemsList;
public static final int HEADER_VIEW = 0;
public static final int ITEMS_VIEW = 1;
public FavoritesAdapter(Context context, List<Object> itemsList) {
this.context = context;
this.itemsList = itemsList;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if (viewType == HEADER_VIEW) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.app_adapter_header_layout, parent, false);
return new AdapterHeaderItemViewHolder(view);
} else if (viewType == ITEMS_VIEW) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.favorites_item_layout, parent, false);
return new FavoritesViewHolder(view);
}
throw new RuntimeException("No matching viewTypes");
}
#Override
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, int position) {
if (holder instanceof AdapterHeaderItemViewHolder) {
AdapterHeaderItem header = (AdapterHeaderItem) itemsList.get(position);
((AdapterHeaderItemViewHolder) holder).headerTitleTV.setText(header.getHeaderTitle());
Picasso.with(context)
.load(header.getHeaderIcon())
.placeholder(R.drawable.drawer_header_trimmed)
.into(((AdapterHeaderItemViewHolder) holder).headerIconIV);
} else if (holder instanceof FavoritesViewHolder) {
final Favorites favorites = (Favorites) itemsList.get(position);
Picasso.with(context)
.load(favorites.getLargeImgURL())
.placeholder(R.mipmap.ic_launcher)
.into(((FavoritesViewHolder) holder).favoriteWPImg);
((FavoritesViewHolder) holder).removeTV.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d(TAG, "Adapter VH Posn:\t" + holder.getAdapterPosition());
String fav_id = favorites.getFavoritesId();
Log.d(TAG, "Favorites+id:\t" + fav_id);
removeAtPosition(holder.getAdapterPosition(), fav_id);
}
});
((FavoritesViewHolder) holder).previewTV.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent previewIntent = new Intent(context, PreviewWallPaperActivity.class);
previewIntent.putExtra("fav_id", favorites.getFavoritesId());
previewIntent.putExtra("large_url", favorites.getLargeImgURL());
previewIntent.putExtra("preview_url", favorites.getPreviewImgURL());
context.startActivity(previewIntent);
}
});
}
}
private void removeAtPosition(int position, String id) {
Log.d(TAG, "id in method:\t" + id);
new Delete()
.from(Favorites.class)
.where("favorites_id=?", id)
.execute();
Log.d(TAG, "Favorite Removed from db");
itemsList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, itemsList.size());
Toast.makeText(context, "Removed From Favorites", Toast.LENGTH_SHORT).show();
}
#Override
public int getItemCount() {
if (itemsList == null) {
return 0;
}
return itemsList.size();
}
#Override
public int getItemViewType(int position) {
if (isPositionHeader(position))
return HEADER_VIEW;
return ITEMS_VIEW;
}
private boolean isPositionHeader(int position) {
return position == 0;
}
}
I think the problem lies here with the loop and inserting into the adapter list:
itemsList = getAllFavorites();
Favorites favorites = new Favorites();
for (int i = 0; i < getAllFavorites().size(); i++) {
favorites.setFavoritesId(getAllFavorites().get(i).getFavoritesId());
favorites.setLargeImgURL(getAllFavorites().get(i).getLargeImgURL());
favorites.setPreviewImgURL(getAllFavorites().get(i).getPreviewImgURL());
favorites.setImageId(getAllFavorites().get(i).getImageId());
Log.d(TAG, "All Favs Ids:\t" + getAllFavorites().get(i).getFavoritesId());
objectList.add(favorites);
}
//objectList.add(itemsList); // I have tried adding the first list of Favorite model class into the adapter list but it gives `classcast exception: Model class can't be cast to ArrayList`
Can anyone help me understand why same item is coming multiple times? Thanks.
How to show date or today , yesterday like text in between conversation
like whatsapp
MainActivity
public class MainActivity extends AppCompatActivity {
private ChatAdapter chatAdapter;
private RecyclerView recyclerView;
private Context context;
private int loggedInUserID;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindRecyclerView();
// TODO get logged in user id and initialize into 'loggedInUserID'
}
#Override
protected void onResume() {
super.onResume();
getData();
}
private void getData() {
/**
*Your server call to get data and parse json to your appropriate model
* after parsing json to model simply call the
*/
List<ChatModel> chatModelList = ParseData.chatParser(jsonArray);
groupDataIntoHashMap(chatModelList);
}
private void bindRecyclerView() {
chatAdapter = new ChatAdapter(null);
chatAdapter.setUser(loggedInUserID);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(context);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(chatAdapter);
}
private void groupDataIntoHashMap(List<ChatModel> chatModelList) {
LinkedHashMap<String, Set<ChatModel>> groupedHashMap = new LinkedHashMap<>();
Set<ChatModel> list = null;
for (ChatModel chatModel : chatModelList) {
//Log.d(TAG, travelActivityDTO.toString());
String hashMapKey = DateParser.convertDateToString(chatModel.getChatTime());
//Log.d(TAG, "start date: " + DateParser.convertDateToString(travelActivityDTO.getStartDate()));
if (groupedHashMap.containsKey(hashMapKey)) {
// The key is already in the HashMap; add the pojo object
// against the existing key.
groupedHashMap.get(hashMapKey).add(chatModel);
} else {
// The key is not there in the HashMap; create a new key-value pair
list = new LinkedHashSet<>();
list.add(chatModel);
groupedHashMap.put(hashMapKey, list);
}
}
//Generate list from map
generateListFromMap(groupedHashMap);
}
private List<ListObject> generateListFromMap(LinkedHashMap<String, Set<ChatModel>> groupedHashMap) {
// We linearly add every item into the consolidatedList.
List<ListObject> consolidatedList = new ArrayList<>();
for (String date : groupedHashMap.keySet()) {
DateObject dateItem = new DateObject();
dateItem.setDate(date);
consolidatedList.add(dateItem);
for (ChatModel chatModel : groupedHashMap.get(date)) {
ChatModelObject generalItem = new ChatModelObject();
generalItem.setChatModel(chatModel);
consolidatedList.add(generalItem);
}
}
chatAdapter.setDataChange(consolidatedList);
return consolidatedList;
}
}
ChatModel.java
public class ChatModel implements Serializable {
private String messageId;
private int userId;
private String firstName;
private String userName;
private String message;
private Date chatTime;
//TODO generate getter and setter
}
ListObject.java (to determind the type of message)
public abstract class ListObject {
public static final int TYPE_DATE = 0;
public static final int TYPE_GENERAL_RIGHT = 1;
public static final int TYPE_GENERAL_LEFT = 2;
abstract public int getType(int userId);
}
DateObject.java
public class DateObject extends ListObject {
private String date;
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
#Override
public int getType(int userId) {
return TYPE_DATE;
}
}
ChatModelObject.java
public class ChatModelObject extends ListObject {
private ChatModel chatModel;
public ChatModel getChatModel() {
return chatModel;
}
public void setChatModel(ChatModel chatModel) {
this.chatModel = chatModel;
}
#Override
public int getType(int userId) {
if (this.chatModel.getUserId() == userId) {
return TYPE_GENERAL_RIGHT;
} else
return TYPE_GENERAL_LEFT;
}
}
DateParse.java to parse date for grouping the chat
public class DateParser {
private static DateFormat dateFormat1 = new SimpleDateFormat("dd/MM/yyyy");
public static String convertDateToString(Date date) {
String strDate = "";
strDate = dateFormat1.format(date);
return strDate;
}
}
ChatAdapter.java
public class ChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<ListObject> listObjects;
private int loggedInUserId;
public ChatAdapter(List<ListObject> listObjects) {
this.listObjects = listObjects;
}
public void setUser(int userId) {
this.loggedInUserId = userId;
}
public void setDataChange(List<ListObject> asList) {
this.listObjects = asList;
//now, tell the adapter about the update
notifyDataSetChanged();
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case ListObject.TYPE_GENERAL_RIGHT:
View currentUserView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_chat_list_row_right, parent, false);
viewHolder = new ChatRightViewHolder(currentUserView); // view holder for normal items
break;
case ListObject.TYPE_GENERAL_LEFT:
View otherUserView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_chat_list_row_left, parent, false);
viewHolder = new ChatLeftViewHolder(otherUserView); // view holder for normal items
break;
case ListObject.TYPE_DATE:
View v2 = inflater.inflate(R.layout.date_row, parent, false);
viewHolder = new DateViewHolder(v2);
break;
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
switch (viewHolder.getItemViewType()) {
case ListObject.TYPE_GENERAL_RIGHT:
ChatModelObject generalItem = (ChatModelObject) listObjects.get(position);
ChatRightViewHolder chatViewHolder = (ChatRightViewHolder) viewHolder;
chatViewHolder.bind(generalItem.getChatModel());
break;
case ListObject.TYPE_GENERAL_LEFT:
ChatModelObject generalItemLeft = (ChatModelObject) listObjects.get(position);
ChatLeftViewHolder chatLeftViewHolder = (ChatLeftViewHolder) viewHolder;
chatLeftViewHolder.bind(generalItemLeft.getChatModel());
break;
case ListObject.TYPE_DATE:
DateObject dateItem = (DateObject) listObjects.get(position);
DateViewHolder dateViewHolder = (DateViewHolder) viewHolder;
dateViewHolder.bind(dateItem.getDate());
break;
}
}
#Override
public int getItemCount() {
if (listObjects != null) {
return listObjects.size();
}
return 0;
}
#Override
public int getItemViewType(int position) {
return listObjects.get(position).getType(loggedInUserId);
}
public ListObject getItem(int position) {
return listObjects.get(position);
}
}
ChatRightViewHolder.java for current user message
public class ChatRightViewHolder extends RecyclerView.ViewHolder {
private final String TAG = ChatRightViewHolder.class.getSimpleName();
public ChatRightViewHolder(View itemView) {
super(itemView);
//TODO initialize your xml views
}
public void bind(final ChatModel chatModel) {
//TODO set data to xml view via textivew.setText();
}
}
ChatLeftViewHolder.java for display other user messages.
public class ChatLeftViewHolder extends RecyclerView.ViewHolder {
private final String TAG = ChatRightViewHolder.class.getSimpleName();
public ChatLeftViewHolder(View itemView) {
super(itemView);
//TODO initialize your xml views
}
public void bind(final ChatModel chatModel) {
//TODO set data to xml view via textivew.setText();
}
}
DateViewHolder.java to display date
public class DateViewHolder extends RecyclerView.ViewHolder {
public DateViewHolder(View itemView) {
super(itemView);
//TODO initialize your xml views
}
public void bind(final String date) {
//TODO set data to xml view via textivew.setText();
}
}
You need to create a new ViewHolder for that purpose
For example:
// Different types of rows
private static final int TYPE_ITEM_LEFT = 0;
private static final int TYPE_ITEM_RIGHT = 1;
private static final int TYPE_ITEM_DATE_CONTAINER = 2;
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
class ViewHolder0 extends RecyclerView.ViewHolder {
// Viewholder for row type 0
}
class ViewHolder1 extends RecyclerView.ViewHolder {
// Viewholder for row type 1
}
class ViewHolder2 extends RecyclerView.ViewHolder {
// Viewholder for row type 2
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) {
if (viewHolder.getItemViewType() == TYPE_ITEM_LEFT) {
// Code to populate type 0 view here
} else if (viewHolder.getItemViewType() == TYPE_ITEM_RIGHT) {
// Code to populate type 1 view here
} else if (viewHolder.getItemViewType() == TYPE_ITEM_DATE_CONTAINER) {
// Code to populate type 2 view here
}
}
You just have to compare the date when scrolling and set the visibility of date view. The advantage of this is there's no hard-coded today/yesterday in data list and is able to refresh the correct date immediately (scrolling) after 12.00 a.m.
e.g. in your onBindViewHolder() in recycleview:
if (position != 0) {
processDate(holder.topDateTextView, myData.getDate()
, this.myDataList.get(position - 1).getDate()
, false)
;
} else {
processDate(holder.topDateTextView, data.getDay()
, null
, true)
;
}
Method to process that date view (Assume your list has format "dd/MM/yyyy"):
private void processDate(#NonNull TextView tv, String dateAPIStr
, String dateAPICompareStr
, boolean isFirstItem) {
SimpleDateFormat f = new SimpleDateFormat("dd/MM/yyyy");
if (isFirstItem) {
//first item always got date/today to shows
//and overkill to compare with next item flow
Date dateFromAPI = null;
try {
dateFromAPI = f.parse(dateAPIStr);
if (DateUtils.isToday(dateFromAPI.getTime())) tv.setText("today");
else if (DateUtils.isToday(dateFromAPI.getTime() + DateUtils.DAY_IN_MILLIS)) tv.setText("yesterday");
else tv.setText(dateAPIStr);
tv.setIncludeFontPadding(false);
tv.setVisibility(View.VISIBLE);
} catch (ParseException e) {
e.printStackTrace();
tv.setVisibility(View.GONE);
}
} else {
if (!dateAPIStr.equalsIgnoreCase(dateAPICompareStr)) {
try {
Date dateFromAPI = f.parse(dateAPIStr);
if (DateUtils.isToday(dateFromAPI.getTime())) tv.setText("today");
else if (DateUtils.isToday(dateFromAPI.getTime() + DateUtils.DAY_IN_MILLIS)) tv.setText("yesterday");
else tv.setText(dateAPIStr);
tv.setIncludeFontPadding(false);
tv.setVisibility(View.VISIBLE);
} catch (ParseException e) {
e.printStackTrace();
tv.setVisibility(View.GONE);
}
} else {
tv.setVisibility(View.GONE);
}
}
}
Note: You also need to do yourAdapter.notifyDataSetChanged(); if append new item to redraw to dismiss previous "today"/date after 12.00 a.m on the same page, not just rely on yourAdapter.notifyItemInserted(new_item_position) which doesn't redraw previous items.