当前位置: 首页 > 知识库问答 >
问题:

更新RecyclerView数据会降低activity UI的速度

易书
2023-03-14

我正在处理一个聊天应用程序,我有一些问题显示聊天消息。对于存储,我使用了一个Room数据库,为了显示消息,我使用了一个RecyclerView。问题是,activity变得非常慢,在滚动信息时没有那么好的响应。

下面是我的代码:

ChatActivity.java

public class ChatActivity extends AppCompatActivity {
    public static final String TAG = ChatActivity.class.getSimpleName();

    public static Contact contact;
    public static boolean isContactConnected;

    private CircleImageView mContactPicture;
    private ImageView mContactConnected;
    private TextView mContactName;
    private TextView mContactStatus;

    private ChatAdapter mChatAdapter;
    private RecyclerView mRecyclerView;

    private EmojiconEditText mUserMessageInput;

    private View rootView;
    private ImageView emojiImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat);

        initializeToolbar();

        String contactPhone = Objects.requireNonNull(getIntent().getStringExtra("phone"));
        contact = MainActivity.db.getContactDao().findByPhone(contactPhone);

        if (MainActivity.notificationMessages.get(contact.getId()) != null) {
            MainActivity.notificationMessages.put(contact.getId(), new ArrayList<Message>());
        }

        updateUI(contact);
        initializeViews();
        initializeRecyclerView();

        EmojIconActions emojIconActions = new EmojIconActions(this, rootView, mUserMessageInput, emojiImageView);
        emojIconActions.ShowEmojIcon();
        emojIconActions.setIconsIds(R.drawable.ic_baseline_keyboard_24, R.drawable.ic_baseline_emoji_emotions_24);

        mChatAdapter = new ChatAdapter(this, new ArrayList<Message>());
        mRecyclerView.setAdapter(mChatAdapter);

        MainActivity.db.getMessageDao().getLiveMessages(contactPhone).observe(this, new Observer<List<Message>>() {
            @Override
            public void onChanged(List<Message> newMessages) {
                mChatAdapter.setMessages(newMessages);
                mRecyclerView.scrollToPosition(newMessages.size() - 1);
            }
        });
    }

    [...]

    private void updateUI(Contact contact) {
        mContactName.setText(contact.getName());

        if (!contact.isConnected()) {
            Date currentTime = Calendar.getInstance().getTime();
            SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm", Locale.US);

            isContactConnected = false;
            mContactStatus.setText(
                    String.format(
                            "Last seen %s",
                            DateManager.getLastActiveText(
                                    df.format(currentTime),
                                    contact.getLastActive()
                            )
                    )
            );

            mContactConnected.setVisibility(View.GONE);

            Log.d(TAG, "updateUI: initialized contact UI as disconnected");
        } else {
            mContactStatus.setText(R.string.active_now);
            mContactConnected.setVisibility(View.VISIBLE);
            isContactConnected = true;

            Log.d(TAG, "updateUI: initialized contact UI as connected");
        }

        if (contact.getPhotoUri() != null) {
            Uri imageUri = Uri.parse(contact.getPhotoUri());

            try {
                Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), imageUri);
                mContactPicture.setImageBitmap(bitmap);

                Log.d(TAG, "updateUI: loaded contact photo from device");
            } catch (IOException e) {
                Toast.makeText(
                        ChatActivity.this,
                        "Failed to load image from device.",
                        Toast.LENGTH_SHORT
                ).show();

                e.printStackTrace();
            }
        }
    }

    [...]

    private void initializeRecyclerView() {
        mRecyclerView = findViewById(R.id.chat_recycler_view);

        RecyclerView.LayoutManager layoutManager =
                new LinearLayoutManager(ChatActivity.this, LinearLayoutManager.VERTICAL, false);
        mRecyclerView.setLayoutManager(layoutManager);

        Log.d(TAG, "initializeRecyclerView: initialized RecyclerView");
    }

    [...]
}

AppDatabase.java

@Database(entities = {Contact.class, Message.class}, version = 1)
@TypeConverters({Converters.class})
public abstract class AppDatabase extends RoomDatabase {
    public abstract ContactDao getContactDao();

    public abstract MessageDao getMessageDao();
}

MessageDao.java

@Dao
public interface MessageDao {
    @Query("SELECT * FROM messages WHERE to_from = :contact ORDER BY timestamp")
    List<Message> getMessages(String contact);

    @Query("SELECT * FROM messages WHERE to_from = :contact ORDER BY timestamp")
    LiveData<List<Message>> getLiveMessages(String contact);

