Skip to content

Commit dd6a2a4

Browse files
committed
Upload file
1 parent 76b6d95 commit dd6a2a4

2 files changed

Lines changed: 46 additions & 13 deletions

File tree

common/src/main/java/com/omarea/common/ui/AdapterAppChooser.kt

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,25 @@ class AdapterAppChooser(
2727
var selected: Boolean = false
2828
}
2929

30+
// ================= Coroutine scope (THAY GlobalScope) =================
31+
32+
private val job = SupervisorJob()
33+
private val scope = CoroutineScope(Dispatchers.Main + job)
34+
35+
// ======================================================================
36+
3037
private var selectStateListener: SelectStateListener? = null
3138
private var filter: Filter? = null
3239

3340
internal var filterApps: ArrayList<AppInfo> = apps
3441
private val mLock = Any()
3542

36-
private class ArrayFilter(private val adapter: AdapterAppChooser) : Filter() {
43+
// ================= Filter =================
3744

45+
private class ArrayFilter(private val adapter: AdapterAppChooser) : Filter() {
3846
override fun performFiltering(constraint: CharSequence?): FilterResults {
3947
val results = FilterResults()
40-
val prefix = constraint?.toString()?.lowercase() ?: ""
48+
val prefix = constraint?.toString()?.lowercase(Locale.getDefault()) ?: ""
4149

4250
if (prefix.isEmpty()) {
4351
synchronized(adapter.mLock) {
@@ -56,8 +64,8 @@ class AdapterAppChooser(
5664
continue
5765
}
5866

59-
val name = item.appName?.lowercase() ?: ""
60-
val pkg = item.packageName?.lowercase() ?: ""
67+
val name = item.appName?.lowercase(Locale.getDefault()) ?: ""
68+
val pkg = item.packageName?.lowercase(Locale.getDefault()) ?: ""
6169

6270
if (name.contains(prefix) || pkg.contains(prefix)) {
6371
newValues.add(item)
@@ -83,8 +91,12 @@ class AdapterAppChooser(
8391
return filter!!
8492
}
8593

94+
// ================= Icon cache =================
95+
8696
private val iconCaches = LruCache<String, Drawable>(100)
8797

98+
// ================= Adapter basic =================
99+
88100
override fun getCount(): Int = filterApps.size
89101

90102
override fun getItem(position: Int): AppInfo = filterApps[position]
@@ -103,31 +115,37 @@ class AdapterAppChooser(
103115
return convertView
104116
}
105117

118+
// ================= Icon loading =================
119+
106120
private fun loadIcon(app: AppInfo): Deferred<Drawable?> {
107-
return GlobalScope.async(Dispatchers.IO) {
121+
return scope.async(Dispatchers.IO) {
108122
val pkg = app.packageName ?: return@async null
109-
val cached = iconCaches.get(pkg)
110-
if (cached != null) return@async cached
123+
124+
iconCaches.get(pkg)?.let { return@async it }
111125

112126
if (!app.notFound) {
113127
try {
114128
val info = context.packageManager.getPackageInfo(pkg, 0)
115129
val icon = info.applicationInfo?.loadIcon(context.packageManager)
116-
if (icon != null) iconCaches.put(pkg, icon)
130+
if (icon != null) {
131+
iconCaches.put(pkg, icon)
132+
return@async icon
133+
}
117134
} catch (_: Exception) {
118135
app.notFound = true
119136
}
120137
}
121-
iconCaches.get(pkg)
138+
null
122139
}
123140
}
124141

142+
// ================= Row binding =================
143+
125144
fun updateRow(position: Int, convertView: View) {
126145
val item = getItem(position)
127146

128-
val holder = (convertView.tag as? ViewHolder) ?: ViewHolder(convertView).also {
129-
convertView.tag = it
130-
}
147+
val holder = (convertView.tag as? ViewHolder)
148+
?: ViewHolder(convertView).also { convertView.tag = it }
131149

132150
holder.itemTitle.text = item.appName ?: ""
133151
holder.itemDesc.text = item.packageName ?: ""
@@ -148,14 +166,16 @@ class AdapterAppChooser(
148166
val pkg = item.packageName
149167
holder.imgView.tag = pkg
150168

151-
GlobalScope.launch(Dispatchers.Main) {
169+
scope.launch {
152170
val icon = loadIcon(item).await()
153171
if (icon != null && holder.imgView.tag == pkg) {
154172
holder.imgView.setImageDrawable(icon)
155173
}
156174
}
157175
}
158176

177+
// ================= Selection =================
178+
159179
fun setSelectAllState(allSelected: Boolean) {
160180
apps.forEach { it.selected = allSelected }
161181
notifyDataSetChanged()
@@ -169,6 +189,16 @@ class AdapterAppChooser(
169189
this.selectStateListener = listener
170190
}
171191

192+
// ================= Release (QUAN TRỌNG) =================
193+
194+
fun release() {
195+
job.cancel() // hủy toàn bộ coroutine
196+
iconCaches.evictAll() // clear cache icon
197+
selectStateListener = null
198+
}
199+
200+
// ================= ViewHolder =================
201+
172202
class ViewHolder(view: View) {
173203
val itemTitle: TextView = view.findViewById(R.id.ItemTitle)
174204
val itemDesc: TextView = view.findViewById(R.id.ItemDesc)

common/src/main/java/com/omarea/common/ui/DialogAppChooser.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,5 +164,8 @@ class DialogAppChooser(
164164

165165
override fun onDismiss(dialog: DialogInterface) {
166166
super.onDismiss(dialog)
167+
if (::adapter.isInitialized) {
168+
adapter.release()
169+
}
167170
}
168171
}

0 commit comments

Comments
 (0)