多个适配器或一个适配器用于不同的列表和对象 - 代码性能

Posted

技术标签:

【中文标题】多个适配器或一个适配器用于不同的列表和对象 - 代码性能【英文标题】:Multiple Adapters or One Adapter for different lists and objects - Code Performance 【发布时间】:2019-04-06 13:34:25 【问题描述】:

就性能而言,在 android 应用中实现的更好选择:

为每个具有不同对象的单个列表的多个适配器 布局, 处理不同数据的单个适配器。

假设我们需要创建

评论,

视频,

问题

适配器中的列表以正确显示数据。每个列表属于不同的布局,所以我们有不同的TextViewsImageViews等等。

公共类 FilesAdapter 扩展 RecyclerView.Adapter

public static final int VIDEO_FILES_ADAPTER = 1; 公共静态最终诠释 COMMENT_ADAPTER = 2; public static final int QUESTIONS_ADAPTER = 3;

private int CURRENT_ADAPTER;

私人列表视频文件; 私有列表 cmets; 私人列表问题;

boolean isForUser;

public FilesAdapter(int currentAdapter, List videoFiles, boolean isForUser) this.videoFiles = 视频文件; this.CURRENT_ADAPTER = 当前适配器; this.isForUser = isForUser;

public FilesAdapter(int currentAdapter, List cmets) this.cmets = cmets; this.CURRENT_ADAPTER = 当前适配器;

public FilesAdapter(int currentAdapter, List questions, int usedVariable) this.questions = 问题; this.CURRENT_ADAPTER = 当前适配器;

@NonNull @覆盖 public FilesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 查看视图; FilesViewHolder viewHolder;

switch(CURRENT_ADAPTER)

    case VIDEO_FILES_ADAPTER:

        if(isForUser)
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_layout_file_user, parent, false);
        else
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_layout_file_main, parent, false);
        

        viewHolder = new FilesViewHolder(VIDEO_FILES_ADAPTER, view, isForUser);

        return viewHolder;

    case COMMENT_ADAPTER:
        view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_layout_comment, parent, false);
        viewHolder = new FilesViewHolder(COMMENT_ADAPTER, view, false);

        return viewHolder;

    case QUESTIONS_ADAPTER:
        view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_layout_question, parent, false);
        viewHolder = new FilesViewHolder(QUESTIONS_ADAPTER, view, false);

        return viewHolder;


return null;

@覆盖 public void onBindViewHolder(@NonNull FilesViewHolder holder, int position)

switch (CURRENT_ADAPTER)

    case VIDEO_FILES_ADAPTER:
        holder.videoTitle.setText(videoFiles.get(position).getFileName());
        holder.videoDescription.setText(videoFiles.get(position).getFileDescription());
        if(isForUser)
            holder.videoDate.setText(videoFiles.get(position).getFileCreatedAt());
        else
            holder.videoUser.setText(videoFiles.get(position).getUsername());
        

        holder.videoCount.setText(videoFiles.get(position).getWatched());
        break;

    case COMMENT_ADAPTER:
        holder.commentComment.setText(comments.get(position).getComment());
        holder.commentUsername.setText(comments.get(position).getUsername());
        holder.commentCreatedAt.setText(comments.get(position).getCreatedAt());
        break;

    case QUESTIONS_ADAPTER:
        holder.questionTitle.setText(questions.get(position).getProviderUsername());
        break;

@覆盖 公共 int getItemCount()

switch (CURRENT_ADAPTER)
    case VIDEO_FILES_ADAPTER:
        return videoFiles.size();
    case COMMENT_ADAPTER:
        return comments.size();
    case QUESTIONS_ADAPTER:
        return questions.size();


return 0;

公共静态类 FilesViewHolder 扩展 RecyclerView.ViewHolder

private static final int VIDEO_FILES_ADAPTER = 1;
private static final int COMMENT_ADAPTER = 2;
private static final int QUESTIONS_ADAPTER = 3;

private int CURRENT_ADAPTER;

// Related to audio file class
public TextView videoTitle, videoDescription, videoDate, videoUser, videoCount;

// Related to comment class
private TextView commentComment, commentUsername, commentCreatedAt;

// Related to subscription class
private TextView questionTitle;


