Android 自定义Adapter关键函数getView性能最优使用

文章目录

在Android开发中,自定义Adapter是非常常见的,用于为ListView、GridView、RecyclerView等视图提供数据。自定义Adapter的关键函数是 getView()方法,它负责为每一项数据创建和返回一个View。以下是一个标准的自定义Adapter及其 getView()方法的详细用例和解释。

1、自定义Adapter关键函数getView()标准写法

假设我们有一个简单的用户数据类:

java 复制代码
public class User {
    private String name;
    private String email;

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }
}

自定义Adapter的实现:

java 复制代码
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

public class UserAdapter extends BaseAdapter {
    private Context context;
    private List<User> userList;
    private LayoutInflater inflater;

    public UserAdapter(Context context, List<User> userList) {
        this.context = context;
        this.userList = userList;
        this.inflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return userList.size();
    }

    @Override
    public Object getItem(int position) {
        return userList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;

        if (convertView == null) {
            // Inflate the custom layout
            convertView = inflater.inflate(R.layout.list_item_user, parent, false);

            // Initialize the ViewHolder
            viewHolder = new ViewHolder();
            viewHolder.nameTextView = convertView.findViewById(R.id.nameTextView);
            viewHolder.emailTextView = convertView.findViewById(R.id.emailTextView);

            // Store the holder with the view
            convertView.setTag(viewHolder);
        } else {
            // Retrieve the view holder
            viewHolder = (ViewHolder) convertView.getTag();
        }

        // Get the current user
        User currentUser = (User) getItem(position);

        // Set the user details to the view
        viewHolder.nameTextView.setText(currentUser.getName());
        viewHolder.emailTextView.setText(currentUser.getEmail());

        return convertView;
    }

    // ViewHolder pattern to optimize list view performance
    static class ViewHolder {
        TextView nameTextView;
        TextView emailTextView;
    }
}

2、布局文件list_item_user.xml

这是自定义的布局文件,定义了每个列表项的布局:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="8dp">

    <TextView
        android:id="@+id/nameTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:textColor="@android:color/black" />

    <TextView
        android:id="@+id/emailTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="14sp"
        android:textColor="@android:color/darker_gray" />

</LinearLayout>

3、解释

  1. ViewHolder模式

    • ViewHolder是一个静态内部类,用来缓存View。这样避免了每次调用getView()方法时都调用findViewById()方法,提高了ListView的性能。
  2. getView()方法

    • convertView参数是用于重用旧视图的。为了性能优化,如果convertView不为null,则可以重用。
    • 如果convertView为null,意味着这是第一次创建这个视图,需要使用LayoutInflater去加载布局,并初始化ViewHolder
    • 使用convertView.setTag(viewHolder)来存储ViewHolder对象,方便后续重用。
    • 使用convertView.getTag()来获取缓存的ViewHolder对象,避免重复调用findViewById()
    • 最后,将当前项的数据设置到ViewHolder中的各个控件上。

3、示例使用

假设在某个Activity中使用这个Adapter:

java 复制代码
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ListView listView = findViewById(R.id.listView);

        // 示例数据
        List<User> users = new ArrayList<>();
        users.add(new User("Alice", "alice@example.com"));
        users.add(new User("Bob", "bob@example.com"));

        // 设置自定义Adapter
        UserAdapter adapter = new UserAdapter(this, users);
        listView.setAdapter(adapter);
    }
}

4、结果

运行应用时,ListView将显示用户列表,每行包含用户名和电子邮件地址。通过使用ViewHolder模式,确保了列表的高效滚动和视图重用。

5、进一步优化和扩展

5.1. 优化性能:ViewHolder模式

在大数据集的情况下,ViewHolder模式是非常重要的优化技术。它通过缓存View引用,减少了不必要的视图查找操作。

java 复制代码
// Adapter类中
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder viewHolder;

    if (convertView == null) {
        // Inflate the custom layout
        convertView = inflater.inflate(R.layout.list_item_user, parent, false);

        // Initialize the ViewHolder
        viewHolder = new ViewHolder();
        viewHolder.nameTextView = convertView.findViewById(R.id.nameTextView);
        viewHolder.emailTextView = convertView.findViewById(R.id.emailTextView);

        // Store the holder with the view
        convertView.setTag(viewHolder);
    } else {
        // Retrieve the view holder
        viewHolder = (ViewHolder) convertView.getTag();
    }

    // Get the current user
    User currentUser = (User) getItem(position);

    // Set the user details to the view
    viewHolder.nameTextView.setText(currentUser.getName());
    viewHolder.emailTextView.setText(currentUser.getEmail());

    return convertView;
}

// ViewHolder pattern to optimize list view performance
static class ViewHolder {
    TextView nameTextView;
    TextView emailTextView;
}

5.2. 处理多种类型的视图

