RecyclerView适配器上的一个Map和两个Lists



我正在开发一个聊天应用程序,我正在处理SearchableActivity,用户在其中输入他想要搜索的文本。输出如下。如您所见,RecyclerView显示用户和/或消息。我有一个包含消息的列表,一个包含上一个列表的消息中的用户数据的列表,以及一个存储用户部分中用户的映射。

问题是,这种结构在代码上很复杂,而且不是很有效。如果你注意到,我打开了软键盘,因为当用户Map和消息List都不为空时,关闭软键盘会引发这种情况(我不知道是什么导致了这种行为(以及其他一些不一致,甚至会导致应用程序崩溃。

考虑到上面的细节,我希望能够完美地展示这两个项目。这是代码:SearchableActivity.java

public class SearchableActivity extends AppCompatActivity {
private Map<String, User> searchedUsers;
private List<Message> searchedMessages;
private List<User> searchedMessagesUser;
private String searchUserID;
private TextView notFoundTV;
private RecyclerView searchRV;
private SearchableAdapter searchableAdapter;
private MaterialCardView searchTipCV;
private boolean isUserNameValid = true;
private boolean doesMessageFitQuery = false;
private final DatabaseReference messagesReference = FirebaseDatabase.getInstance().getReference()
.child(KEY_COLLECTION_MESSAGE);
private final DatabaseReference usersReference = FirebaseDatabase.getInstance().getReference()
.child(KEY_COLLECTION_USER);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_searchable);
ActionBar actionBar = this.getSupportActionBar();
actionBar.setTitle("");
actionBar.setDisplayHomeAsUpEnabled(true);
setUpRV();
notFoundTV = findViewById(R.id.notFoundTV);
searchTipCV = findViewById(R.id.searchTipCV);
}
private void setUpRV() {
searchedUsers = new HashMap<>();
searchedMessages = new ArrayList<>();
searchedMessagesUser = new ArrayList<>();
searchableAdapter = new SearchableAdapter(SearchableActivity.this,
searchedUsers,
searchedMessages,
searchedMessagesUser
);
searchRV = findViewById(R.id.searchRV);
searchRV.setHasFixedSize(true);
searchRV.setLayoutManager(new LinearLayoutManager(SearchableActivity.this));
searchRV.setAdapter(searchableAdapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_searchable, menu);
SearchView searchView = (SearchView) menu.findItem(R.id.searchIT).getActionView();
searchView.setMaxWidth(Integer.MAX_VALUE);
searchView.setIconified(false);
searchView.setFocusable(true);
searchView.requestFocusFromTouch();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String query) {
if (!TextUtils.isEmpty(query)) {
search(query);
}
return true;
}
});
return true;
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
private void search(String query) {
searchedUsers.clear();
searchedMessages.clear();
searchedMessagesUser.clear();
isUserNameValid = true;
String finalQuery = query.trim();
if (finalQuery.isEmpty()) {
setViewsVisibility(View.GONE, View.VISIBLE, View.GONE);
isUserNameValid = false;
} else if (finalQuery.length() < 4 || !finalQuery.matches("^[a-zA-Z0-9]+$")) {
isUserNameValid = false;
}
messagesReference.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NotNull DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() == null && isUserNameValid) {
searchUser(finalQuery);
} else {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
doesMessageFitQuery = false;
Message message = snapshot.getValue(Message.class);
String[] wordsFromMessage = message.getMessage().split(" ");
int i;
for (i = 0; i < wordsFromMessage.length; i++) {
if (wordsFromMessage[i].toLowerCase().startsWith(finalQuery.toLowerCase())) {
doesMessageFitQuery = true;
break;
}
}
if (doesMessageFitQuery
&& (message.getSenderID().equals(CURRENT_USER.getId())
|| message.getReaderID().equals(CURRENT_USER.getId()))) {
if (message.getReaderID().equals(CURRENT_USER.getId())) {
searchUserID = message.getSenderID();
} else {
searchUserID = message.getReaderID();
}
searchedMessages.add(message);
usersReference.child(searchUserID).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
User user = snapshot.getValue(User.class);
searchedMessagesUser.add(user);
if (isUserNameValid) {
searchUser(finalQuery);
} else {
refreshRV();
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
} else if (isUserNameValid) {
searchUser(finalQuery);
} else {
setViewsVisibility(View.GONE, View.GONE, View.VISIBLE);
}
}
}
}
@Override
public void onCancelled(@NotNull DatabaseError databaseError) { }
});
}
private void searchUser(String finalQuery) {
usersReference.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NotNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
User user = snapshot.getValue(User.class);
if (user.getUserName().equals(CURRENT_USER.getUserName())) continue;
if (user.getUserName().toLowerCase().startsWith(finalQuery.toLowerCase())) {
searchedUsers.put(user.getId(), user);
}
refreshRV();
}
}
@Override
public void onCancelled(@NotNull DatabaseError databaseError) { }
});
}
private void setViewsVisibility(int searchVis, int searchTipVis, int notFoundVis) {
searchRV.setVisibility(searchVis);
searchTipCV.setVisibility(searchTipVis);
notFoundTV.setVisibility(notFoundVis);
}
private void refreshRV() {
setViewsVisibility(View.VISIBLE, View.GONE, View.GONE);
if (searchedUsers.size() > 0 && searchedMessages.size() > 0) {
setupRV(searchedUsers, searchedMessages, searchedMessagesUser);
} else if (searchedUsers.size() > 0) {
setupRV(searchedUsers, new ArrayList<>(), new ArrayList<>());
} else if (searchedMessages.size() > 0) {
setupRV(new HashMap<>(), searchedMessages, searchedMessagesUser);
} else {
setViewsVisibility(View.GONE, View.GONE, View.VISIBLE);
}
}
private void setupRV(@NotNull Map<String, User> searchedUsers,
@NotNull List<Message> searchedMessages,
@NotNull List<User> searchedMessagesUsers) {
searchableAdapter = new SearchableAdapter(
SearchableActivity.this,
searchedUsers,
searchedMessages,
searchedMessagesUsers
);
searchRV.setAdapter(searchableAdapter);
}
}

