原创

Android适配器RecyclerView.Adapter和ArrayAdapter的使用

前言

适配器有什么用?

简单来说就是连接View和数据的桥梁。

如果用MVC模式来理解的话,可以这么理解:

Model(我们的数据) ---> Controller(适配器Adapter)---> View(Android用户界面)

RecyclerView.Adapter(RecyclerView)

Android 5.0时提供了RecyclerView这个列表元件,作为ListView的强化版,它提供更好的效能表现、更高的灵活性,博客有文章将其称为艺术般的元件。

RecyclerView要求必须使用ViewHolder模式,一般我们在使用过程中,都需要去建立一个新的ViewHolder然后作为泛型传入Adapter。

简单的Demo

先写一个MenuProgressAdapterRecyclerView适配器:

public class MenuProgressAdapter extends RecyclerView.Adapter<MenuProgressAdapter.ViewHolder> {
    private Context context;
    private List<MenuProgress> data;
    private DebugTaskModel debugTask;

    public MenuProgressAdapter(Context context, List<MenuProgress> data, DebugTaskModel debugTask) {
        this.context = context;
        this.data = data;
        this.debugTask = debugTask;
    }

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

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        MenuProgress menuProgress = data.get(position);

        holder.menuProgressItem = menuProgress;

        holder.itemId.setText(data.get(position).getId());
        holder.itemName.setText(data.get(position).getTitle());

        if (menuProgress.isFinish()) {
            holder.testFinish.setVisibility(View.VISIBLE);
            holder.testTodo.setVisibility(View.GONE);
        } else {
            holder.testFinish.setVisibility(View.GONE);
            holder.testTodo.setVisibility(View.VISIBLE);
        }

        // 为每个Item添加点击事件
        holder.itemView.setOnClickListener(v -> {
            if (DoubleClickUtil.doubleClick()) {
                Toast.makeText(context, DOUBLE_CLICK_PROMPT, Toast.LENGTH_LONG).show();
                return;
            }

            // 获取被点击之后的MenuProgress
            MenuProgress item = data.get(position);

            // 点击之后的业务逻辑...

        });
    }

    @Override
    public int getItemCount() {
        if (data == null) {
            return 0;
        }
        return data.size();
    }

    public void clear() {
        if (data != null) {
            data.clear();
        }
        notifyDataSetChanged();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        public final View mView;

        public final ImageView testFinish;
        public final ImageView testTodo;

        public final TextView itemId;
        public final TextView itemName;

        public MenuProgress menuProgressItem;

        public ViewHolder(View view) {
            super(view);
            this.mView = view;
            this.testFinish = itemView.findViewById(R.id.testFinish);
            this.testTodo = itemView.findViewById(R.id.testTodo);
            this.itemId = itemView.findViewById(R.id.itemId);
            this.itemName = itemView.findViewById(R.id.itemName);
        }

        @Override
        public String toString() {
            return "ViewHolder{" +
                    "mView=" + mView +
                    ", itemId=" + itemId +
                    ", itemName=" + itemName +
                    ", menuProgressItem=" + menuProgressItem +
                    '}';
        }
    }
}
private MenuProgressAdapter adapter;
// 通过构造器将我们的数据t.getData()和debugTaskData设置进去
adapter = new MenuProgressAdapter(this, t.getData(), debugTaskData);
// 设置LayoutManager
binding.debugTaskList.setLayoutManager(new LinearLayoutManager(this));
// 为debugTaskList视图设置适配器
binding.debugTaskList.setAdapter(adapter);

ArrayAdapter

ArrayAdapter数组适配器用于绑定格式单一的数据,数据源可以是集合或者数组列表视图(ListView)以垂直的形式列出需要显示的列表项。

ArrayAdapter比较简单,通常会和ListView一起使用,但是现在我们已经很少使用ListView了,被废弃了,现在用的是RecyclerView。

简单的Demo(ListView)

定义CommonMenu的适配器ItemListAdapter

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CommonMenu {

    private String id;
    private String title;

    // 是否完成此试验数据填写
    private boolean finish;

}
public class ItemListAdapter extends ArrayAdapter<CommonMenu> {
    private int resourceId;

    public ItemListAdapter(@NonNull Context context, int resource, @NonNull List<CommonMenu> objects) {
        super(context, resource, objects);
        resourceId = resource;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        CommonMenu item = getItem(position);

        View view;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
        } else {
            view = convertView;
        }

        TextView itemId = view.findViewById(R.id.itemId);
        TextView itemName = view.findViewById(R.id.itemName);

        itemId.setText(item.getId());
        itemName.setText(item.getTitle());

        return view;
    }
}

使用ItemListAdapter适配器:

private List<CommonMenu> menuList = new ArrayList<>();
// 在此之前,将从数据库中查询出来的menuList放置到适配器中。
ItemListAdapter itemListAdapter = new ItemListAdapter(this, R.layout.common_item_list, menuList);

// 将此ListView的View拿到
ListView itemListView = findViewById(R.id.tap_switch_item_list_view);

// 为ListView设置适配器itemListAdapter
itemListView.setAdapter(itemListAdapter);

// 为每个item设置监听器
itemListView.setOnItemClickListener((parent, view, position, id) -> {
    // parent:被点击的AdapterView
    // view:被点击的View
    // position:适配器中被点击的View的位置,可以通过menuList.get(position)可以获取到被点击的CommonMenu数据
    // id:id单击的项目的行ID

    // 点击某个item之后的业务逻辑...
});

获取被点击的item数据,我举个例子,我先添加一个数据:

menuList.add(CommonMenu.builder()
             .id("123456789")
             .title("示例1")
             .finish(true)
             .build());
itemListView.setOnItemClickListener((parent, view, position, id) -> {
    // 被点击的CommonMenu数据
    CommonMenu commonMenu = menuList.get(position);
});

OnItemClickListener的源码:

/**
 * Interface definition for a callback to be invoked when an item in this
 * AdapterView has been clicked.
 */
public interface OnItemClickListener {

    /**
     * Callback method to be invoked when an item in this AdapterView has
     * been clicked.
     * <p>
     * Implementers can call getItemAtPosition(position) if they need
     * to access the data associated with the selected item.
     *
     * @param parent The AdapterView where the click happened.
     * @param view The view within the AdapterView that was clicked (this
     *            will be a view provided by the adapter)
     * @param position The position of the view in the adapter.
     * @param id The row id of the item that was clicked.
     */
    void onItemClick(AdapterView<?> parent, View view, int position, long id);
}
正文到此结束
本文目录