【问题标题】:Using an Interface twice in the same activity在同一个活动中使用接口两次
【发布时间】:2021-04-20 23:51:19
【问题描述】:

只是让您知道,我对 Kotlin 还很陌生,但我对 Java 有很好的体验。 我在一个活动中有两个回收器视图,具有相同的适配器,但行为不同。在 Java 中,只需在适配器类中创建一个接口并使用方法 setOnItemClick(OnClick onClick) 覆盖它,但在 Kotlin 中,情况似乎有所不同。 我看到人们在活动中覆盖了界面,这只会作为一种行为...... 有什么建议吗?

更新:见下面的代码:

适配器类:

class RoleAdapter(context : Context, list : ArrayList<Role>) : RecyclerView.Adapter<RoleAdapter.MyViewHolder>() {

    private var list : ArrayList<Role>? = null
    private var context : Context? = null
    private var listener : OnItemClick? = null

    /**
     * Handle click events on Items.
     * @see RoleAdapter
     */
    interface OnItemClick {

        fun onClick(position : Int)
        fun onHold(position: Int) : Boolean
    }


    /**
     * Return the current list of items displayed
     */
    fun getList() : ArrayList<Role> = list!!

    init {
        this.list = list
        this.context = context
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        return MyViewHolder(
            LayoutInflater.from(parent.context).
            inflate(R.layout.item_role,parent,false)
        )
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val item : Role = list!![position]

        holder.icon.setImageDrawable(Icons.getDrawableIcon(icon = item.getIcon()!!, context = context!!))
        holder.text.text = item.getName()

        holder.itemView.setOnClickListener {
            if (listener != null) listener!!.onClick(holder.adapterPosition)
        }

        holder.itemView.setOnLongClickListener{
            if (listener != null) listener!!.onHold(holder.adapterPosition)
            return@setOnLongClickListener true

        }
    }

    override fun getItemCount(): Int {
        return list!!.size
    }

    class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        val icon : ImageView = itemView.findViewById(R.id.item_icon)
        val text : TextView = itemView.findViewById(R.id.item_text)
    }

    /**
     * Override the adapter's listener with a new one.
     * @param listener new listener
     */
    fun setListener(listener : OnItemClick){
        this.listener = listener
    }

    /**
     * Add an element to the list displayed by the adapter
     * @param item item to insert
     * @param position insertion position
     */
    fun addItem(item : Role, position: Int){
        list!!.add(item)
        notifyItemInserted(position)
    }

    /**
     * Remove an element from the list displayed by the adapter
     * @param position position of the item to be removed
     */
    fun removeItem(position : Int){
        list!!.removeAt(position)
        notifyItemRemoved(position)
    }
}

活动

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

       
        setContentView(R.layout.activity_new_game)

        currentPlayersRV = findViewById(R.id.current_players_rv)
        availableRolesRV = findViewById(R.id.roles_rv)

        currentPlayersAdapter = RoleAdapter(context = applicationContext, list = ArrayList<Role>())
        currentPlayersAdapter!!.setListener(INSERT_LISTENER_1)

        currentPlayersRV!!.layoutManager = GridLayoutManager(baseContext,3)
        currentPlayersRV!!.adapter = currentPlayersAdapter
        availableRolesAdapter = RoleAdapter(context = applicationContext, list = Role.getRoles(applicationContext))
        availableRolesAdapter!!.setListener(INSERT_LISTENER_2)
        availableRolesRV!!.layoutManager = GridLayoutManager(baseContext, 3)
        availableRolesRV!!.adapter = availableRolesAdapter

    }

【问题讨论】:

  • 接口在 Kotlin 和 Java 中的行为方式相同,但 Kotlin 还提供了一种通过委托给实现该接口的另一个对象来实现接口的方法。不过听起来不像你描述的那样。我们必须看看你在说什么的例子。
  • 我马上更新。
  • 如果您还在这里,请更新...

标签: android kotlin android-recyclerview interface


【解决方案1】:

