如何从AndroidStudio 3.5.2中的RecyclerView.ViewHolder(itemView)获取活动?

如何从AndroidStudio 3.5.2中的RecyclerView.ViewHolder(itemView)获取活动?,android,android-studio,kotlin,Android,Android Studio,Kotlin,函数Navigation.findNavController()需要代码a中的活动参数,但我只能通过itemView.context获取上下文 如何在Android Studio中从RecyclerView.ViewHolder(itemView)获取Activity 目前,我必须将private val mActivity:Activity从代码B传递到代码A,这很有效,但我认为这不是一个好方法 添加内容: 米丽安娜·伊塔尼:谢谢 您的代码运行良好。我粘贴FrameLayout xml文件,可

函数
Navigation.findNavController()
需要代码a中的
活动
参数,但我只能通过
itemView.context获取
上下文

如何在Android Studio中从
RecyclerView.ViewHolder(itemView)
获取
Activity

目前,我必须将
private val mActivity:Activity
从代码B传递到代码A,这很有效,但我认为这不是一个好方法

添加内容:

米丽安娜·伊塔尼:谢谢

您的代码运行良好。我粘贴FrameLayout xml文件,可以看到代码C

我很奇怪代码
Navigation.findNavController(temView)…
如何找到NavController控件你能告诉我吗

您知道使用代码
Navigation.findNavController(mActivity,R.id.fragment\u container)
很容易理解,因为NavController的id是
fragment\u container
,并且它是唯一的

代码A

class VideoListAdapter (private val videoList: List<File>, private val mActivity: Activity) : RecyclerView.Adapter<VideoListAdapter.MyViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideoListAdapter.MyViewHolder {
        val v = LayoutInflater.from(parent.context).inflate(R.layout.layout_fragment_video_list_recycleview, parent, false)
        return MyViewHolder(v)
    }

    override fun onBindViewHolder(holder: VideoListAdapter.MyViewHolder, position: Int) {
        holder.bindItems(videoList[position])
    }

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

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

        fun bindItems(aFile: File) {           
            itemView.tvVideoFileName.text=aFile.name
            itemView.btnPlay.setOnClickListener {
                Navigation.findNavController(mActivity, R.id.fragment_container).navigate(
                    UIFragmentVideoListDirections.aVideoList2Video((aFile.absolutePath)) )

            }
        }
    }

}
类VideoListAdapter(private-val-videoList:List,private-val-mActivity:Activity):RecyclerView.Adapter(){
重写CreateViewHolder(父级:ViewGroup,viewType:Int):VideoListAdapter.MyViewHolder{
val v=LayoutFlater.from(parent.context).充气(R.layout.layout\u fragment\u video\u list\u recycleview,parent,false)
返回MyViewHolder(v)
}
覆盖BindViewHolder(holder:VideoListAdapter.MyViewHolder,位置:Int){
holder.bindItems(视频列表[位置])
}
重写getItemCount():Int{
返回videoList.size
}
内部类MyViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){
趣味bindItems(文件:文件){
itemView.tvVideoFileName.text=aFile.name
itemView.btnPlay.setOnClickListener{
findNavController(mActivity,R.id.fragment_容器)。导航(
UIFragmentVideoListDirections.aVideoList2Video((aFile.absolutePath)))
}
}
}
}
代码B

class UIFragmentVideoList : Fragment() {

    private lateinit var listFile: MutableList<File>

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? = inflater.inflate(R.layout.layout_fragment_video_list, container, false)


    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val outputDirectoryOfVideo = getVideoOutputDirectory(requireContext())
        listFile =outputDirectoryOfVideo.listFiles{file -> VIDEO_EXTENSION_WHITELIST.contains(file.extension.toUpperCase())}
                   .sorted().reversed().toMutableList()