    @Query("SELECT * FROM messages WHERE to_from =:contact AND status = 0")
    List<Message> getUndeliveredMessages(String contact);

    @Query("SELECT * FROM messages WHERE payloadId = :payloadId LIMIT 1")
    Message getMessageByPayloadId(long payloadId);

    @Query("SELECT * FROM messages WHERE to_from = :contact ORDER BY timestamp DESC LIMIT 1")
    Message getLastMessage(String contact);

    @Query("SELECT * FROM messages WHERE to_from = :contact ORDER BY timestamp DESC LIMIT 1")
    LiveData<Message> getLastLiveMessage(String contact);

    @Query("DELETE FROM messages")
    void deleteAllMessages();

    @Insert
    void addMessage(Message message);

    @Update
    void updateMessage(Message message);

    @Delete
    void deleteMessage(Message message);
}

ChatAdapter.java

public class ChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private Context mContext;
    private List<Message> messages;

    public ChatAdapter(Context context, List<Message> messages) {
        this.mContext = context;
        this.messages = messages;
    }

    @Override
    public int getItemViewType(int position) {
        Message message = messages.get(position);

        int status = message.getStatus();

        if (status == Message.RECEIVED) {
            return 0;
        } else {
            return 1;
        }
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (viewType == 0) {
            View itemView = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.chat_message_item, parent, false);

            return new ChatUserViewHolder(itemView);
        }

        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.chat_message_item2, parent, false);

        return new ChatOtherViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        Message currentMessage = messages.get(position);

        String messageContent = currentMessage.getContent();
        Date date = currentMessage.getTimestamp();
        SimpleDateFormat ft = new SimpleDateFormat("dd/MM/yyyy HH:mm", Locale.US);

        Date currentDate = Calendar.getInstance().getTime();

        switch (getItemViewType(position)) {
            case 0:
                ChatUserViewHolder mHolder = (ChatUserViewHolder) holder;

                Contact sender = MainActivity.db.getContactDao().findByPhone(currentMessage.getToFrom());

                if (sender.getPhotoUri() != null) {
                    Uri imageUri = Uri.parse(sender.getPhotoUri());

                    try {
                        Bitmap bitmap = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), imageUri);
                        mHolder.getSenderProfilePicture().setImageBitmap(bitmap);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                mHolder.getSenderName().setText(sender.getName());
                mHolder.getMessageContent().setText(messageContent);
                mHolder.getTimestamp().setText(DateManager.getLastActiveText(ft.format(currentDate), ft.format(date)));
                break;

            case 1:
                ChatOtherViewHolder nHolder = (ChatOtherViewHolder) holder;

                SharedPreferences sharedPreferences = mContext.getSharedPreferences("LOGIN_DETAILS", MODE_PRIVATE);

                String name = sharedPreferences.getString("name", "");
                String photoUri = sharedPreferences.getString("photoUri", null);

                if (photoUri != null) {
                    Uri imageUri = Uri.parse(photoUri);

                    try {
                        Bitmap bitmap = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), imageUri);
                        nHolder.getSenderProfilePicture().setImageBitmap(bitmap);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                nHolder.getSenderName().setText(name);
                nHolder.getMessageContent().setText(messageContent);
                nHolder.getTimestamp().setText(DateManager.getLastActiveText(ft.format(currentDate), ft.format(date)));

                if (currentMessage.getStatus() == Message.SENT) {
                    nHolder.getMessageStatus().setImageResource(R.drawable.ic_baseline_done_24);
                } else {
                    nHolder.getMessageStatus().setImageResource(R.drawable.ic_baseline_done_all_24);
                }

                break;

            default:
                break;
        }

    }

    @Override
    public int getItemCount() {
        return messages.size();
    }

    public void setMessages(List<Message> messages) {
        if (this.messages.size() > 0) {
            this.messages.clear();
        }

        this.messages = messages;
        notifyDataSetChanged();
    }

ChatitemViewWholder.java

class ChatItemViewHolder extends RecyclerView.ViewHolder {
    private CircleImageView mUserProfilePic;
    private ImageView mUserStatus;
    private TextView mUserProfileName;
    private EmojiconTextView mLastMessage;
    private TextView mTimestamp;

    public ChatItemViewHolder(@NonNull View itemView) {
        super(itemView);

        mUserProfilePic = itemView.findViewById(R.id.contact_image_item);
        mUserProfileName = itemView.findViewById(R.id.contact_name_item);
        mUserStatus = itemView.findViewById(R.id.status);
        mLastMessage = itemView.findViewById(R.id.contact_status_item);
        mTimestamp = itemView.findViewById(R.id.timestamp);
    }

