【问题标题】:One Map and two Lists on a RecyclerView adapterRecyclerView 适配器上的一个 Map 和两个 List
【发布时间】:2021-05-21 16:37:42
【问题描述】:

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

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

鉴于上述细节,我希望能够完美地展示这两个项目。这是代码: 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

【问题讨论】:

    标签: android android-recyclerview android-adapter


    【解决方案1】:

    几天后,我想出了一个解决方法。我已将结构更改为更简单的结构,即使这意味着更多代码。我在 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);
        }
    }
    

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

    【讨论】:

      猜你喜欢
      • 2017-07-15
      • 2017-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-22
      • 1970-01-01
      相关资源
      最近更新 更多