Android 如何将kotlin中的应用程序图标和名称列表获取到recyclerview
所以我是kotlin的新手,我正在尝试让设备上所有安装的应用程序返回到recycler查看我的问题是recycler适配器中的所有活动返回null,即使我传递了上下文 这是我的代码: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
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,因为它返回了0onCreateViewHolder()
将永远不会被调用。您应该做的是初始化构造函数()中的列表应用程序
在主要活动中,您应该:
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
}