在同一 activity 中使用接口两次
Using an Interface twice in the same activity
只是想让你知道,我对 Kotlin 很陌生,但我对 Java 有很好的体验。
我在 activity 中有两个回收器视图,具有相同的适配器,但行为不同。在 Java 中,只需在适配器 class 中创建一个接口并使用方法 setOnItemClick(OnClick onClick) 覆盖它,但在 Kotlin 中,情况似乎有所不同。
我看到人们重写了 activity 中的界面,那只会作为一种行为......
有什么建议吗?
更新:见下面的代码:
适配器Class:
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)
}
}
Activity
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
}
您已经描述了两种实现接口的方法,这两种方法都可以在 Java 或 Kotlin 中完成。
- Fragment 或 Activity class 实现接口本身。您的接口的函数签名不提供适配器传递自身的方式,因此如果您将此策略用于多个适配器,它们都必须以完全相同的方式运行。这仅在两个适配器都引用相同的数据列表时才有效。
// 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
}
}
- 为两个适配器分别使用接口的不同匿名对象实现。
// 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
}
}
在我看来,如果将侦听器函数签名更改为 return 实际项目而不是项目位置,则不会那么复杂。这样 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 有属性,所以你的 getListener
和 setListener
函数是完全多余的。你应该删除它们并使 listener
成为 public 属性.
此外,使用 !!
几乎总是一种代码味道。如果某些东西可能为空,则使用安全调用 ?.
,或者如果它不应该为空,则使 属性 不可为空。
只是想让你知道,我对 Kotlin 很陌生,但我对 Java 有很好的体验。 我在 activity 中有两个回收器视图,具有相同的适配器,但行为不同。在 Java 中,只需在适配器 class 中创建一个接口并使用方法 setOnItemClick(OnClick onClick) 覆盖它,但在 Kotlin 中,情况似乎有所不同。 我看到人们重写了 activity 中的界面,那只会作为一种行为...... 有什么建议吗?
更新:见下面的代码:
适配器Class:
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)
}
}
Activity
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
}
您已经描述了两种实现接口的方法,这两种方法都可以在 Java 或 Kotlin 中完成。
- Fragment 或 Activity class 实现接口本身。您的接口的函数签名不提供适配器传递自身的方式,因此如果您将此策略用于多个适配器,它们都必须以完全相同的方式运行。这仅在两个适配器都引用相同的数据列表时才有效。
// 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
}
}
- 为两个适配器分别使用接口的不同匿名对象实现。
// 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
}
}
在我看来,如果将侦听器函数签名更改为 return 实际项目而不是项目位置,则不会那么复杂。这样 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 有属性,所以你的 getListener
和 setListener
函数是完全多余的。你应该删除它们并使 listener
成为 public 属性.
此外,使用 !!
几乎总是一种代码味道。如果某些东西可能为空,则使用安全调用 ?.
,或者如果它不应该为空,则使 属性 不可为空。