SearchableAdapter.java

public class SearchableAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Context context;
private final Map<String, User> searchedUsers;
private final List<User> searchedMessagesUsers;
private final List<Message> searchedMessages;
private int messageListPosition;
private boolean areUsersLeft = true;
public static final int NO_ITEM = -1;
public static final int ITEM_USER = 0;
public static final int ITEM_MSG_SENT = 1;
public static final int ITEM_MSG_RECEIVED = 2;
public SearchableAdapter(Context context, Map<String, User> searchedUsers, List<Message> searchedMessages, List<User> searchedMessagesUsers) {
this.context = context;
this.searchedUsers = searchedUsers;
this.searchedMessages = searchedMessages;
this.searchedMessagesUsers = searchedMessagesUsers;
messageListPosition = 0;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view;
switch (viewType) {
case ITEM_USER:
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_user_searched, parent, false);
return new SearchableAdapter.UserHolder(view);
case ITEM_MSG_SENT:
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_recent_chat_sent, parent, false);
return new SearchableAdapter.MessageSentHolder(view);
case ITEM_MSG_RECEIVED:
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_recent_chat_received, parent, false);
return new SearchableAdapter.MessageReceivedHolder(view);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case ITEM_USER:
String key = (String) searchedUsers.keySet().toArray()[position];
((SearchableAdapter.UserHolder) holder).bind(searchedUsers.get(key), position);
break;
case ITEM_MSG_SENT:
((SearchableAdapter.MessageSentHolder) holder).bind(
searchedMessages.get(messageListPosition),
searchedMessagesUsers.get(messageListPosition),
messageListPosition
);
if (messageListPosition + 1 != searchedMessages.size()) {
messageListPosition++;
}
break;
case ITEM_MSG_RECEIVED:
((SearchableAdapter.MessageReceivedHolder) holder).bind(
searchedMessages.get(messageListPosition),
searchedMessagesUsers.get(messageListPosition),
messageListPosition
);
if (messageListPosition + 1 != searchedMessages.size()) {
messageListPosition++;
}
break;
}
}
@Override
public int getItemCount() {
if (!searchedMessages.isEmpty() && !searchedUsers.isEmpty()) {
return searchedUsers.size() + searchedMessages.size();
} else if (!searchedMessages.isEmpty()) {
return searchedMessages.size();
} else if (!searchedUsers.isEmpty()) {
return searchedUsers.size();
}
return 0;
}
@Override
public int getItemViewType(int position) {
if (areUsersLeft && !searchedUsers.isEmpty() && position < searchedUsers.size()) {
if (searchedUsers.size() - 1 == position) {
areUsersLeft = false;
}
return ITEM_USER;
} else if (!searchedMessages.isEmpty()) {
if (!searchedUsers.isEmpty() && messageListPosition < searchedMessages.size()) {
if (searchedMessages.get(messageListPosition).getSenderID().equals(Constants.CURRENT_USER.getId())) {
return ITEM_MSG_SENT;
} else {
return ITEM_MSG_RECEIVED;
}
} else if (searchedUsers.isEmpty() && position < searchedMessages.size()) {
if (searchedMessages.get(position).getSenderID().equals(Constants.CURRENT_USER.getId())) {
return ITEM_MSG_SENT;
} else {
return ITEM_MSG_RECEIVED;
}
}
}
return NO_ITEM;
}
class UserHolder extends RecyclerView.ViewHolder {
public ImageView profileIV;
public TextView defaultProfileTV, usernameTV, aboutTV, usersSectionTV;
public UserHolder(@NonNull View itemView) {
super(itemView);
defaultProfileTV = itemView.findViewById(R.id.defaultProfileTV);
usernameTV = itemView.findViewById(R.id.usernameTV);
aboutTV = itemView.findViewById(R.id.aboutTV);
profileIV = itemView.findViewById(R.id.profileIV);
usersSectionTV = itemView.findViewById(R.id.usersSectionTV);
}
void bind(User user, int position) {
if (position == 0) {
usersSectionTV.setVisibility(View.VISIBLE);
}
usernameTV.setText(user.getUserName());
aboutTV.setText(user.getAbout());
showProfilePic(defaultProfileTV, profileIV, user);
itemView.setOnClickListener(v -> openChat(user));
}
}
class MessageReceivedHolder extends RecyclerView.ViewHolder {
public TextView defaultProfileTV, usernameTV, dateLastMesTV, previewMessageTV, messagesSectionTV;
public ImageView profileIV;
public CardView statusCV;
public MessageReceivedHolder(@NonNull View itemView) {
super(itemView);
defaultProfileTV = itemView.findViewById(R.id.defaultProfileTV);
usernameTV = itemView.findViewById(R.id.usernameTV);
dateLastMesTV = itemView.findViewById(R.id.dateLastMesTV);
previewMessageTV = itemView.findViewById(R.id.previewMessageTV);
profileIV = itemView.findViewById(R.id.profileIV);
statusCV = itemView.findViewById(R.id.statusCV);
messagesSectionTV = itemView.findViewById(R.id.messagesSectionTV);
}
void bind(Message message, User user, int position) {
statusCV.setVisibility(View.GONE);
if (position == 0) {
messagesSectionTV.setVisibility(View.VISIBLE);
}
usernameTV.setText(user.getUserName());
previewMessageTV.setText(message.getMessage());
formatDate(dateLastMesTV, message.getDate());
showProfilePic(defaultProfileTV, profileIV, user);
itemView.setOnClickListener(v -> openChat(user));
}
}
class MessageSentHolder extends RecyclerView.ViewHolder {
public TextView defaultProfileTV, usernameTV, dateLastMesTV, previewMessageTV, messagesSectionTV;
public ImageView profileIV, seenIV, notSeenIV;
public CardView statusCV;
MessageSentHolder(View itemView) {
super(itemView);
defaultProfileTV = itemView.findViewById(R.id.defaultProfileTV);
usernameTV = itemView.findViewById(R.id.usernameTV);
dateLastMesTV = itemView.findViewById(R.id.dateLastMesTV);
previewMessageTV = itemView.findViewById(R.id.previewMessageTV);
profileIV = itemView.findViewById(R.id.profileIV);
seenIV = itemView.findViewById(R.id.seenIV);
notSeenIV = itemView.findViewById(R.id.notSeenIV);
statusCV = itemView.findViewById(R.id.statusCV);
messagesSectionTV = itemView.findViewById(R.id.messagesSectionTV);
}
void bind(Message message, User user, int position) {
statusCV.setVisibility(View.GONE);
if (position == 0) {
messagesSectionTV.setVisibility(View.VISIBLE);
}
if (message.isSeen()) {
seenIV.setVisibility(View.VISIBLE);
notSeenIV.setVisibility(View.GONE);
} else {
seenIV.setVisibility(View.GONE);
notSeenIV.setVisibility(View.VISIBLE);
}
usernameTV.setText(user.getUserName());
previewMessageTV.setText(message.getMessage());
showProfilePic(defaultProfileTV, profileIV, user);
formatDate(dateLastMesTV, message.getDate());
itemView.setOnClickListener(v -> openChat(user));
}
}
private void formatDate(TextView dateLastMesTV, String date) {
SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault());
Date currentDay =  new Date(System.currentTimeMillis());
Date chatDay = new Date(Long.parseLong(date));
if (formatter.format(currentDay).equals(formatter.format(chatDay))) {
dateLastMesTV.setText(
DateFormat.getTimeInstance(
DateFormat.SHORT,
Locale.getDefault()
).format(chatDay)
);
} else {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yy", Locale.getDefault());
dateLastMesTV.setText(dateFormat.format(Long.valueOf(date)));
}
}
private void showProfilePic(TextView defaultProfileTV, ImageView profileIV, User user) {
if (user.getImageURL().equals(Constants.KEY_IMAGE_URL_DEFAULT)) {
defaultProfileTV.setVisibility(View.VISIBLE);
defaultProfileTV.setText(user.getUserName().substring(0, 1));
} else {
profileIV.setVisibility(View.VISIBLE);
Glide.with(context)
.load(user.getImageURL())
.circleCrop()
.into(profileIV);
}
}
private void openChat(User user) {
Intent i = new Intent(context, ChatActivity.class);
i.putExtra(Constants.INTENT_USER, user);
context.startActivity(i);
}
}

