当前位置: 首页 > 知识库问答 >
问题:

如何获得列表的应用程序图标和名称在kotlin回收视图

林哲茂
2023-03-14

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

这是我的代码:

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()




    }

}

listofapps的大小为0,包管理器为空

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

我做错了什么

如何在适配器中不为空的情况下获取活动或上下文

片段中的回收视图

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
}

共有2个答案

柳轶
2023-03-14

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

class AppsAdapter() : RecyclerView.Adapter<AppsAdapter.AppsViewHolder>() {

private var list: MutableList<App> = ArrayList()

constructor(packageManager: PackageManager): this() {
    val packageInfos = packageManager.getInstalledPackages(0)
    for (packageInfo in packageInfos) {
        val appName = packageInfo.applicationInfo.loadLabel(packageManager) as String
        if (appName.startsWith("com.", true)) {
            continue
        }
        val appDrawable = packageInfo.applicationInfo.loadIcon(packageManager)
        list.add(App(appDrawable, appName))
    }
}



override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppsViewHolder {
    val inflater = LayoutInflater.from(parent.context)
    val view: View = inflater.inflate(R.layout.item_app, parent, false)
    return AppsViewHolder(view)
}

override fun onBindViewHolder(holder: AppsViewHolder, position: Int) {
    holder.onBind(list[position])
}

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

class AppsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    fun onBind(app: App) {
        val appIcon = itemView.findViewById<ImageView>(R.id.appIconImageView)
        val textView = itemView.findViewById<TextView>(R.id.appNameTextView)
        appIcon.setImageDrawable(app.appIcon)
        textView.text = app.appName
    }
}}

Where应用。kt是:

class App (val appIcon: Drawable, val appName: String)

而在Main活动中,您应该:

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
}}

柴英博
2023-03-14

由于关注点的分离,适配器不应该负责搜索要显示的数据。

首先,为每个应用程序的信息创建一个数据类,这些信息与您的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]
    }
}

然后,在Activity、Fragment或ViewModel中,您可以使用一个协同程序获取所有数据,这样就不会在主线程上加载drawables。在我的例子中,我在ViewModel中执行此操作,并填充UI订阅的SharedFlow,但为了简单起见,既然您提到了活动,下面是如何在活动中执行此操作:

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
}
 类似资料:
  • 我尝试过各种各样的解决方案,从堆栈溢出没有运气。我想要什么。 我知道不同应用程序的包名 例如,我有一个包名。如何获取此应用程序图标并在ImageView中显示?

  • 如何从XML设置RecyclView layoutManager?

  • 我希望能够得到字符串包名称和图标的所有应用程序安装在我的手机上。我所做的:浏览并找到了这个解决方案 问题是,它将包和类名混合显示,而我无法获取图标。我想要的是向用户显示手机上安装的所有应用程序的列表和图标。我还需要能够获得带有。我假设使用一系列应用程序名和包名,它们的位置相同,我就可以做到这一点。但是我怎样才能用软件包名获得应用程序图标和名称呢。最好是作为数组或ArrayList,我可以将其转换为

  • 我想知道一个应用程序的包名,我只知道那个应用程序的应用程序名。假设我想知道一个电子邮件应用程序的包名,只是它的名字,然后如何得到它 我只知道应用程序名。 这是代码,以获得所有的应用程序的包名称,但我需要知道特定的应用程序。

  • 我正在使用回收器视图显示具有多个视图的项目。每当我启动应用程序时,就会显示一些空白。正好等于我的列表项。我提供了截图,请浏览一下。 我想我的代码没有问题。下面是我的代码RecycerView 适配器代码 请帮帮我。谢谢。

  • 我的谷歌页面上有几个栏目。列数随时间变化(将来可能会添加新列)。如果我的床单看起来像这样,我想得到一张地图或类似的东西: 查看我的工作表 API调用的响应: 换句话说,我想在api响应的工作表中获取列名及其标签。或者,任何类似的方法也会起作用。我不知道该做什么API调用。我知道调用,但我不知道如何获取此表中列的标签。我只能得到一定范围内的数据。我不知道如何获得列的标签。