有时我们需要在一个列表中展示不同类型的视图,可以通过覆盖getViewTypeCount()getItemViewType(int position)来实现。

java 复制代码
@Override
public int getViewTypeCount() {
    // 两种不同的视图类型
    return 2;
}

@Override
public int getItemViewType(int position) {
    User user = (User) getItem(position);
    if (user.isSpecialUser()) {
        return 0; // 特殊用户类型
    } else {
        return 1; // 普通用户类型
    }
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    int viewType = getItemViewType(position);
    ViewHolder viewHolder;

    if (convertView == null) {
        switch (viewType) {
            case 0:
                // 特殊用户视图
                convertView = inflater.inflate(R.layout.special_user_item, parent, false);
                viewHolder = new SpecialViewHolder();
                viewHolder.specialTextView = convertView.findViewById(R.id.specialTextView);
                break;
            case 1:
                // 普通用户视图
                convertView = inflater.inflate(R.layout.list_item_user, parent, false);
                viewHolder = new ViewHolder();
                viewHolder.nameTextView = convertView.findViewById(R.id.nameTextView);
                viewHolder.emailTextView = convertView.findViewById(R.id.emailTextView);
                break;
        }
        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }

    // 填充数据
    User currentUser = (User) getItem(position);
    if (viewType == 0) {
        ((SpecialViewHolder) viewHolder).specialTextView.setText(currentUser.getSpecialInfo());
    } else {
        viewHolder.nameTextView.setText(currentUser.getName());
        viewHolder.emailTextView.setText(currentUser.getEmail());
    }

    return convertView;
}

// 普通ViewHolder
static class ViewHolder {
    TextView nameTextView;
    TextView emailTextView;
}

// 特殊用户ViewHolder
static class SpecialViewHolder extends ViewHolder {
    TextView specialTextView;
}

5.3. 使用RecyclerView.Adapter

如果你的项目使用RecyclerView,而不是ListView或GridView,可以使用RecyclerView.Adapter来实现自定义Adapter。RecyclerView比ListView更强大和灵活,并且内置了ViewHolder模式。

java 复制代码
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHolder> {
    private List<User> userList;

    public UserAdapter(List<User> userList) {
        this.userList = userList;
    }

    @Override
    public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.list_item_user, parent, false);
        return new UserViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(UserViewHolder holder, int position) {
        User currentUser = userList.get(position);
        holder.nameTextView.setText(currentUser.getName());
        holder.emailTextView.setText(currentUser.getEmail());
    }

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

    public static class UserViewHolder extends RecyclerView.ViewHolder {
        public TextView nameTextView;
        public TextView emailTextView;

        public UserViewHolder(View view) {
            super(view);
            nameTextView = view.findViewById(R.id.nameTextView);
            emailTextView = view.findViewById(R.id.emailTextView);
        }
    }
}

6、RecyclerView使用示例

java 复制代码
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RecyclerView recyclerView = findViewById(R.id.recyclerView);

        // 示例数据
        List<User> users = new ArrayList<>();
        users.add(new User("Alice", "alice@example.com"));
        users.add(new User("Bob", "bob@example.com"));

        // 设置布局管理器
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        // 设置自定义Adapter
        UserAdapter adapter = new UserAdapter(users);
        recyclerView.setAdapter(adapter);
    }
}

7、结果

在使用RecyclerView时,列表项的视图会更高效地被管理和重用,提供更平滑的滚动体验。

8、结论

无论是ListView还是RecyclerView,自定义Adapter的getView()方法(或onBindViewHolder()方法)都是核心部分,负责创建和绑定视图。使用ViewHolder模式可以显著提高性能。对于复杂的列表,可以通过实现不同的视图类型来满足需求。RecyclerView提供了更灵活和高效的实现,推荐在新的项目中使用。

相关推荐
前端青山2 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
帅得不敢出门5 小时前
安卓设备adb执行AT指令控制电话卡
android·adb·sim卡·at指令·电话卡
我又来搬代码了7 小时前
【Android】使用productFlavors构建多个变体
android
青云交8 小时前
大数据新视界 -- 大数据大厂之 Impala 性能优化:应对海量复杂数据的挑战(上)(7/30)
大数据·性能优化·impala·数据分区·查询优化·海量复杂数据·经典案例
德育处主任9 小时前
Mac和安卓手机互传文件(ADB)
android·macos
芦半山9 小时前
Android“引用们”的底层原理
android·java
迃-幵9 小时前
力扣:225 用队列实现栈
android·javascript·leetcode
大风起兮云飞扬丶10 小时前
Android——从相机/相册获取图片
android
Rverdoser10 小时前
Android Studio 多工程公用module引用
android·ide·android studio
aaajj10 小时前
[Android]从FLAG_SECURE禁止截屏看surface
android