欢迎提出任何建议。也许Lists/Map背后的逻辑可以简化,我不知道。我想得再清楚不过了。以下是相关的数据库结构,以防万一:

> Message
> > (message ID)
> > > date
> > > message
> > > readerID
> > > seen
> > > senderID
> User
> > (user ID)
> > > about
> > > id
> > > imageURL
> > > lastSeen
> > > userName

几天后,我想出了一个解决方法。我已经将结构更改为更简单的结构,尽管这意味着更多的代码。我在SearchActivity中放了一个ViewPager2,以便为用户和消息分别提供一个选项卡,而不是在同一个RecyclerView中显示所有选项卡。这样,代码不仅更简单,而且有助于显示查询结果,比以前的方法更干净。这是代码:

SearchActivity.java

public class SearchActivity extends AppCompatActivity {
private ViewPager2 searchVP2;
private String globalQuery;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
setupActionBar();
setupViewPager();
}
private void setupActionBar() {
ActionBar actionBar = this.getSupportActionBar();
actionBar.setTitle("");
actionBar.setDisplayHomeAsUpEnabled(true);
}
private void setupViewPager() {
searchVP2 = findViewById(R.id.searchVP2);
searchVP2.setAdapter(new SearchPagerAdapter(this));
TabLayout searchTL = findViewById(R.id.searchTL);
TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(searchTL, searchVP2, (tab, position) -> {
switch (position) {
case 0: {
tab.setText(R.string.users);
break;
}
case 1: {
tab.setText(R.string.messages);
break;
}
}
});
tabLayoutMediator.attach();
searchTL.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
searchInCurrentFrag(globalQuery, tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) { }
@Override
public void onTabReselected(TabLayout.Tab tab) { }
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_searchable, menu);
SearchView searchView = (SearchView) menu.findItem(R.id.searchIT).getActionView();
searchView.setMaxWidth(Integer.MAX_VALUE);
searchView.setIconified(false);
searchView.setFocusable(true);
searchView.requestFocusFromTouch();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String query) {
globalQuery = query;
if (!TextUtils.isEmpty(query)) {
searchInCurrentFrag(query, searchVP2.getCurrentItem());
}
return true;
}
});
return true;
}
private void searchInCurrentFrag(String query, int position) {
if (query != null) {
Fragment currentFragment = getSupportFragmentManager().findFragmentByTag("f" + position);
if (currentFragment instanceof SearchUserFragment) {
((SearchUserFragment) currentFragment).searchUser(query);
} else {
((SearchMessageFragment) currentFragment).searchMessage(query);
}
}
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
}

