Android无限层扩展多级recyclerview列表+实时搜索弹窗

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/2767499cd5434afea18c885d0f54a1ae.png
业务逻辑:
点击选择,弹出弹窗,列表数据由后台提供,不限层级,可叠加无限层子级;
点击item展开收起,点击尾部icon单选选中,点击[确定]为最终选中,收起弹窗;
搜索框输入字符时,实时检索数据显示;
搜索出的列表点击直接选中,收起弹窗。

弹窗代码:

class DepartListDialog {class Builder(context: Context) : BasicDialog.Builder<Builder>(context) {private val inputView: EditText? by lazy { findViewById(R.id.et_input) }private val titleView: TextView? by lazy { findViewById(R.id.tv_title) }private val leftView: TextView? by lazy { findViewById(R.id.tv_left) }private val rightView: TextView? by lazy { findViewById(R.id.tv_right) }private val clearView: ImageView? by lazy { findViewById(R.id.iv_del) }private val llEmpty: LinearLayout? by lazy { findViewById(R.id.ll_empty) }private var onLeftClick: ((BasicDialog) -> Unit)? = nullprivate var onRightClick: ((String, BasicDialog) -> Unit)? = nullprivate var isFilterEmail = falseprivate var query = ""private var onItemClick: ((DepartModel, Int, BasicDialog?) -> Unit)? = nullprivate var onItemSelectClick: ((View, Int, DepartModel) -> Unit)? = nullprivate var onSearchItemClick: ((ArrayList<String>, DepartModel, Int, BasicDialog?) -> Unit)? = nullprivate var onInputListener: ((String, BasicDialog?) -> Unit)? = nullprivate val rvSearch: RecyclerView? by lazy { findViewById(R.id.rv_search) }private val recyclerView: RecyclerView? by lazy { findViewById(R.id.recycler_view) }private var recyclerAdapter: DepartTreeAdapter? = nullprivate var treeItemList = arrayListOf<DepartModel>()private val rvSearchAdapter: CommonAdapter<DepartModel>? by lazy {CommonAdapter<DepartModel>(R.layout.item_string).apply {convert = { holder, position, item ->item?.let {var str = item.namevar cList = item.children ?: arrayListOf()while (cList.isNotEmpty()) {str += "/" + cList[0].namecList = cList[0].children ?: arrayListOf()}val tvName = holder.getView<TextView>(R.id.tv_name)setPartText(tvName, str, query,getColor(R.color.color_909090), getColor(R.color.color_303030))}}setOnItemClickListener { adapter, _, position ->adapter.getItem(position)?.let {val ids = arrayListOf<String>()var bean = itids.add(bean.id)var str = bean.namewhile (bean.children != null && bean.children?.isNotEmpty() == true) {bean = bean.children!![0]ids.add(bean.id)str += "/" + bean.name}val nameArr = str.split("/")if (nameArr.size > 2) {bean.name ="……/" + nameArr[nameArr.size - 2] + "/" + nameArr[nameArr.size - 1]} else {bean.name = str}onSearchItemClick?.invoke(ids, bean, position, getDialog())dismiss()}}}}init {setContentView(R.layout.dialog_common_input_data)setAnimStyle(AnimAction.ANIM_BOTTOM)setGravity(Gravity.BOTTOM)setCancelable(false)setCanceledOnTouchOutside(false)setOnClickListener(leftView, rightView, clearView)setRightBtnEnable(false)recyclerAdapter = DepartTreeAdapter(context, treeItemList)recyclerView?.adapter = recyclerAdapterrecyclerAdapter?.setOnItemClickListener(object : DepartTreeAdapter.OnItemClickListener {override fun onItemClick(view: View, position: Int, model: DepartModel) {
//                    showToast("当前点击的数据为 ${model.name}")}})recyclerAdapter?.onItemChildClickListener =object : DepartTreeAdapter.OnItemChildClickListener {override fun onClick(view: View, position: Int, model: DepartModel) {onItemSelectClick?.invoke(view, position, model)setRightBtnEnable(true)}}rvSearch?.adapter = rvSearchAdapterinputView?.addTextChangedListener(object : TextWatcher {override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}override fun afterTextChanged(p0: Editable?) {query = inputView?.text?.trim().toString()if (query.isEmpty()) {rvSearchAdapter?.submitList(arrayListOf())rvSearchAdapter?.notifyDataSetChanged()recyclerView?.visibility = View.VISIBLEval v = if ((recyclerView?.adapter?.itemCount?: 0) < 1) View.VISIBLE else View.GONEllEmpty?.visibility = v} else {onInputListener?.invoke(query, getDialog())recyclerView?.visibility = View.INVISIBLE}clearView?.isVisible = query.isNotEmpty()}})}fun setRightBtnEnable(enable: Boolean): Builder = apply {val color = if (enable) {if (UiUtil.isDarkMode(getContext())) getColor(R.color.color_E16C5F) else getColor(R.color.color_DD594A)} else {if (UiUtil.isDarkMode(getContext())) getColor(R.color.color_606060) else getColor(R.color.color_909090)}rightView?.setTextColor(color)rightView?.isEnabled = enable}fun setData(data: ArrayList<DepartModel>): Builder = apply {recyclerAdapter?.submitList(data)recyclerAdapter?.notifyDataSetChanged()val v = if (data.isEmpty()) View.VISIBLE else View.GONEllEmpty?.visibility = v}fun resetDefault() {recyclerAdapter?.setDefaultAdapter()}fun setSelectItem(index: Int): Builder = apply {recyclerAdapter?.notifyItemChanged(index)}fun setSearchData(data: ArrayList<DepartModel>): Builder = apply {rvSearchAdapter?.submitList(data)rvSearchAdapter?.notifyDataSetChanged()val v =if (data.isEmpty() && recyclerView?.visibility == View.INVISIBLE) View.VISIBLE else View.GONEllEmpty?.visibility = v}fun setSelectSearchItem(index: Int): Builder = apply {rvSearchAdapter?.notifyItemChanged(index)}fun setOnItemClick(onItemClick: ((DepartModel, Int, BasicDialog?) -> Unit)): Builder =apply {this.onItemClick = onItemClick}fun setOnItemSelectClick(onItemSelectClick: ((View, Int, DepartModel) -> Unit)): Builder =apply {this.onItemSelectClick = onItemSelectClick}fun setOnSearchItemClick(onSearchItemClick: ((ArrayList<String>, DepartModel, Int, BasicDialog?) -> Unit)): Builder =apply {this.onSearchItemClick = onSearchItemClick}fun setOnInputListener(onInputListener: ((String, BasicDialog?) -> Unit)): Builder =apply {this.onInputListener = onInputListener}override fun onClick(view: View) {when (view) {leftView -> {getDialog()?.let {onLeftClick?.invoke(it)}dismiss()}rightView -> {val input = inputView?.text?.toString()?.trim() ?: ""getDialog()?.let {onRightClick?.invoke(input, it)}dismiss()}clearView -> {inputView?.text?.clear()}}}// 设置标题fun setTitle(title: String): Builder = apply {titleView?.text = title}// 设置左边的文本fun setLeftText(leftStr: String): Builder = apply {leftView?.text = leftStr}// 设置右边的文本fun setRightText(rightStr: String): Builder = apply {rightView?.text = rightStr}// 设置输入类型fun setInputType(inputType: Int): Builder = apply {inputView?.inputType = inputType}// 设置输入最大长度fun setInputLength(maxLength: Int): Builder = apply {inputView?.filters = arrayOf(InputFilter.LengthFilter(maxLength))}// 设置邮箱字符过滤fun needFilterEmail(): Builder = apply {isFilterEmail = true}// 设置默认输入fun setDefaultInput(str: String): Builder = apply {inputView?.setText(str)}// 设置输入提示语fun setInputHint(hint: String): Builder = apply {inputView?.hint = hint}// 设置左边按钮点击事件fun setLeftClick(onLeftClick: ((BasicDialog) -> Unit)): Builder = apply {this.onLeftClick = onLeftClick}// 设置右边按钮点击事件fun setRightClick(onRightClick: ((String, BasicDialog) -> Unit)): Builder = apply {this.onRightClick = onRightClick}}
}

弹窗布局文件:

<?xml version="1.0" encoding="utf-8"?>
<com.ruffian.library.widget.RRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginTop="@dimen/dp_56"android:layout_gravity="bottom"app:background_normal="?first_bg_color"app:corner_radius_top_left="@dimen/dp_24"app:corner_radius_top_right="@dimen/dp_24"tools:viewBindingIgnore="true"><TextViewandroid:id="@+id/tv_left"android:layout_width="wrap_content"android:layout_height="@dimen/dp_54"android:gravity="center"android:paddingHorizontal="@dimen/dp_17"android:text="@string/cancel"android:textColor="?third_text_color"android:textSize="@dimen/sp_14" /><TextViewandroid:id="@+id/tv_right"android:layout_width="wrap_content"android:layout_height="@dimen/dp_54"android:layout_alignParentEnd="true"android:gravity="center"android:paddingHorizontal="@dimen/dp_17"android:text="@string/confirm"android:enabled="false"android:textColor="?first_btn_bg_color"android:textSize="@dimen/sp_14" /><TextViewandroid:id="@+id/tv_title"android:layout_width="wrap_content"android:layout_height="@dimen/dp_54"android:layout_centerHorizontal="true"android:gravity="center"android:paddingHorizontal="@dimen/dp_17"android:text="@string/depart_select"android:textColor="?first_text_color"android:textSize="@dimen/sp_18" /><Viewandroid:id="@+id/v_divider"android:layout_below="@+id/tv_title"android:layout_marginHorizontal="@dimen/dp_16"android:layout_width="match_parent"android:layout_height="0.5dp"android:background="?first_divider_color" /><com.ruffian.library.widget.RRelativeLayoutandroid:id="@+id/rl_et"android:layout_width="match_parent"android:layout_height="@dimen/dp_32"app:corner_radius="@dimen/dp_4"android:layout_below="@+id/v_divider"android:layout_margin="@dimen/dp_16"app:background_normal="?second_btn_bg_color"><ImageViewandroid:id="@+id/iv_search"android:layout_width="@dimen/dp_16"android:layout_height="@dimen/dp_16"android:layout_centerVertical="true"android:contentDescription="@null"android:layout_marginStart="@dimen/dp_10"android:src="?icon_edit_search" /><EditTextandroid:id="@+id/et_input"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginStart="@dimen/dp_10"android:layout_toStartOf="@+id/iv_del"android:layout_toEndOf="@+id/iv_search"android:background="@color/transparent"android:importantForAutofill="no"android:inputType="text"android:textColor="?first_text_color"android:hint="@string/please_input_depart_name"android:textColorHint="?first_hint_text_color"android:textSize="@dimen/sp_14"tools:ignore="LabelFor" /><ImageViewandroid:id="@+id/iv_del"android:layout_width="@dimen/dp_32"android:layout_height="@dimen/dp_32"android:layout_alignParentEnd="true"android:contentDescription="@null"android:paddingHorizontal="@dimen/dp_8"android:paddingVertical="@dimen/dp_8"android:visibility="invisible"android:src="?icon_clear_edit" /></com.ruffian.library.widget.RRelativeLayout><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recycler_view"android:layout_below="@+id/rl_et"app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"android:layout_width="match_parent"android:layout_height="wrap_content"/><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/rv_search"android:layout_below="@+id/rl_et"app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="?first_bg_color"/><LinearLayoutandroid:visibility="gone"android:id="@+id/ll_empty"android:layout_below="@+id/rl_et"android:layout_width="match_parent"android:layout_height="@dimen/dp_280"android:background="?first_bg_color"android:gravity="center"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"><ImageViewandroid:layout_width="@dimen/dp_180"android:layout_height="@dimen/dp_160"android:src="?img_empty"/></LinearLayout></com.ruffian.library.widget.RRelativeLayout>

树形结构的适配器:

class DepartTreeAdapter(private val mContext: Context,private val treeItemList: ArrayList<DepartModel>
) :RecyclerView.Adapter<DepartTreeAdapter.KTTreeViewHolder>() {private var selectPosition = RecyclerView.NO_POSITIONprivate var onItemClickListener: OnItemClickListener? = nullvar onItemChildClickListener: OnItemChildClickListener? = nullprivate var settedAdapter = falsefun setSelectPosition(position: Int) {selectPosition = positionnotifyDataSetChanged()}fun submitList(data: ArrayList<DepartModel>) {treeItemList.clear()treeItemList.addAll(data)notifyDataSetChanged()}fun setDefaultAdapter() {notifyDataSetChanged()settedAdapter = true}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KTTreeViewHolder {val binding =ItemDepartmentBinding.inflate(LayoutInflater.from(parent.context), parent, false)return KTTreeViewHolder(binding)}override fun onBindViewHolder(holder: KTTreeViewHolder, position: Int) {val treeItem = treeItemList[position]holder.bind(treeItem)}override fun getItemCount(): Int {return treeItemList.size}inner class KTTreeViewHolder(val binding: ItemDepartmentBinding) :RecyclerView.ViewHolder(binding.root) {fun bind(treeItem: DepartModel) {// 根据层级设置左边距val leftPadding = (treeItem.level - 1) * 50binding.llIcon.setPadding(leftPadding, 0, 0, 0)binding.tvName.text = treeItem.nameval icon =if (TestActivity.lastSelectBean?.id == treeItem.id) R.mipmap.ic_selected else R.mipmap.ic_unselectbinding.ivSelect.setImageResource(icon)//设置默认已选中数据的adapterif (settedAdapter && TestActivity.lastSelectBean?.id == treeItem.id) {settedAdapter = falseTestActivity.curAdapter = this@DepartTreeAdapter}// 根据展开状态设置箭头图标if (treeItem.children != null && treeItem.children?.isNotEmpty() == true) {if (treeItem.isOpen) {binding.ivNext.rotation = 180f} else {binding.ivNext.rotation = 0f}} else {binding.llIcon.visibility = View.INVISIBLE}// 设置点击事件itemView.setOnClickListener {// 切换展开状态treeItem.isOpen = !treeItem.isOpen// 局部刷新,只刷新当前点击的位置和其子项的数据notifyItemChanged(bindingAdapterPosition)onItemClickListener?.onItemClick(itemView, bindingAdapterPosition, treeItem)
//                setSelectPosition(bindingAdapterPosition)}// 如果没有数据子列表不显示binding.recyclerView.visibility = if (treeItem.isOpen) View.VISIBLE else View.GONE// 如果有子数据,设置适配器并显示箭头if (treeItem.children != null && treeItem.children?.isNotEmpty() == true) {binding.ivNext.visibility = View.VISIBLEbinding.recyclerView.visibility = if (treeItem.isOpen) View.VISIBLE else View.GONE// 计算子项的级别,加上适当的偏移量//给了level 不用计算
//                val childLevel = treeItem.level + 1
//                treeItem.children!!.forEach { child ->
//                    child.level = childLevel
//                }binding.recyclerView.layoutManager = LinearLayoutManager(mContext)val childAdapter = DepartTreeAdapter(mContext, treeItem.children!!)binding.recyclerView.adapter = childAdapterchildAdapter.setOnItemClickListener(object : OnItemClickListener {override fun onItemClick(view: View, position: Int, model: DepartModel) {onItemClickListener?.onItemClick(view, position, model)}})childAdapter.onItemChildClickListener = object : OnItemChildClickListener {override fun onClick(view: View, position: Int, model: DepartModel) {TestActivity.lastSelectBean = modelTestActivity.curAdapter?.notifyDataSetChanged()childAdapter.notifyDataSetChanged()TestActivity.curAdapter = childAdapterif (model.name.contains("……")) {onItemChildClickListener?.onClick(view, position, model)} else {var name = ""if (model.level > 2) {name = "……/"}name += "${treeItem.name}/${model.name}"val selModel = DepartModel(model.id, name)onItemChildClickListener?.onClick(view, position, selModel)}}}} else {    // 没有子数据,隐藏箭头binding.ivNext.visibility = View.GONEbinding.recyclerView.visibility = View.GONE}binding.ivSelect.setOnClickListener {TestActivity.lastSelectBean = treeItemTestActivity.curAdapter?.notifyDataSetChanged()notifyDataSetChanged()TestActivity.curAdapter = this@DepartTreeAdapteronItemChildClickListener?.onClick(it, bindingAdapterPosition, treeItem)}// 根据是否带有右箭头来设置背景颜色
//            itemView.setBackgroundColor(
//                ContextCompat.getColor(
//                    mContext,
//                    if (binding.ivNext.visibility == View.VISIBLE
//                        && bindingAdapterPosition == selectPosition
//                    ) R.color.color_public_bg else R.color.white
//                )
//            )}}fun setOnItemClickListener(listener: OnItemClickListener) {this.onItemClickListener = listener}interface OnItemClickListener {fun onItemClick(view: View, position: Int, model: DepartModel)}interface OnItemChildClickListener {fun onClick(view: View, position: Int, model: DepartModel)}
}

adapter绑定的item布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="wrap_content"xmlns:app="http://schemas.android.com/apk/res-auto"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center_vertical"android:paddingVertical="@dimen/dp_16"android:paddingHorizontal="@dimen/dp_16"><LinearLayoutandroid:id="@+id/ll_icon"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageViewandroid:id="@+id/iv_next"android:layout_width="@dimen/dp_12"android:layout_height="@dimen/dp_12"android:src="?ic_expand_normal" /></LinearLayout><TextViewandroid:id="@+id/tv_name"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginStart="@dimen/dp_6"android:layout_weight="1"android:textColor="?first_text_color"android:textSize="@dimen/sp_14" /><ImageViewandroid:id="@+id/iv_select"android:layout_width="@dimen/dp_24"android:layout_height="@dimen/dp_24"android:src="?ic_unselect" /></LinearLayout><Viewandroid:id="@+id/v_divider"android:layout_width="match_parent"android:layout_height="0.5dp"android:background="?first_divider_color"android:layout_marginHorizontal="@dimen/dp_16" /><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recyclerView"app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"android:layout_width="match_parent"android:layout_height="wrap_content" />
</LinearLayout>

实体类:

data class DepartModel(var id: String = "",var name: String = "",var pid: String = "",var children: ArrayList<DepartModel>? = arrayListOf(),var level: Int = 1,var isOpen: Boolean = false
)

页面选中后的UI需求如下:
在这里插入图片描述

TestActivity中设置:

    private var departData = arrayListOf<DepartModel>()private lateinit var builder: DepartListDialog.Builderprivate var tmpSelectDepart = DepartModel()private var selectDepart = DepartModel()//编辑页面中传入的已选择部门idprivate var department_id = ""//编辑页面中传入的已选择部门list(包含已选择的所有父级子级)private var department_list = arrayListOf<IdModel>()override fun initView() {builder = DepartListDialog.Builder(this)//如果是编辑页面进入,取出已选择数据选中if (isEditPage) {if (department_list.size > 0) {department_list.reverse()var departName = ""department_list.forEach {if (department_list.indexOf(it) > 1) return@forEachdepartName = it.name + "/" + departNameif (it.id.equals(department_id)) {tmpSelectDepart = DepartModel(id = it.id, name = it.name)}}if (department_list.size > 2) {departName = "……/${departName}"}departName = departName.substring(0, departName.length - 1)setDepartTxt(departName)tmpSelectDepart.name = departName}selectDepart.id = department_idlastSelectBean = DepartModel(id = department_id)}}override fun observeViewModel() {viewModel.departList.observe(this) {departData = ArrayList(it)if (isEditPage) {//从[编辑]跳转,把选中的item展开if (department_list.size > 1) {val ids = arrayListOf<String>()department_list.forEach { selDepart -> ids.add(selDepart.id) }departData.forEach { dd ->if (ids.contains(dd.id)) {//find选中部门的最外层级//循环把所有子级都展开dd.isOpen = truevar cList = dd.children ?: arrayListOf()var i = 0//大于10级就不读了while (i++ < 10 && cList.isNotEmpty()) {//子级中find选中部门的内层级cList.forEach { childDd ->if (ids.contains(childDd.id)) {//find选中部门的内层级
//                                    if(childDd.id==department_id){
//                                        childDd.isSelect=true
//                                    }//子集也打开childDd.isOpen = true//接着赋值新的list循环cList = childDd.children ?: arrayListOf()}}}}}}}builder.setData(departData)if (jumpType == 2) {builder.resetDefault()}showDepartDialog()}viewModel.departSearchList.observe(this) {builder.setSearchData(ArrayList(it))}}private fun showDepartDialog() {if (isEditPage && lastSelectBean?.id?.isNotEmpty() == true) builder.setRightBtnEnable(true)builder.setOnItemSelectClick { view, pos, item ->tmpSelectDepart = item}.setRightClick { s, basicDialog ->if (tmpSelectDepart.id != selectDepart.id) {//切换了部门resetPos()}selectDepart = tmpSelectDepartsetDepartTxt(selectDepart.name)}.setOnSearchItemClick { ids, departModel, pos, basicDialog ->if (departModel.id != selectDepart.id) {//切换了部门resetPos()}tmpSelectDepart = departModelselectDepart = departModellastSelectBean = DepartModel(id = departModel.id, name = departModel.name)setDepartTxt(departModel.name)//将选中状态更新到部门列表builder.resetDefault()//从搜索中选中的,将数据open状态全部重置,使弹窗重新打开就显示出选中itemdepartData.forEach { dd ->if (ids.contains(dd.id)) {//find选中部门的最外层级//循环把所有子级都展开dd.isOpen = truevar cList = dd.children ?: arrayListOf()var i = 0//大于10级就不读了while (i++ < 10 && cList.isNotEmpty()) {//子级中find选中部门的内层级cList.forEach { childDd ->if (ids.contains(childDd.id)) {//find选中部门的内层级//子集也打开childDd.isOpen = true//接着赋值新的list循环cList = childDd.children ?: arrayListOf()} else {childDd.isOpen = false}}}} else {dd.isOpen = false}}}.setOnInputListener { s, basicDialog ->viewModel.searchDepartmentList("0", s)}.addOnDismissListener(object : BasicDialog.OnDismissListener {override fun onDismiss(dialog: BasicDialog?) {setProgressShow(true)builder.setSearchData(arrayListOf())builder.setDefaultInput("")}}).setInputType(InputType.TYPE_CLASS_TEXT).show()setProgressShow(false)}/*** 设置部门名称文字变色*/private fun setDepartTxt(content: String) {val weekStr = content.substring(0, content.lastIndexOf("/") + 1)val weekColor =  ContextCompat.getColor(this, R.color.color_BFBFBF)val normalColor = ContextCompat.getColor(this, R.color.color_303030)setPartText(binding.tvDepart, content, weekStr, normalColor, weekColor)}companion object {var curAdapter: DepartTreeAdapter? = nullvar lastSelectBean: DepartModel? = null}

这里解释下为什么放了静态的curAdapter和lastSelectBean吧(如果不需要选中效果的话可以不要这块儿)

因为嵌套了多层子级RecyclerView和配套adapter,如果本来选中第一层,改选第二层,那么现在你去notifyAdapter的时候,只能通知到当前第二层的子Adapter,原来第一层已选中的Adapter没法通知刷新到,UI上就无法取消选择,所以直接把它放在Activity里暂存,这样Adapter更新后,Activity里的依然是上次选择时用的那一个。

lastSelectBean为什么不放在Adapter里呢,原因跟上面一样,Adapter一加载子级就是新的Adapter了,lastSelectBean也就变成新的了。

当然这种方法很der哈,但是咱就是工资也很der,这样很合理在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/59456.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

写作 | 人工智能在师生教学场景中的应用前景

正文 本文讨论人工智能在师生教学场景中的应用前景。在开展论述前&#xff0c;首先需要明确一些概念。 第一&#xff0c;什么是人工智能&#xff1f;人工智能&#xff08;Artificial Intelligence&#xff09;&#xff0c; 字面意义&#xff0c;即人工制作的智慧能力。这种智慧…

Java线程6种生命周期及转换

多线程技术是我们后端工程师在面试的时候必问的一个知识点&#xff0c;今天就来盘点一下多线程的相关知识&#xff0c; 先来说下进程&#xff0c;线程及线程的生命周期&#xff1a; 进程&#xff1a;进程就是正在进行中的程序&#xff0c;是没有生命的实体&#xff0c;只有在运…

美格智能5G车规级通信模组: 5G+C-V2X连接汽车通信未来十年

自2019年5G牌照发放开始&#xff0c;经过五年发展&#xff0c;我国5G在基础设施建设、用户规模、创新应用等方面均取得了显著成绩&#xff0c;5G网络建设也即将从基础的大范围覆盖向各产业融合的全场景应用转变。工业和信息化部数据显示&#xff0c;5G行业应用已融入76个国民经…

GooglePlay: 应用和游戏的内容分级

对于后台私信的开发者们,希望能够携带详细过审记录和拒审邮件一同发来,方便我们尽快解决问题 应用与游戏 为您的应用或游戏选择类别和标签选择要添加的标签选择类别并添加标签类别示例与应用、游戏以及两者中所投放广告的内容分级相关的要求应用如何获得内容分级内容分级的用…

多线程--模拟实现定时器--Java

一、定时器的概念 定时器的本质就是一个闹钟&#xff0c;时间到了开始执行某些逻辑。Java标准库中的定时器是Timer。 我们查阅Java文档可以详细看到定时器的使用方法&#xff1a; Timer最核心的方法就是schedule方法。值得注意的是我们通常描述任务是使用Runnable来描述&…

Docker 镜像体积优化实践:从基础镜像重建到层压缩的全流程指南

​ 由于最近在发布的时候发现docker镜像体积变得越来越大&#xff0c;导致整个打包发布流程变得非常耗时了。所以又接到一个差事&#xff0c;优化最终镜像体积。顺便也记录一下docker镜像体积优化的一些步骤。 大概步骤可以分为以下几个步骤&#xff1a; 重做基础镜像&#x…

[linux 驱动]PWM子系统详解

目录 1 描述 2 结构体 2.1 pwm_chip 2.2 pwm_ops 2.3 pwm_device 2.4 pwm_class 3 相关函数 3.1 注册与注销 PWM 控制器 3.1.1 pwmchip_add 3.1.2 pwmchip_remove 3.2 申请与释放 PWM 设备 3.2.1 pwm_request 3.2.2 devm_pwm_get 3.2.3 pwm_free 3.3 控制 PWM …

Linux入门(2)

林纳斯托瓦兹 Linux之父 1. echo echo是向指定文件打印内容 ehco要打印的内容&#xff0c;不加任何操作就默认打印到显示器文件上。 知识点 在Linux下&#xff0c;一切皆文件。 打印到显示器&#xff0c;显示器也是文件。 2.重定向 >重定向操作&#xff0c;>指向的…

如何判断本地DNS是否污染

本地DNS污染是一种比较复杂且会对网络访问产生负面影响的现象。DNS即域名系统&#xff0c;它的主要功能是将便于人们记忆的域名转换为计算机能够理解的IP地址。本地DNS污染是指在本地网络环境中&#xff0c;DNS解析过程受到恶意干扰或错误配置的影响&#xff0c;使得域名被解析…

【数据仓库】Hive 拉链表实践

背景 拉链表是一种数据模型&#xff0c;主要是针对数据仓库设计中表存储数据的方式而定义的&#xff1b;顾名思义&#xff0c;所谓拉链表&#xff0c;就是记录历史。记录一个事务从开始一直到当前状态的所有变化的信息。 拉链表可以避免按每一天存储所有记录造成的海量存储问题…

日常工作采坑,关于图片压缩哪些坑一次性踩完。

文章目录 0.前言1.代码实现2.压缩工具包的配置 0.前言 首先说明一下这个图片压缩为什么那么艰难&#xff0c;主要原因还是在于需求过于奇葩。比较奇葩的原因有如下几点&#xff1a;   1.图片是一个很大的文件&#xff0c;我长这么大还没见过这个大的文件。图下可以图片文件可…

语音识别ic赋能烤箱,离线对话操控,引领智能厨房新体验

一、智能烤箱产品的行业背景 随着科技的飞速发展&#xff0c;智能家居已经成为现代家庭的新宠。智能烤箱作为智能家居的重要组成部分&#xff0c;正逐渐从高端市场走向普通家庭。消费者对于烤箱的需求不再仅仅局限于基本的烘焙功能&#xff0c;而是更加注重其智能化、便捷化和…

一文详解开源ETL工具Kettle!

一、Kettle 是什么 Kettle 是一款开源的 ETL&#xff08;Extract - Transform - Load&#xff09;工具&#xff0c;用于数据抽取、转换和加载。它提供了一个可视化的设计环境&#xff0c;允许用户通过简单的拖拽和配置操作来构建复杂的数据处理工作流&#xff0c;能够处理各种数…

D59【python 接口自动化学习】- python基础之异常

day59 捕获异常常见问题 学习日期&#xff1a;20241105 学习目标&#xff1a;异常 -- 75 避坑指南&#xff1a;编写捕获异常程序时经常出现的问题 学习笔记&#xff1a; 捕获位置设置不当 设置范围不当 捕获处理设置不当 嵌套try-except语法错误 总结 位置&#xff0c;范围…

Java开发配置文件的详情教程配置文件类型

学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把手教你开发炫酷的vbs脚本制作(完善中……&#xff09; 4、牛逼哄哄的 IDEA编程利器技巧(编写中……&#xff09; 5、面经吐血整理的 面试技…

应审稿人要求| pseudo bulk差异分析

一、写在前面 最近有粉丝提问&#xff0c;收到了如下的审稿人意见&#xff1a; 审稿人认为在单细胞测序过程中&#xff0c;利用findMarker通过Wilcox获得的差异基因虽然考虑到了不同组别细胞数量的不同&#xff0c;但是未能考虑到每组样本数量的不同。因此作者希望纳入样本水平…

Android13 系统/用户证书安装相关分析总结(二) 如何增加一个安装系统证书的接口

一、前言 接着上回说&#xff0c;最初是为了写一个SDK的接口&#xff0c;需求大致是增加证书安装卸载的接口&#xff08;系统、用户&#xff09;。于是了解了一下证书相关的处理逻辑&#xff0c;在了解了功能和流程之后&#xff0c;发现settings中支持安装的证书&#xff0c;只…

矩阵特殊打印方式

小伙伴们大家好&#xff0c;好几天没更新了&#xff0c;主要有个比赛。从今天起继续给大家更新&#xff0c;今天给大家带来一种新的题型&#xff1a;矩阵特殊打印方式。 螺旋打印矩阵 解题思路 首先给大家看一下什么是螺旋方式打印&#xff1a; 就像这样一直转圈圈。 我想大多…

C语言 流程控制语句

时间&#xff1a;2024.11.5 一、学习内容 流程控制语句&#xff1a; 通过一些语句&#xff0c;控制程序的执行流程。 1、顺序结构 从上往下依次执行&#xff0c;是程序默认的执行过程。 2、if的第一种格式 if(关系表达式) { 语句体&#xff1b; } //考试奖励&#xff1a;…

03集合基础

目录 1.集合 Collection Map 常用集合 List 接口及其实现 Set 接口及其实现 Map 接口及其实现 Queue 接口及其实现 Deque 接口及其实现 Stack类 并发集合类 工具类 2.ArrayList 3.LinkedList 单向链表的实现 1. 节点类&#xff08;Node&#xff09; 2. 链表类&a…