Android 如何将kotlin中的应用程序图标和名称列表获取到recyclerview

Android 如何将kotlin中的应用程序图标和名称列表获取到recyclerview,android,android-layout,kotlin,android-recyclerview,Android,Android Layout,Kotlin,Android Recyclerview,所以我是kotlin的新手,我正在尝试让设备上所有安装的应用程序返回到recycler查看我的问题是recycler适配器中的所有活动返回null,即使我传递了上下文 这是我的代码: class Games_listx : RecyclerView.Adapter<Games_listx.viewxlist>() { var appsx = Gamesff() var listofapps = ArrayList<String>() var

所以我是kotlin的新手,我正在尝试让设备上所有安装的应用程序返回到recycler查看我的问题是recycler适配器中的所有活动返回null,即使我传递了上下文

这是我的代码:

class Games_listx  : RecyclerView.Adapter<Games_listx.viewxlist>() {

    var appsx = Gamesff()
    var listofapps  = ArrayList<String>()
    var  all_apps : MutableList<ApplicationInfo>? = null
    var icons  : Drawable? = null

    class viewxlist(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val txt_game = itemView.findViewById<View>(R.id.txtgames) as TextView
        val im_game = itemView.findViewById<View>(R.id.imgames) as ImageView
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Games_listx.viewxlist {




        val layoutInflater = LayoutInflater.from(parent.context)

        val view = layoutInflater.inflate(R.layout.lay_allgames,parent,false)


        all_apps = appsx.activity?.packageManager?.getInstalledApplications(0)
        Log.w("apps" , "app " + all_apps?.size)

        for (app in all_apps?.indices!!) {
            val name = all_apps?.get(app)?.loadLabel(appsx.activity?.packageManager!!)

            if  (!(name?.startsWith("com.")!!)) {
                listofapps.add(name?.toString())
            }

        }
        return viewxlist(view)
    }

    override fun getItemCount(): Int {

       return listofapps.size
    }

    override fun onBindViewHolder(holder: Games_listx.viewxlist, position: Int) {


        holder.txt_game.text = listofapps.get(position).toString()




    }

}
classgames\u listx:RecyclerView.Adapter(){
var appsx=Gamesff()
var listofapps=ArrayList()
var all_应用程序:可变列表?=null
变量图标:可绘制?=null
类ViewXLList(itemView:View):RecyclerView.ViewHolder(itemView){
val txt_game=itemviewbyd(R.id.txtgames)作为文本视图
val im_game=itemView.findviewbyd(R.id.imgames)作为ImageView
}
override fun onCreateViewHolder(父级:ViewGroup,viewType:Int):Games\u listx.viewxlist{
val layoutInflater=layoutInflater.from(parent.context)
val view=LAYOUTINGFLATER.充气(R.LAYOU.lay_allgames,父项,false)
所有应用程序=appsx.activity?.packageManager?.getInstalledApplications(0)
Log.w(“应用程序”、“应用程序”+所有应用程序?.size)
for(所有应用中的应用?.index!!){
val name=all_apps?.get(app)?.loadLabel(appsx.activity?.packageManager!!)
如果(!(名称?.startsWith(“com”)!!){
listofapps.add(名称?.toString())
}
}
返回viewxlist(视图)
}
重写getItemCount():Int{
返回listofapps.size
}
覆盖BindViewHolder(holder:Games\u listx.viewxlist,位置:Int){
holder.txt_game.text=listofapps.get(position.toString())
}
}
listofapps的大小为0,包管理器为空

我使用相同的代码在onstart中获取应用程序,并且它可以正常工作

我做错了什么

如何在适配器中获取活动或上下文而不为null

片段中的回收视图

class Gamesff : Fragment() {





override fun onStart() {
    super.onStart()



}

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {

    val viewx = inflater.inflate(R.layout.fragment_gamesff,container,false)

    val all_games_list = viewx.findViewById<View>(R.id.gamelistfounds) as RecyclerView
    val add_game_folder = viewx.findViewById(R.id.txtaddgamefolder) as TextView









    add_game_folder.setOnClickListener {

        Toast.makeText(activity,"Make your own gaming folder",Toast.LENGTH_SHORT).show()

        val i = Intent(activity,GamingFolder::class.java)
        i.action = "add"

        startActivity(i)

    }


    val gridlay = GridLayoutManager(activity,4,GridLayoutManager.VERTICAL,false)

    all_games_list.layoutManager = gridlay
    all_games_list.fitsSystemWindows = true
    all_games_list.hasFixedSize()
    all_games_list.adapter = Games_listx()


    return viewx
}
class Gamesff:Fragment(){
覆盖有趣的onStart(){
super.onStart()
}
覆盖创建视图(
充气机,
容器:视图组?,
savedInstanceState:捆绑?
):查看{
val viewx=充气机。充气(右布局。碎片,容器,false)
val all_games_list=viewx.findviewbyd(R.id.gamelistfounds)作为RecyclerView
val add_game_folder=viewx.findviewbyd(R.id.txtaddgamefolder)作为文本视图
添加游戏文件夹。setOnClickListener{
Toast.makeText(活动“创建您自己的游戏文件夹”,Toast.LENGTH\u SHORT.show())
val i=Intent(活动,GamingFolder::class.java)
i、 action=“添加”
星触觉(一)
}
val gridlay=GridLayoutManager(活动,4,GridLayoutManager.VERTICAL,false)
所有游戏列表。布局管理器=网格布局
所有游戏\u list.fitsSystemWindows=true
所有游戏列表。hasFixedSize()
all_games_list.adapter=games_listx()
返回视图x
}

如果我理解正确,您需要一种在适配器中初始化数据的方法。 您所做的错误是尝试初始化
onCreateViewHolder()
中的列表。在调用
onCreateViewHolder()
之前,将调用
getItemCount()
。它将返回0,因为它返回了0
onCreateViewHolder()
将永远不会被调用。您应该做的是初始化
构造函数()中的
列表应用程序

在主要活动中,您应该:

class MainActivity : AppCompatActivity() {

private lateinit var adapter: AppsAdapter

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    adapter = AppsAdapter(packageManager)
    val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
    recyclerView.layoutManager = GridLayoutManager(
        this,
        4,
        GridLayoutManager.VERTICAL,
        false
    )
    recyclerView.adapter = adapter
}}
class MainActivity:AppCompatActivity(){
私有lateinit变量适配器:AppsAdapter
重写创建时的乐趣(savedInstanceState:Bundle?){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
适配器=应用适配器(packageManager)
val recyclerView=findviewbyd(R.id.recyclerView)
recyclerView.layoutManager=GridLayoutManager(
这
4.
GridLayoutManager.VERTICAL,
假的
)
recyclerView.adapter=适配器
}}
由于问题分离,适配器不应负责搜索要显示的数据

首先,为每个应用程序的信息创建一个数据类,这些信息与您的RecyclerView显示或操作相关,例如:

data class AppInfo (
    val appName: String,
    val packageName: String,
    val icon: Drawable
)

您的适配器应该为数据列表公开一个公共属性。这是任何适配器的工作方式。您可以在
onCreateViewHolder
中创建视图和ViewHolder,并在
onBindViewHolder
中绑定值。我喜欢设置ViewHolder在内部处理此问题,因此我的onBind和onCreate函数非常简单。我还为项单击侦听器公开单个属性,因此单击功能也在外部处理。适配器除了将数据和逻辑连接到视图之外,不做任何事情

class AppsListAdapter: RecyclerView.Adapter<AppsListAdapter.ViewHolder>() {

    inner class ViewHolder(val rootView: ViewGroup): RecyclerView.ViewHolder(rootView), View.OnClickListener {

        init { rootView.onClickListener = this }

        val titleView = rootView.findViewById<TextView>(android.R.id.title)
        val iconView = rootView.findViewById<ImageView>(android.R.id.icon)

        var data: AppInfo? = null
            set(value) {
                field = value
                value ?: return
                titleView.text = value.appName
                iconView.setImageDrawable(value.icon)
            }

        override fun onClick(v: View) {
            data?.let {
                onListItemClick(it)
            }
        }
    }

    fun interface OnItemClickListener {
        fun onItemClick(appInfo: AppInfo)
    }

    var dataList: List<AppInfo> = emptyList()
        set(value) {
            field = value
            notifyDataSetChanged()
        }

    private var onItemClickListener: OnItemClickListener? = null
    
    fun setOnItemClickListener(listener: OnItemClickListener) 
        this.onItemClickListener = listener
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
        ViewHolder(
            LayoutInflater.from(parent.context)
                .inflate(R.layout.app_list_item, parent, false)
        )

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.data = dataList[position]
    }
}
事实上,由于用户可能安装了许多应用程序,我也支持在获得初始列表和每五个图标后提前取消协同程序,如下所示:

lifecycleScope.launch {
    val packageManager = context.packageManager
    val appsData = withContext(Dispatchers.IO) { 
        packageManager.getInstalledPackages(0)
            .filterNot { it.packageName.startsWith("com.") }
            .mapIndexed { idx, it ->
                if (idx % 5 == 0) yield()
                AppsInfo(
                    it.applicationInfo.loadLabel(packageManager).toString(),
                    it.packageName,
                    it.applicationInfo.loadIcon(packageManager)
                )
            }
    }
    adapter.dataList = appsData
}

onCreateViewHolder
被重复调用,对于RecyclerView中的每个可见列表项视图组调用一次。如果列表为空,则从一开始就不会调用它。您需要创建数据列表并在适配器类外部填充它,然后将准备好的数据列表传递给适配器。@Tenfour04谢谢,我知道如何调用它adapter在java中工作您可以在adapter中处理数据并访问上下文,但在kotlin中,它始终返回null。它必须是在kotlin和java中工作的方式。您正在
onCreateViewHolder()中获取已安装应用程序的列表
,这没什么意义。@tenfour04那么,如何将可绘制内容从活动中的应用程序信息传递到适配器,而不是保存在数组中的路径呢?谢谢你的回答,它的完整答案现在我知道kotlin是如何工作的了,我发现了我的问题,还有一件事,如果不是在java中的kotlin中,如果(!s.startwith(…){}我如何在kotlin中做到这一点?在Kotlini中也一样,如果kotlin中的(!string.startwith(“”{})不是startwith,而是!出现错误未解析引用,则使用此选项
class AppsListAdapter: RecyclerView.Adapter<AppsListAdapter.ViewHolder>() {

    inner class ViewHolder(val rootView: ViewGroup): RecyclerView.ViewHolder(rootView), View.OnClickListener {

        init { rootView.onClickListener = this }

        val titleView = rootView.findViewById<TextView>(android.R.id.title)
        val iconView = rootView.findViewById<ImageView>(android.R.id.icon)

        var data: AppInfo? = null
            set(value) {
                field = value
                value ?: return
                titleView.text = value.appName
                iconView.setImageDrawable(value.icon)
            }

        override fun onClick(v: View) {
            data?.let {
                onListItemClick(it)
            }
        }
    }

    fun interface OnItemClickListener {
        fun onItemClick(appInfo: AppInfo)
    }

    var dataList: List<AppInfo> = emptyList()
        set(value) {
            field = value
            notifyDataSetChanged()
        }

    private var onItemClickListener: OnItemClickListener? = null
    
    fun setOnItemClickListener(listener: OnItemClickListener) 
        this.onItemClickListener = listener
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
        ViewHolder(
            LayoutInflater.from(parent.context)
                .inflate(R.layout.app_list_item, parent, false)
        )

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.data = dataList[position]
    }
}
val adapter = AppsListAdapter()
adapter.setOnItemClickListener { // Set what to do when item is clicked
    Log.d("item click", "Clicked package ${it.packageName}")
    
}
myRecyclerView.adapter = adapter

lifecycleScope.launch {
    val packageManager = context.packageManager
    val appsData = withContext(Dispatchers.IO) { // do all loading in background thread
        packageManager.getInstalledPackages(0)
            .filterNot { it.packageName.startsWith("com.") } // any filtering you want before loading
            .map {
                AppInfo(
                    it.applicationInfo.loadLabel(packageManager).toString(),
                    it.packageName,
                    it.applicationInfo.loadIcon(packageManager)
                )
            }
    }
    adapter.dataList = appsData
}
lifecycleScope.launch {
    val packageManager = context.packageManager
    val appsData = withContext(Dispatchers.IO) { 
        packageManager.getInstalledPackages(0)
            .filterNot { it.packageName.startsWith("com.") }
            .mapIndexed { idx, it ->
                if (idx % 5 == 0) yield()
                AppsInfo(
                    it.applicationInfo.loadLabel(packageManager).toString(),
                    it.packageName,
                    it.applicationInfo.loadIcon(packageManager)
                )
            }
    }
    adapter.dataList = appsData
}