SearchPagerAdapter.java

public class SearchPagerAdapter extends FragmentStateAdapter {
public SearchPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
super(fragmentActivity);
}
@NonNull
@Override
public Fragment createFragment(int position) {
if (position == 0) {
return new SearchUserFragment();
} else {
return new SearchMessageFragment();
}
}
@Override
public int getItemCount() {
return 2;
}
}

SearchMessageAdapter.java

public class SearchMessageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Context context;
private final List<User> searchedMessagesUsers;
private final List<Message> searchedMessages;
//Result codes
public static final int ITEM_MSG_SENT = 0;
public static final int ITEM_MSG_RECEIVED = 1;
public SearchMessageAdapter(Context context, List<Message> searchedMessages, List<User> searchedMessagesUsers) {
this.context = context;
this.searchedMessages = searchedMessages;
this.searchedMessagesUsers = searchedMessagesUsers;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view;
switch (viewType) {
case ITEM_MSG_SENT:
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_recent_chat_sent, parent, false);
return new SearchMessageAdapter.MessageSentHolder(view);
case ITEM_MSG_RECEIVED:
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_recent_chat_received, parent, false);
return new SearchMessageAdapter.MessageReceivedHolder(view);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case ITEM_MSG_SENT:
((SearchMessageAdapter.MessageSentHolder) holder).bind(
searchedMessages.get(position),
searchedMessagesUsers.get(position)
);
break;
case ITEM_MSG_RECEIVED:
((SearchMessageAdapter.MessageReceivedHolder) holder).bind(
searchedMessages.get(position),
searchedMessagesUsers.get(position)
);
break;
}
}
@Override
public int getItemCount() {
return searchedMessages.size();
}
@Override
public int getItemViewType(int position) {
if (searchedMessages.get(position).getSenderID().equals(Constants.CURRENT_USER.getId())) {
return ITEM_MSG_SENT;
} else {
return ITEM_MSG_RECEIVED;
}
}
class MessageReceivedHolder extends RecyclerView.ViewHolder {
public TextView defaultProfileTV, usernameTV, dateLastMesTV, previewMessageTV;
public ImageView profileIV;
public CardView statusCV;
public MessageReceivedHolder(@NonNull View itemView) {
super(itemView);
defaultProfileTV = itemView.findViewById(R.id.defaultProfileTV);
usernameTV = itemView.findViewById(R.id.usernameTV);
dateLastMesTV = itemView.findViewById(R.id.dateLastMesTV);
previewMessageTV = itemView.findViewById(R.id.previewMessageTV);
profileIV = itemView.findViewById(R.id.profileIV);
statusCV = itemView.findViewById(R.id.statusCV);
}
void bind(Message message, User user) {
statusCV.setVisibility(View.GONE);
usernameTV.setText(user.getUserName());
previewMessageTV.setText(message.getMessage());
formatDate(dateLastMesTV, message.getDate());
showProfilePic(defaultProfileTV, profileIV, user);
itemView.setOnClickListener(v -> openChat(user));
}
}
class MessageSentHolder extends RecyclerView.ViewHolder {
public TextView defaultProfileTV, usernameTV, dateLastMesTV, previewMessageTV;
public ImageView profileIV, seenIV, notSeenIV;
public CardView statusCV;
MessageSentHolder(View itemView) {
super(itemView);
defaultProfileTV = itemView.findViewById(R.id.defaultProfileTV);
usernameTV = itemView.findViewById(R.id.usernameTV);
dateLastMesTV = itemView.findViewById(R.id.dateLastMesTV);
previewMessageTV = itemView.findViewById(R.id.previewMessageTV);
profileIV = itemView.findViewById(R.id.profileIV);
seenIV = itemView.findViewById(R.id.seenIV);
notSeenIV = itemView.findViewById(R.id.notSeenIV);
statusCV = itemView.findViewById(R.id.statusCV);
}
void bind(Message message, User user) {
statusCV.setVisibility(View.GONE);
if (message.isSeen()) {
seenIV.setVisibility(View.VISIBLE);
notSeenIV.setVisibility(View.GONE);
} else {
seenIV.setVisibility(View.GONE);
notSeenIV.setVisibility(View.VISIBLE);
}
usernameTV.setText(user.getUserName());
previewMessageTV.setText(message.getMessage());
showProfilePic(defaultProfileTV, profileIV, user);
formatDate(dateLastMesTV, message.getDate());
itemView.setOnClickListener(v -> openChat(user));
}
}
private void formatDate(TextView dateLastMesTV, String date) {
SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault());
Date currentDay =  new Date(System.currentTimeMillis());
Date chatDay = new Date(Long.parseLong(date));
if (formatter.format(currentDay).equals(formatter.format(chatDay))) {
dateLastMesTV.setText(
DateFormat.getTimeInstance(
DateFormat.SHORT,
Locale.getDefault()
).format(chatDay)
);
} else {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yy", Locale.getDefault());
dateLastMesTV.setText(dateFormat.format(Long.valueOf(date)));
}
}
private void showProfilePic(TextView defaultProfileTV, ImageView profileIV, User user) {
if (user.getImageURL().equals(Constants.KEY_IMAGE_URL_DEFAULT)) {
defaultProfileTV.setVisibility(View.VISIBLE);
defaultProfileTV.setText(user.getUserName().substring(0, 1));
} else {
profileIV.setVisibility(View.VISIBLE);
Glide.with(context)
.load(user.getImageURL())
.circleCrop()
.into(profileIV);
}
}
private void openChat(User user) {
Intent i = new Intent(context, ChatActivity.class);
i.putExtra(Constants.INTENT_USER, user);
context.startActivity(i);
}
}