您已经描述了两种实现接口的方法,这两种方法都可以在 Java 或 Kotlin 中完成。

  1. 片段或活动类实现接口本身。您的接口的函数签名不提供适配器传递自身的方式,因此如果您将此策略与多个适配器一起使用,它们都必须以完全相同的方式运行。这只有在两个适配器都引用相同的数据列表时才有效。
// Java
public class MyActivity extends AppCompatActivity implements RoleAdapter.Listener {

    private List<Something> data;

    // ...

    public void onClick(int position) {
        doSomething(data.get(position));
    }

    public boolean onHold(int position) {
        return doSomethingElse(data.get(position));
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ...
        adapter.setListener(this);
        adapter2.setListener(this);
    }
}
// Kotlin
class MyActivity: AppCompatActivity(), RoleAdapter.Listener {

    private var data: List<Something>? = null

    // ...

    fun onClick(position : Int) {
        data?.get(position)?.let { doSomething(it) }
    }
 
    fun onHold(position: Int) : Boolean {
        return data?.get(position)?.let { doSomethingElse(it) }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        adapter.listener = this
        adapter2.listener = this
    }
}
  1. 为两个适配器中的每一个使用接口的不同匿名对象实现。
// Java
public class MyActivity extends AppCompatActivity {

    private List<Something> data;
    private List<Something> data2;

    private RoleAdapter.Listener adapterListener = new RoleAdapter.Listener() {
        public void onClick(int position) {
            doSomething(data.get(position));
        }

        public boolean onHold(int position) {
            return doSomethingElse(data.get(position));
        }
    };

    private RoleAdapter.Listener adapterListener2 = new RoleAdapter.Listener() {
        public void onClick(int position) {
            doSomething(data2.get(position));
        }

        public boolean onHold(int position) {
            return doSomethingElse(data2.get(position));
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ...
        adapter.setListener(adapterListener);
        adapter2.setListener(adapterListener2);
    }
}
// Kotlin
class MyActivity: AppCompatActivity() {

    private var data: List<Something>? = null
    private var data2: List<Something>? = null

    private val adapterListener = object: RoleAdapter.Listener {
        fun onClick(position : Int) {
            data?.get(position)?.let { doSomething(it) }
        }
 
        fun onHold(position: Int) : Boolean {
            return data?.get(position)?.let { doSomethingElse(it) }
        }
    }

    private val adapterListener2 = object: RoleAdapter.Listener {
        fun onClick(position : Int) {
            data2?.get(position)?.let { doSomething(it) }
        }
 
        fun onHold(position: Int) : Boolean {
            return data2?.get(position)?.let { doSomethingElse(it) }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        adapter.listener = adapterListener
        adapter2.listener = adapterListener2
    }
}

在我看来,如果您更改侦听器函数签名以返回实际项目而不是项目位置,则不会那么复杂。然后 Activity 不必向适配器冗余地跟踪数据。它还允许您将策略 1 与多个适配器和数据集一起使用。示例:

// in Adapter class:
interface OnItemClick {
    fun onClick(item: Role)
    fun onHold(item: Role) : Boolean
}

//...

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val item : Role = list!![position]

        holder.icon.setImageDrawable(Icons.getDrawableIcon(icon = item.getIcon()!!, context = context!!))
        holder.text.text = item.getName()

        holder.itemView.setOnClickListener {
            listener?.onClick(item)
        }

        holder.itemView.setOnLongClickListener{
            listener?.onHold(item)
            return@setOnLongClickListener true

        }
    }

另外,Kotlin 具有属性,因此您的 getListenersetListener 函数是完全多余的。您应该删除它们并将listener 设为公共属性。

另外,!! 的使用几乎总是一种代码异味。如果某些内容可能为 null,请使用安全调用 ?.,或者如果该属性不应该为 null,则使该属性不可为 null。

【讨论】:

  • 第二种方法就是我的意思,还是谢谢你!
猜你喜欢
  • 2018-04-28
  • 1970-01-01
  • 1970-01-01
  • 2016-08-31
  • 1970-01-01
  • 2020-12-11
  • 1970-01-01
  • 1970-01-01
  • 2014-07-14
相关资源
最近更新 更多