        videoRecyclerView.layoutManager =  LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)
        val aVideoListAdapter=VideoListAdapter(listFile,requireActivity())
        videoRecyclerView.adapter=aVideoListAdapter

    }

}
类UIFragmentVideoList:Fragment(){ 私有lateinit变量列表文件:MutableList 覆盖创建视图(充气机:布局充气机,容器:视图组?, savedInstanceState:Bundle?:View?=充气机。充气(R.layout.layout\u fragment\u video\u列表,容器,false) 覆盖已创建的视图(视图:视图,保存状态:捆绑?){ super.onViewCreated(视图,savedInstanceState) val outputDirectoryOfVideo=getVideoOutputDirectory(requireContext()) listFile=outputDirectoryOfVideo.listFiles{file->VIDEO\u EXTENSION\u WHITELIST.contains(file.EXTENSION.toUpperCase())} .sorted().reversed().toMutableList() videoRecyclerView.layoutManager=LinearLayoutManager(requireContext(),RecyclerView.VERTICAL,false) val aVideoListAdapter=VideoListAdapter(listFile,require()) videoRecyclerView.adapter=aVideoListAdapter } }
代码C

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
    >

    <fragment
            android:id="@+id/fragment_container"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:navGraph="@navigation/nav_graph" />

</FrameLayout>

您可以从视图的上下文中检索活动,如下所示:

tailrec fun Context.findActivity(): Activity {
    if (this is Activity) {
        @Suppress("UNCHECKED_CAST")
        return this
    } else {
        if (this is ContextWrapper) {
            return this.baseContext.findActivity()
        }
        throw IllegalStateException("The context chain does not contain Activity!")
    }
}
现在你可以做了

val activity = view.context.findActivity()

可以将函数传递给片段中的适配器。这样你就不必通过活动

class VideoListAdapter (private val videoList: List<File>, val btnPlayClick: (File) -> Unit) : RecyclerView.Adapter<VideoListAdapter.MyViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideoListAdapter.MyViewHolder {
        val v = LayoutInflater.from(parent.context).inflate(R.layout.layout_fragment_video_list_recycleview, parent, false)
        return MyViewHolder(v)
    }

    override fun onBindViewHolder(holder: VideoListAdapter.MyViewHolder, position: Int) {
        holder.bindItems(videoList[position], btnPlayClicked )
    }

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

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

        fun bindItems(aFile: File, click -> (File) -> Unit) {           
            itemView.tvVideoFileName.text=aFile.name
            itemView.btnPlay.setOnClickListener {
                 click(aFile)
            }
        }
    }
}

事实上,我不认为您需要通过活动才能让NavController工作:

我认为更好的办法是:

Navigation.findNavController(temView).navigate(
            UIFragmentVideoListDirections.aVideoList2Video((aFile.absolutePath))
        )
请试着让我知道

添加了答案:

NavHostFragment-实现用于创建片段目的地的NavHost。它有自己的导航控制器和导航图。通常,每个活动都有一个NavHostFragment

导航-用于获取NavController实例和将导航连接到UI事件(如按钮单击)的助手类


NavigationUI-用于将抽屉、底部导航或actionbar等应用程序导航模式与NavController连接的类。

只需使用界面将处理逻辑移动到片段,然后在
UIFragmentVideoList
中调用
navigation.findNavController()
,谢谢!您能在我的问题中看到我添加的内容吗?虽然我经常直接从ViewHolder导航,但最好是将控件传递回ViewModel(通过界面)。@HelloCW如果可以解释的话,请告诉我it@AjahnCharles实际上,我发现这种方法更好,因为没有接口传递。请纠正我,如果有任何官方文件不建议这个问题。这是较少的代码,但它的混合责任。不过,我完全赞成不要先发制人地进行重构!我想这取决于项目的规模。(我投了赞成票!)我喜欢在ViewHolder文件中创建一个
typealias
,以提高可读性:
typealias-OnItemClickListener=(file)->Unit)
。然后,您可以将构造函数参数更改为
val itemclicklinklistener:OnItemClickListener
这鼓励将所有内容耦合到活动,而不是使用接口,这将使单元测试更加困难。但它确实回答了
如何从RecyclerView.ViewHolder(itemView)获取活动的问题
这是我的初衷。如果我们像平常一样处理它,您当然可以像中一样使用接口或函数类型
Navigation.findNavController(temView).navigate(
            UIFragmentVideoListDirections.aVideoList2Video((aFile.absolutePath))
        )