SearchUserAdapter.java

public class SearchUserAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Context context;
private final Map<String, User> searchedUsers;
public SearchUserAdapter(Context context, Map<String, User> searchedUsers) {
this.context = context;
this.searchedUsers = searchedUsers;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_user_searched, parent, false);
return new SearchUserAdapter.UserHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
String key = (String) searchedUsers.keySet().toArray()[position];
((SearchUserAdapter.UserHolder) holder).bind(searchedUsers.get(key));
}
@Override
public int getItemCount() {
return searchedUsers.size();
}
class UserHolder extends RecyclerView.ViewHolder {
public ImageView profileIV;
public TextView defaultProfileTV, usernameTV, aboutTV;
public UserHolder(@NonNull View itemView) {
super(itemView);
defaultProfileTV = itemView.findViewById(R.id.defaultProfileTV);
usernameTV = itemView.findViewById(R.id.usernameTV);
aboutTV = itemView.findViewById(R.id.aboutTV);
profileIV = itemView.findViewById(R.id.profileIV);
}
void bind(User user) {
usernameTV.setText(user.getUserName());
aboutTV.setText(user.getAbout());
showProfilePic(defaultProfileTV, profileIV, user);
itemView.setOnClickListener(v -> openChat(user));
}
}
private void showProfilePic(TextView defaultProfileTV, ImageView profileIV, User user) {
if (user.getImageURL().equals(Constants.KEY_IMAGE_URL_DEFAULT)) {
defaultProfileTV.setVisibility(View.VISIBLE);
defaultProfileTV.setText(user.getUserName().substring(0, 1));
} else {
profileIV.setVisibility(View.VISIBLE);
Glide.with(context)
.load(user.getImageURL())
.circleCrop()
.into(profileIV);
}
}
private void openChat(User user) {
Intent i = new Intent(context, ChatActivity.class);
i.putExtra(Constants.INTENT_USER, user);
context.startActivity(i);
}
}