    public CircleImageView getUserProfilePic() {
        return mUserProfilePic;
    }

    public ImageView getUserStatus() {
        return mUserStatus;
    }

    public TextView getUserProfileName() {
        return mUserProfileName;
    }

    public EmojiconTextView getLastMessage() {
        return mLastMessage;
    }

    public TextView getTimestamp() {
        return mTimestamp;
    }
}

chatotherviewholder.java

class ChatOtherViewHolder extends RecyclerView.ViewHolder {
    private CircleImageView mSenderProfilePicture;
    private TextView mSenderName;
    private EmojiconTextView mMessageContent;
    private TextView mTimestamp;
    private ImageView mMessageStatus;

    public ChatOtherViewHolder(@NonNull View itemView) {
        super(itemView);

        mSenderProfilePicture = itemView.findViewById(R.id.sender_profile_pic);
        mSenderName = itemView.findViewById(R.id.sender_name);
        mMessageContent = itemView.findViewById(R.id.message_content);
        mTimestamp = itemView.findViewById(R.id.message_timestamp);
        mMessageStatus = itemView.findViewById(R.id.message_status);
    }

    public CircleImageView getSenderProfilePicture() {
        return mSenderProfilePicture;
    }

    public TextView getSenderName() {
        return mSenderName;
    }

    public EmojiconTextView getMessageContent() {
        return mMessageContent;
    }

    public TextView getTimestamp() {
        return mTimestamp;
    }

    public ImageView getMessageStatus() {
        return mMessageStatus;
    }
}

显然问题出在房车上。最初我认为在UI线程上运行的observe方法可能会导致问题,但我替换了onChanged方法中的操作,UI非常流畅,所以只有在尝试更新RV项时才会出现问题。

我能做些什么来解决这个问题?

共有1个答案

宰父淳
2023-03-14

我看到了两个大问题

>

  • 永远不要在适配器中进行数据库调用,数据库调用在适配器中使用太贵了。

    您还可以将整个位图加载到内存中,使用像Glide这样的图像加载库来加载图像,它们处理回收的视图,并将图像调整到所需的大小,同时进行异步加载

  •  类似资料:
    • 问题内容: 我之所以这样问是因为我使用Python,但是它也可以应用于其他解释语言(Ruby,PHP,JavaScript)。 每当我在代码中留下评论时,我是否会放慢解释器的速度?根据我对解释器的有限了解,它以字符串形式读取程序表达式,然后将这些字符串转换为代码。似乎每次解析评论时都是浪费时间。 是这样吗 是否有一些解释性语言的注释约定,或者其影响可以忽略不计? 问题答案: 对于Python而言,

    • RecycerView只显示创建时ArrayList(适配器的数据)中的项。我所有添加更多行的尝试似乎都奏效了,但列表仍然是初始数据。它不是重复的,因为我尝试了谷歌上找到的所有建议。我已经做了什么: Adapter.NotifyDataSetChanged(); Adapter.NotifyItemChanged(5); recyleList.invalidate(); recyclelist.s

    • 我使用ElasticSearch 5.6。 运行快照时,我运行http://localhost:9200/_cluster/health但在10秒以上没有得到回应。我还可以看到,当快照运行时,机器在磁盘/网络IO方面有很多成本。 如果我不运行快照,这样的延迟不会发生。 我用超时检查_cluster/健康状况,以确保创建快照不会减慢查询速度。这是检查的正确方法吗?在实践中,创建快照会使查询变慢吗?

    • 我正在从ListView迁移到RecyclerView,但是在SQLite中输入一些数据之后,我的列表没有使用notifyDataSetChanged()更新;所以我总是必须调用setAdapter()方法; 回收器ViewAdapter 观赏者 模型

    • > 从创建的片段中更新,将新数据设置为adapter,然后调用;但没有奏效。 像其他人一样创建一个新适配器,它对他们起作用,但对我没有任何改变: 在中创建一个更新数据的方法,如下所示: 问题是gridView的布局如下所示: 然后我只是删除了并将作为父布局。

    • 试图弄清楚更新的适配器有什么问题。 在我得到一个新的产品列表后,我尝试: > 从创建的片段中更新,将新数据设置到adapter,然后调用;但没有奏效。 像其他人一样创建一个新适配器,它对他们有效,但对我没有任何改变: 在中创建一个更新数据的方法,如下所示: 然后每当我想要更新数据列表时,我就调用这个方法;但没有奏效。 检查是否可以以任何方式修改recyclerView,并且我尝试至少删除一个项目: