当前位置: 首页 > news >正文

安卓开发---在适配器中使用监听器

根据以下的例子,来学习怎么在适配器中怎么使用监听器。

1.在适配器中使用监听器的目的是什么?

答: ​​实现组件间的解耦通信,Adapter 只应负责数据绑定和视图创建,不应包含业务逻辑​​,通过监听器将点击事件"转发"给业务层处理。保障线程安全与生命周期安全​​,自动在主线程回调(避免UI更新崩溃)。

2.在适配器中使用监听器的顺序是什么?

参考以下案例的步骤

在Adapter里面

①定义监听接口

public interface OnItemClickListener { void onItemClick(int position, KeySetting item); }

②设置监听器:将外部传入的监听器对象保存到适配器成员变量中

private OnItemClickListener onItemClickListener;

public void setOnItemClickListener(OnItemClickListener listener) {

this.onItemClickListener = listener;

}

③触发监听

holder.itemView.setOnClickListener(v -> {//为整个列表项设置点击监听器d
int adapterPosition = holder.getAdapterPosition();//获取当前点击项在Adapter中的位置
//检查位置是否有效:adapterPosition != RecyclerView.NO_POSITION
//检查监听器是否已经设置:onItemClickListener != null
   if (adapterPosition != RecyclerView.NO_POSITION && onItemClickListener != null) {
//触发回调,传递两个关键数据,点击的位置索引,点击项的数据对象
onItemClickListener.onItemClick(adapterPosition, keyListInAdapter.get(adapterPosition));
    }
});

在Activity中

//【外部使用监听器】实现接口
adapter.setOnItemClickListener((position, item) -> {
// 写入缓存,只写当前耳朵
Caches.getInstance().saveButtonTitle(buttonIndex, item.getName(), isLeftSelected);
    Caches.getInstance().saveButtonAction(buttonIndex, item.getName(), isLeftSelected);

    // 更新UI
updateButtonDisplay(buttonIndex, item.getName());
    adapter.setSelectedPosition(position);//用户点击时,更新选中状态
    tvTitle.setText(item.getName());
});

3.具体的数据流是怎么样流动的?

①当用户点击列表项,直接触发适配器中的holder.itemView.setOnClickListener,立刻向Adapter传递数据onItemClickListener.onItemClick(adapterPosition,keyListInAdapter.get(adapterPosition));。

②适配器自动检查监听器有效性,然后转发数据,就是回调listener.onItemClick()。

③Activity收到数据,根据收到的数据处理UI。

标准流程图

核心组件关系图

MainActivity.java

package com.example.myapplication;import android.content.res.ColorStateList;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import com.google.android.material.bottomsheet.BottomSheetDialog;import java.util.ArrayList;
import java.util.List;public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";//UIprivate TextView leftEarphone, rightEarphone; //左耳,右耳private ImageView oneClickForward, doubleClickForward, threeClickForward, longPressForward; //单击,双击,三击,长按private TextView oneClickWoldDispaly, doubleClickWoldDispaly, threeClickWoldDispaly, longPressWoldDispaly; //显示的功能值private int oneclick_1 = 1, doubleclick_2 = 2, threeclick_3 = 3, longpress_4 = 4; //用于区分按钮private boolean isLeftSelected = true; // 当前选中的耳朵,默认左耳(true 左耳,false 右耳)private BottomSheetDialog dialog; // 当前显示的对话框List<KeySetting> keyList = new ArrayList<>();//数据列表@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//初始化initView();initClick();initListDate();// 初始化加载配置loadButtonConfigs();selectEarUI(); // 触发首次UI更新}@Overrideprotected void onPause() {super.onPause();dismissCurrentDialog();}// 初始化列表数据private void initListDate() {keyList.add(new KeySetting("无作用"));keyList.add(new KeySetting("语音助手"));keyList.add(new KeySetting("上一首"));keyList.add(new KeySetting("下一首"));keyList.add(new KeySetting("音量加"));keyList.add(new KeySetting("音量减"));keyList.add(new KeySetting("播放/暂停"));keyList.add(new KeySetting("ANC切换"));}//1.获取视图private void initView() {leftEarphone = findViewById(R.id.tv_left_earphone);rightEarphone = findViewById(R.id.tv_right_earphone);oneClickForward = findViewById(R.id.iv_one_forward);doubleClickForward = findViewById(R.id.iv_double_forward);threeClickForward = findViewById(R.id.iv_three_forward);longPressForward = findViewById(R.id.iv_long_forward);oneClickWoldDispaly = findViewById(R.id.tv_one_click_display);doubleClickWoldDispaly = findViewById(R.id.tv_double_click_display);threeClickWoldDispaly = findViewById(R.id.tv_three_click_display);longPressWoldDispaly = findViewById(R.id.tv_long_press_display);}//2.点击事件private void initClick() {// 按钮点击事件oneClickForward.setOnClickListener(v -> showSelectDialog(oneclick_1));doubleClickForward.setOnClickListener(v -> showSelectDialog(doubleclick_2));threeClickForward.setOnClickListener(v -> showSelectDialog(threeclick_3));longPressForward.setOnClickListener(v -> showSelectDialog(longpress_4));// 左耳点击事件leftEarphone.setOnClickListener(view -> {isLeftSelected = true;selectEarUI();//更新UI});// 右耳点击事件rightEarphone.setOnClickListener(view -> {isLeftSelected = false;selectEarUI();//更新UI});}// 3.初始化 UI, 从Caches读取4个按钮的功能值,默认显示左耳private void loadButtonConfigs() {// 加载当前选中耳朵的配置updateButtonDisplays(isLeftSelected);}//读存储,更新用来显示的功能值private void updateButtonDisplays(boolean isLeft) {oneClickWoldDispaly.setText(Caches.getInstance().getButtonAction(oneclick_1, isLeft));doubleClickWoldDispaly.setText(Caches.getInstance().getButtonAction(doubleclick_2, isLeft));threeClickWoldDispaly.setText(Caches.getInstance().getButtonAction(threeclick_3, isLeft));longPressWoldDispaly.setText(Caches.getInstance().getButtonAction(longpress_4, isLeft));}// 4.修改按键的UIprivate void selectEarUI() {Log.d(TAG, "选中耳机: " + (isLeftSelected ? "左耳" : "右耳"));leftEarphone.setBackgroundColor(ContextCompat.getColor(this,isLeftSelected ? R.color.blue : R.color.gray));leftEarphone.setTextColor(ContextCompat.getColor(this,isLeftSelected ? R.color.white : R.color.black));rightEarphone.setBackgroundColor(ContextCompat.getColor(this,!isLeftSelected ? R.color.blue : R.color.gray));rightEarphone.setTextColor(ContextCompat.getColor(this,!isLeftSelected ? R.color.white : R.color.black));// 切换按钮时,重新从caches里面更新按钮的功能值updateButtonDisplays(isLeftSelected);}// 5.弹窗展示private void showSelectDialog(int buttonIndex) {// 先销毁已有对话框,确保同一时间只存在一个对话框实例dismissCurrentDialog();//创建新对话框dialog = new BottomSheetDialog(this);//加载对话框布局View view = LayoutInflater.from(this).inflate(R.layout.dialog_key_setting_select, null);dialog.setContentView(view);//获取子视图TextView tvTitle = view.findViewById(R.id.tv_title);//子项的标题RecyclerView rv = view.findViewById(R.id.rv_actions);//子项的列表// 同步标题文字:从Caches读取当前按键的标题String savedTitle = Caches.getInstance().getButtonTitle(buttonIndex, isLeftSelected);//同步获取当前对话框设置的功能值String currentAction = Caches.getInstance().getButtonAction(buttonIndex, isLeftSelected);tvTitle.setText(savedTitle != null ? savedTitle : "请选择");//配置适配器rv.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));//设置分割线rv.setLayoutManager(new LinearLayoutManager(this));// 设置适配器,将列表数据绑定到RecyclerViewKeySettingAdapter adapter = new KeySettingAdapter(keyList);rv.setAdapter(adapter);//初始化选中项,遍历列表找到与缓存匹配的项for (int i = 0; i < keyList.size(); i++) {if (keyList.get(i).getName().equals(currentAction)) {adapter.setSelectedPosition(i);//把选中的位置传给适配器break;}}//设置列表项点击监听器//【外部使用监听器】实现接口adapter.setOnItemClickListener((position, item) -> {// 写入缓存,只写当前耳朵Caches.getInstance().saveButtonTitle(buttonIndex, item.getName(), isLeftSelected);Caches.getInstance().saveButtonAction(buttonIndex, item.getName(), isLeftSelected);// 更新UIupdateButtonDisplay(buttonIndex, item.getName());adapter.setSelectedPosition(position);//用户点击时,更新选中状态tvTitle.setText(item.getName());});dialog.setOnDismissListener(dialog -> {dialog = null; // 清除引用});dialog.show();}//销毁对话框private void dismissCurrentDialog() {if (dialog != null && dialog.isShowing()) {dialog.dismiss();dialog = null;}}// 6.更新按钮的显示private void updateButtonDisplay(int buttonIndex, String newTitle) {switch (buttonIndex) {case 1:oneClickWoldDispaly.setText(newTitle);break;case 2:doubleClickWoldDispaly.setText(newTitle);break;case 3:threeClickWoldDispaly.setText(newTitle);break;case 4:longPressWoldDispaly.setText(newTitle);break;}}
}

KeySettingAdapter.java

package com.example.myapplication;import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;import java.util.List;public class KeySettingAdapter extends RecyclerView.Adapter<KeySettingAdapter.ViewHolder> {//定义数据成员(KeySetting)类型,用于接收Activitiy调用适配器是传递数据,实现数据共享private List<KeySetting> keyListInAdapter;//数据源:选项列表private int selectedPosition = -1;//当前选中项的位置,-1表示未选中//构造函数public KeySettingAdapter(List<KeySetting> keyListInAdapter) {this.keyListInAdapter = keyListInAdapter;}// 1.【定义监听接口】添加点击监听器接口public interface OnItemClickListener {void onItemClick(int position, KeySetting item);}//2.【设置监听器】将外部传入的监听器对象保存到适配器成员变量中private OnItemClickListener onItemClickListener;public void setOnItemClickListener(OnItemClickListener listener) {this.onItemClickListener = listener;}//返回列表项总数@Overridepublic int getItemCount() {return keyListInAdapter.size();}//布局:通过inflate方法将列表项item布局编译为view对象,返回以这个对象为参数的ViewHolder对象(就是创建viewHolder)@NonNull@Overridepublic ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.key_setting_item, parent, false);return new ViewHolder(view);}//将数据渲染到列表项的ViewHolder的view控件中(就是绑定数据)@Overridepublic void onBindViewHolder(@NonNull ViewHolder holder, int position) {//给第position条目 绑定数据(从0开始计数) 对应的数据是keyListInAdapter的position个元素KeySetting item = keyListInAdapter.get(position);holder.tvAction.setText(item.getName());//控制选中图标显示还是隐藏,选中就显示,未选择就隐藏holder.ivSelected.setVisibility(position == selectedPosition ? View.VISIBLE : View.GONE);//设置点击事件//当用户点击某个列表项时,触发回调通知外部//【触发监听】当列表项的任意区域被点击时holder.itemView.setOnClickListener(v -> {//为整个列表项设置点击监听器dint adapterPosition = holder.getAdapterPosition();//获取当前点击项在Adapter中的位置//检查位置是否有效:adapterPosition != RecyclerView.NO_POSITION//检查监听器是否已经设置:onItemClickListener != nullif (adapterPosition != RecyclerView.NO_POSITION && onItemClickListener != null) {//触发回调,传递两个关键数据,点击的位置索引,点击项的数据对象onItemClickListener.onItemClick(adapterPosition, keyListInAdapter.get(adapterPosition));}});}// 选中状态管理(自动取消旧项选中状态,严格保证唯一选中项)public void setSelectedPosition(int position) {if (selectedPosition != position) {//检查新旧位置是否不同int oldPosition = selectedPosition;//保存旧位置selectedPosition = position;//更新当前选中位置if (oldPosition != -1) {//如果旧位置有效notifyItemChanged(oldPosition);//就刷新旧位置}notifyItemChanged(selectedPosition);//刷新新项UI}}// 获取当前选中项public int getSelectedPosition() {return selectedPosition;}//新建viewHolderstatic class ViewHolder extends RecyclerView.ViewHolder {TextView tvAction;ImageView ivSelected;public ViewHolder(@NonNull View itemView) {super(itemView);tvAction = itemView.findViewById(R.id.tv_action);ivSelected = itemView.findViewById(R.id.iv_selected);}}
}

http://www.dtcms.com/a/422792.html

相关文章:

  • 【COT】PromptCoT 2.0少样本训练 CoT
  • 鸿蒙应用开发和安卓应用开发的区别
  • UNIX下C语言编程与实践12-lint 工具使用指南:C 语言源代码语法与逻辑错误检查实战
  • UNIX下C语言编程与实践5-C 语言编译器 cc(gcc/xlc)核心参数解析:-I、-L、-D 的使用场景与实例
  • 机器视觉的双相机对位模切应用
  • 高档网站设计wordpress好用的商城主题
  • 植物大战僵尸融合版下载安装教程【PC/安卓/iOS 完整攻略 + 常见问题解决】
  • 厦门做网站价格想学网站建设与设计的书籍
  • 【TCSVT→Neurocomputing→ASOC投稿】记一次旷日持久的投稿经历
  • namespace 扩展
  • C语言——深入解析C语言指针:从基础到实践从入门到精通(一)
  • leetcode430:扁平化多级双向链表
  • 网站项目开发收费标准360网站名片怎么做的
  • 分布式秒杀系统设计方案
  • 分布式短链接系统设计方案
  • 分布式光纤声波振动与AI的深度融合:开启智慧感知新时代
  • 电商网站设计论文新网金商网站
  • [pdf、epub]320道《软件方法》强化自测题业务建模需求分析共279页(202509更新)
  • 赎金信--leetcode
  • Harbor磁盘空间清理指南:如何安全清理半年前的镜像
  • 网站开发项目组织架构电商平台怎么找商家
  • 基于Hadoop的肾脏疾病风险分析系统架构设计精髓
  • 如何优雅的布局,height: 100% 的使用和 flex-grow: 1 的 min-height 陷阱
  • Ubuntu20.04使用venv创建虚拟环境并安装ultralytics
  • Docker 镜像知识总结
  • 东莞保安公司2019网站seo
  • 34.MariaDB 数据库
  • Gradle之适配
  • 实战:爬取豆瓣电影Top250,并生成Excel榜单
  • 建网站有什么要求山西网站建设方案