SearchUserFragment.java

public class SearchUserFragment extends Fragment {
private TextView notFoundTV;
private RecyclerView searchUserRV;
private MaterialCardView searchTipCV;
private Map<String, User> userMap;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_search_message, container, false);
notFoundTV = view.findViewById(R.id.notFoundTV);
searchTipCV = view.findViewById(R.id.searchTipCV);
refreshRV(view);
return view;
}
private void refreshRV(View view) {
userMap = new HashMap<>();
searchUserRV = view.findViewById(R.id.searchMessageRV);
searchUserRV.setHasFixedSize(true);
searchUserRV.setLayoutManager(new LinearLayoutManager(getContext()));
}
public void searchUser(String query) {
userMap.clear();
boolean isUserNameValid = true;
String finalQuery = query.trim();
if (finalQuery.isEmpty()) {
setViewsVisibility(View.GONE, View.VISIBLE, View.GONE);
isUserNameValid = false;
} else if (finalQuery.length() < 4 || !finalQuery.matches("^[a-zA-Z0-9]+$")) {
setViewsVisibility(View.GONE, View.VISIBLE, View.GONE);
isUserNameValid = false;
}
if (isUserNameValid) {
FirebaseDatabase.getInstance().getReference()
.child(KEY_COLLECTION_USER)
.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
User user = snapshot.getValue(User.class);
if (user.getUserName().equals(CURRENT_USER.getUserName())) continue;
if (user.getUserName().toLowerCase().startsWith(finalQuery.toLowerCase())) {
userMap.put(user.getId(), user);
}
checkList();
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) { }
});
}
}
private void setViewsVisibility(int searchVis, int searchTipVis, int notFoundVis) {
searchUserRV.setVisibility(searchVis);
searchTipCV.setVisibility(searchTipVis);
notFoundTV.setVisibility(notFoundVis);
}
private void checkList() {
if (userMap.size() > 0) {
refreshRV(userMap);
setViewsVisibility(View.VISIBLE, View.GONE, View.GONE);
} else {
setViewsVisibility(View.GONE, View.GONE, View.VISIBLE);
}
}
private void refreshRV(@NotNull Map<String, User> userMap) {
SearchUserAdapter searchUserAdapter = new SearchUserAdapter(
getContext(),
userMap
);
searchUserRV.setAdapter(searchUserAdapter);
}
}

