I have fragment with RecyclerView.
I need the next:
Here my fragment:
public class MyFragment extends Fragment {
private ListConversationAdapter sortAdapter;
private Realm realm;
private RealmResults<LSConversation> realmResults;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
realm = Realm.getDefaultInstance();
realmResults = realm.where(LSConversation.class).findAllAsync();
sortAdapter = new ListConversationAdapter(getActivity(), realmResults)
sortRecyclerView.setAdapter(sortAdapter);
}
Here my adapter:
public class ListConversationAdapter extends RealmRecyclerViewAdapter<LSConversation, ListConversationAdapter.ConversationViewHolder> {
private RealmList<LSConversation> lsConversations = new RealmList<>();
public ListConversationAdapter(Context context, RealmResults<LSConversation> list) {
super(list, true, true);
}
@NonNull
@Override
public ConversationViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.item_conversation, parent, false);
return new ConversationViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ConversationViewHolder holder, final int position) {
LSConversation lsConversation = getItem(position);
if (lsConversation != null && lsConversation.isValid()) {
// to do something
}
}
class ConversationViewHolder extends RecyclerView.ViewHolder {
LinearLayout item;
AvatarView imageViewIcon;
TextView textTitle;
TextView textMessage;
TextView textTimeStamp;
ConversationViewHolder(View itemView) {
super(itemView);
item = itemView.findViewById(R.id.layoutConversation);
imageViewIcon = itemView.findViewById(R.id.iconConversation);
textTitle = itemView.findViewById(R.id.textViewConversationTitle);
textTimeStamp = itemView.findViewById(R.id.textViewConversationTimeStamp);
textMessage = itemView.findViewById(R.id.textViewConversationMessage);
}
}
}
Here my LSConversation.java:
public class LSConversation extends RealmObject {
@PrimaryKey
@Required
@RealmField (name = RealmConstants.conversationId)
private String conversationId;
@Required
@RealmField (name = RealmConstants.displayName)
private String displayName;
// type: direct (private), group (public), broadcast (broadcast)
@Required
@RealmField (name = RealmConstants.type)
private String type;
@RealmField (name = RealmConstants.repliedBroadcast)
private boolean repliedBroadcast;
@RealmField (name = RealmConstants.owner)
private LSUser owner;
@Required
@RealmField (name = RealmConstants.lastModified)
private Date lastModified;
// using for filter conversation by users existed inside it
@RealmField (name = RealmConstants.displayToUsers)
private RealmList<LSUser> displayToUsers;
// using for filter conversation after archive
@RealmField (name = RealmConstants.archiveFromUsers)
private RealmList<LSUser> archiveFromUsers;
// using for filter conversation after delete
@RealmField (name = RealmConstants.deleteFromUsers)
private RealmList<LSUser> deleteFromUsers;
// using for storage all users in conversation
@RealmField (name = RealmConstants.activeUsers)
private RealmList<LSUser> activeUsers;
// using for storage all users was read conversation
@RealmField (name = RealmConstants.seenUsers)
private RealmList<LSUser> seenUsers;
@RealmField (name = RealmConstants.messages)
private RealmList<LSMessage> messages;
// using for storage info of user after delete conversation
@RealmField (name = RealmConstants.conversationHistoryFroms)
private RealmList<LSConversationHistoryFrom> conversationHistoryFroms;
@RealmField (name = RealmConstants.latestMessage)
private LSMessage latestMessage;
@Ignore
private boolean isReaded;
public String getConversationId() { return conversationId; }
public void setConversationId(String conversationId) { this.conversationId = conversationId; }
public String getDisplayName() { return displayName; }
public void setDisplayName(String displayName) { this.displayName = displayName; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public boolean isRepliedBroadcast() { return repliedBroadcast; }
public void setRepliedBroadcast(boolean repliedBroadcast) { this.repliedBroadcast = repliedBroadcast; }
public LSUser getOwner() { return owner; }
public void setOwner(LSUser owner) { this.owner = owner; }
public Date getLastModified() { return lastModified; }
public void setLastModified(Date lastModified) { this.lastModified = lastModified; }
public RealmList<LSUser> getDisplayToUsers() { return displayToUsers; }
public void setDisplayToUsers(RealmList<LSUser> displayToUsers) { this.displayToUsers = displayToUsers; }
public RealmList<LSUser> getArchiveFromUsers() { return archiveFromUsers; }
public void setArchiveFromUsers(RealmList<LSUser> archiveFromUsers) { this.archiveFromUsers = archiveFromUsers; }
public RealmList<LSUser> getDeleteFromUsers() { return deleteFromUsers; }
public void setDeleteFromUsers(RealmList<LSUser> deleteFromUsers) { this.deleteFromUsers = deleteFromUsers; }
public RealmList<LSUser> getActiveUsers() { return activeUsers; }
public void setActiveUsers(RealmList<LSUser> activeUsers) { this.activeUsers = activeUsers; }
public RealmList<LSUser> getSeenUsers() { return seenUsers; }
public void setSeenUsers(RealmList<LSUser> seenUsers) { this.seenUsers = seenUsers; }
public RealmList<LSMessage> getMessages() { return messages; }
public void setMessages(RealmList<LSMessage> messages) { this.messages = messages; }
public RealmList<LSConversationHistoryFrom> getConversationHistoryFroms() {
return conversationHistoryFroms;
}
public void setConversationHistoryFroms(RealmList<LSConversationHistoryFrom> conversationHistoryFroms) {
this.conversationHistoryFroms = conversationHistoryFroms;
}
public boolean isReaded() {
return isReaded;
}
public void setReaded(boolean readed) {
isReaded = readed;
}
public LSMessage getLatestMessage() {
return latestMessage;
}
public void setLatestMessage(LSMessage latestMessage) {
this.latestMessage = latestMessage;
}
public boolean isInActive() {
return MessageUtils.isInactiveConversation(this);
}
public Date getOrderBy() {
if (isInActive()) {
LSMessage lsMessage = MessageUtils.getLatestMessage(this);
if (lsMessage != null) {
return lsMessage.getTimestamp();
} else {
return new Date(0);
}
} else {
return lastModified;
}
}
}
Here my LSConversationSortOrder.java
public class LSConversationSortOrder implements Comparator<LSConversation> {
@Override
public int compare(LSConversation lsConversation1, LSConversation lsConversation2) {
Date date1 = lsConversation1.getOrderBy(), date2 = lsConversation2.getOrderBy();
return (date1 != null && date2 != null) ? date2.compareTo(date1) : 0;
}
}
And as result all work fine. Nice!
But after Realm data changed I want to sorting data list by custom Comparator LSConversationSortOrder, this property "getOrderBy" is only using in Local not sync up to realm server.
Question:
How to using RealmList data after sorting by LSConversationSortOrder for ListConversationAdapter
Something like this:
Here my adapter:
public class ListConversationAdapter extends RealmRecyclerViewAdapter<LSConversation, ListConversationAdapter.ConversationViewHolder> {
private RealmList<LSConversation> lsConversations = new RealmList<>();
public ListConversationAdapter(Context context, RealmResults<LSConversation> list) {
super(list, true, true);
list.addChangeListener(new RealmChangeListener<RealmResults<LSConversation>>() {
@Override
public void onChange(RealmResults<LSConversation> lsConversations) {
MyLogger.getInstance(TAG).info("RealmChangeListener");
updateDataList();
}
});
}
private void updateDataList() {
MyLogger.getInstance(TAG).info("updateDataList");
if (getData() != null && getData().size() > 0) {
lsConversations = new RealmList<>();
lsConversations.addAll(getData());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
lsConversations.sort(new LSConversationSortOrder());
} else {
Collections.sort(lsConversations, new LSConversationSortOrder());
}
notifyDataSetChanged();
}
}
private LSConversation getCustomItem(int position) {
return lsConversations != null ? lsConversations.get(position) : null;
}
@NonNull
@Override
public ConversationViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.item_conversation, parent, false);
return new ConversationViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ConversationViewHolder holder, final int position) {
LSConversation lsConversation = getCustomItem(position);
if (lsConversation != null && lsConversation.isValid()) {
// to do something
}
}
class ConversationViewHolder extends RecyclerView.ViewHolder {
LinearLayout item;
AvatarView imageViewIcon;
TextView textTitle;
TextView textMessage;
TextView textTimeStamp;
ConversationViewHolder(View itemView) {
super(itemView);
item = itemView.findViewById(R.id.layoutConversation);
imageViewIcon = itemView.findViewById(R.id.iconConversation);
textTitle = itemView.findViewById(R.id.textViewConversationTitle);
textTimeStamp = itemView.findViewById(R.id.textViewConversationTimeStamp);
textMessage = itemView.findViewById(R.id.textViewConversationMessage);
}
}
}
I remind you that I need 2 things:
1.When Realm was changed in fragment the RecyclerVeiw must autoupdate.
2.Data show in sorted order
Thank you.
Realm version(s):
android-adapters: 3.0.0
realm-gradle-plugin: 5.4.2
Realm sync feature enabled: no
Android Studio version: 3.1.4
Which Android version and device: 5.1.1
Hi, anyone can help? tks
You can only use Comparator for the list if your list is an "unmanaged RealmList".
But that clearly won't do.
if (data != null && !data.isManaged())
throw new IllegalStateException("Only use this adapter with managed list, " +
"for un-managed lists you can just use the RecyclerView.Adapter");
Therefore to execute the comparator, you need to copy the items from the Realm, this is potentially lengthy operation so it makes sense to do on background thread
try(Realm realm = Realm.getDefaultInstance()) {
return Collections.sort(realm.copyFromRealm(realm.where().....findAll()), new LSConversationSortOrder());
}
Which means the only way to retain automatic updates if you re-evaluate this thing on a background thread each time you get a RealmResults notification for which you probably want a second RealmResults that is
realm.where(LSConversation.class).findAllAsync()
Keep it as field reference, and add a change listener to it so that you know you have to re-calculate your list, which you can pass into your regular ListAdapter and let it diff the new items
@Zhuinden Than you for your answer, but I found the solution as here:
public class ListConversationAdapter extends RealmRecyclerViewAdapter<LSConversation, ListConversationAdapter.ConversationViewHolder> {
private RealmList<LSConversation> lsConversationsRealmList = new RealmList<>();
public ListConversationAdapter(Context context, RealmResults<LSConversation> lsConversations, LSUser myLSUser, String conversationType) {
super(lsConversations, true);
this.context = context;
this.myLSUser = myLSUser;
this.conversationType = conversationType;
lsConversations.addChangeListener((lsConversations1, changeSet) -> {
updateDataList();
notifyDataSetChanged();
});
}
private void updateDataList() {
if (getData() != null && getData().size() > 0) {
lsConversationsRealmList = new RealmList<>();
lsConversationsRealmList.addAll(getData());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
lsConversationsRealmList.sort(new LSConversationSortOrder());
} else {
Collections.sort(lsConversationsRealmList, new LSConversationSortOrder());
}
}
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
updateDataList();
}
@Nullable
@Override
public LSConversation getItem(int index) {
return lsConversationsRealmList != null ? lsConversationsRealmList.get(index) : null;
}
@Override
public int getItemCount() {
return lsConversationsRealmList != null ? lsConversationsRealmList.size() : 0;
}
@NonNull
@Override
public ConversationViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.item_conversation, parent, false);
return new ConversationViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ConversationViewHolder holder, final int position) {
LSConversation lsConversation = getItem(position);
if (lsConversation != null && lsConversation.isValid()) {
// to do something
}
}
}
It's mean: just define RealmList
It's working fine.
Please tell me if something wrong. Thank you.
Well, that's slightly trickier than what I expected, but it makes sense. I just didn't think about re-using RealmRecyclerViewAdapter and override getItem.
Most helpful comment
@Zhuinden Than you for your answer, but I found the solution as here:
It's mean: just define RealmList lsConversationsRealmList and override getItem() inside adapter.
It's working fine.
Please tell me if something wrong. Thank you.