// @param isForUser applies only if CURRENT_ADAPTER == VIDEO_FILES_ADAPTER
public FilesViewHolder(int CURRENT_ADAPTER, View itemView, boolean isForUser) 
    super(itemView);

    switch(CURRENT_ADAPTER)

        case VIDEO_FILES_ADAPTER:

            videoTitle = itemView.findViewById(R.id.tV_title);
            videoDescription = itemView.findViewById(R.id.tV_description);
            if(isForUser)
                videoDate = itemView.findViewById(R.id.tV_date);
            else
                videoUser = itemView.findViewById(R.id.tV_username);
            
            videoCount = itemView.findViewById(R.id.tV_watched);

            break;

        case COMMENT_ADAPTER:

            commentComment = itemView.findViewById(R.id.tV_comment);
            commentUsername = itemView.findViewById(R.id.tV_comment_username);
            commentCreatedAt = itemView.findViewById(R.id.tV_comment_created_at);

            break;

        case QUESTIONS_ADAPTER:

            questionTitle = itemView.findViewById(R.id.tV_question);

            break;
    


还有另一种方法可以做到这一点。 每个列表的单个适配器,例如:

public class CommentAdapter extends RecyclerView.Adapter<CommentAdapter.CommentViewHolder>

private List<Comment> commentList;

public CommentAdapter(List<Comment> comments)
    this.commentList = comments;


public static class CommentViewHolder extends RecyclerView.ViewHolder

    private TextView comment, username, createdAt;

    public CommentViewHolder(View itemView) 
        super(itemView);

        comment = itemView.findViewById(R.id.tV_comment);
        username = itemView.findViewById(R.id.tV_comment_username);
        createdAt = itemView.findViewById(R.id.tV_comment_created_at);
    


@NonNull
@Override
public CommentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_layout_comment, parent, false);

    return new CommentViewHolder(view);


@Override
public void onBindViewHolder(@NonNull CommentViewHolder holder, int position) 
    holder.comment.setText(commentList.get(position).getComment());
    holder.username.setText(commentList.get(position).getUsername());
    holder.createdAt.setText(commentList.get(position).getCreatedAt());


@Override
public int getItemCount() 
    return commentList.size();

我的问题是在性能方面什么会更好实施?如果我决定为不同的列表实现一个适配器,是否会出现明显的性能延迟或补丁?

【问题讨论】:

【参考方案1】:

无论您的布局和处理附加到单元格的复杂性如何,我都建议您为每个列表使用单个适配器。

一张小图说明 RecyclerView 的主要操作: RecyclerView operation

根据 RecyclerView.Adapter 的documentation :当必须创建新的可重用单元格时调用方法createViewHolder()(取决于屏幕上可以显示的单元格数量)。因此,执行 if 语句不会对性能产生太大影响。如果屏幕上显示 10 个单元格,onCreateViewHolder() 可能会被调用多 10 次。 问题可能出在每次 RecyclerView 需要显示新单元格时调用的 onBindViewHolder() 上。因此,如果您有一个包含 100 个元素的列表并且您的用户跳到底部,那么系统将执行 100 个 if 语句。

此外,我认为如果您为每个列表制作单个适配器,您的代码将更易于维护。

我将得出结论,即我不确定系统是否会因为使用一个适配器为整个应用程序而降低效率。性能损失将不明显。我的意思是,最重要的一点是确保您的代码易于理解,否则您将来会浪费时间调试代码。我建议您通过在 onCreateViewHolderonBindViewHolder 上设置断点来测试 RecyclerView 生命周期(如果您好奇的话,还可以设置更多)以了解它们何时被调用。

希望对你有帮助! 祝你好运,玩得开心你的应用

【讨论】:

以上是关于多个适配器或一个适配器用于不同的列表和对象 - 代码性能的主要内容,如果未能解决你的问题,请参考以下文章

带有适配器的 Android 列表视图仅显示第一项(多次)

Android 插件化VirtualApp 源码分析 ( 添加应用源码分析 | LaunchpadAdapter 适配器 | 适配器添加元素 | PackageAppData 元素 )(代

ArrayIndexOutOfBoundsException 与 ListView 中的多个视图的自定义 Android 适配器

具有多个子项目的项目列表的自定义适配器?

如何处理 ListView 中的多个倒数计时器?

将对象的嵌套数组列表从适配器传递到活动