SearchMessageFragment.java

public class SearchMessageFragment extends Fragment {
private final DatabaseReference messagesReference = FirebaseDatabase.getInstance().getReference()
.child(KEY_COLLECTION_MESSAGE);
private final DatabaseReference usersReference = FirebaseDatabase.getInstance().getReference()
.child(KEY_COLLECTION_USER);
private TextView notFoundTV;
private RecyclerView searchMessageRV;
private MaterialCardView searchTipCV;
private List<Message> messageList;
private List<User> userList;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
if (savedInstanceState != null) {
searchMessage(getArguments().getString(BUNDLE_SEARCH));
}*/
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_search_message, container, false);
notFoundTV = view.findViewById(R.id.notFoundTV);
searchTipCV = view.findViewById(R.id.searchTipCV);
setupRV(view);
return view;
}
private void setupRV(View view) {
messageList = new ArrayList<>();
userList = new ArrayList<>();
searchMessageRV = view.findViewById(R.id.searchMessageRV);
searchMessageRV.setHasFixedSize(true);
searchMessageRV.setLayoutManager(new LinearLayoutManager(getContext()));
}
public void searchMessage(String query) {
messageList = new ArrayList<>();
userList = new ArrayList<>();
messagesReference.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
boolean doesMessageFitQuery = false;
Message message = snapshot.getValue(Message.class);
String[] wordsFromMessage = message.getMessage().split(" ");
int i;
for (i = 0; i < wordsFromMessage.length; i++) {
if (wordsFromMessage[i].toLowerCase().startsWith(query.trim().toLowerCase())) {
doesMessageFitQuery = true;
break;
}
}
if (doesMessageFitQuery
&& (message.getSenderID().equals(CURRENT_USER.getId())
|| message.getReaderID().equals(CURRENT_USER.getId()))) {
String searchUserID;
if (message.getReaderID().equals(CURRENT_USER.getId())) {
searchUserID = message.getSenderID();
} else {
searchUserID = message.getReaderID();
}
messageList.add(message);
usersReference.child(searchUserID).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
User user = snapshot.getValue(User.class);
userList.add(user);
checkList();
}
@Override
public void onCancelled(@NonNull DatabaseError error) { }
});
} else {
setViewsVisibility(View.GONE, View.GONE, View.VISIBLE);
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) { }
});
}
private void setViewsVisibility(int searchVis, int searchTipVis, int notFoundVis) {
searchMessageRV.setVisibility(searchVis);
searchTipCV.setVisibility(searchTipVis);
notFoundTV.setVisibility(notFoundVis);
}
private void checkList() {
if (messageList.size() > 0) {
refreshRV(messageList, userList);
setViewsVisibility(View.VISIBLE, View.GONE, View.GONE);
} else {
setViewsVisibility(View.GONE, View.GONE, View.VISIBLE);
}
}
private void refreshRV(@NotNull List<Message> searchedMessages,
@NotNull List<User> searchedMessagesUsers) {
SearchMessageAdapter searchMessageAdapter = new SearchMessageAdapter(
getContext(),
searchedMessages,
searchedMessagesUsers
);
searchMessageRV.setAdapter(searchMessageAdapter);
}
}

我完全意识到一些代码的两面性,但重构并不是我现在主要关心的问题。问题是搜索功能目前运行良好。

最新更新