Skip to content

Commit

Permalink
Main interface list performance optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
2dust committed Aug 13, 2024
1 parent 0a09966 commit 47166b9
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 38 deletions.
9 changes: 9 additions & 0 deletions V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/ProfileItem.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.v2ray.ang.dto

data class ProfileItem(
val configType: EConfigType,
var subscriptionId: String = "",
var remarks: String = "",
var server: String?,
var serverPort: Int?,
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.v2ray.ang.dto

data class ServersCache(val guid: String,
val config: ServerConfig)
val profile: ProfileItem)
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,6 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
.setPositiveButton(android.R.string.ok) { _, _ ->
mainViewModel.removeDuplicateServer()
mainViewModel.reloadServerList()
}
.setNegativeButton(android.R.string.no) {_, _ ->
//do noting
Expand Down
21 changes: 10 additions & 11 deletions V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import com.v2ray.ang.service.V2RayServiceManager
import com.v2ray.ang.util.AngConfigManager
import com.v2ray.ang.util.MmkvManager
import com.v2ray.ang.util.Utils
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import java.util.concurrent.TimeUnit

class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<MainRecyclerAdapter.BaseViewHolder>()
Expand All @@ -51,7 +51,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
if (holder is MainViewHolder) {
val guid = mActivity.mainViewModel.serversCache[position].guid
val config = mActivity.mainViewModel.serversCache[position].config
val profile = mActivity.mainViewModel.serversCache[position].profile
// //filter
// if (mActivity.mainViewModel.subscriptionId.isNotEmpty()
// && mActivity.mainViewModel.subscriptionId != config.subscriptionId
Expand All @@ -61,10 +61,9 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
// holder.itemMainBinding.cardView.visibility = View.VISIBLE
// }

val outbound = config.getProxyOutbound()
val aff = MmkvManager.decodeServerAffiliationInfo(guid)

holder.itemMainBinding.tvName.text = config.remarks
holder.itemMainBinding.tvName.text = profile.remarks
holder.itemView.setBackgroundColor(Color.TRANSPARENT)
holder.itemMainBinding.tvTestResult.text = aff?.getTestDelayString() ?: ""
if ((aff?.testDelayMillis ?: 0L) < 0L) {
Expand All @@ -78,27 +77,27 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
holder.itemMainBinding.layoutIndicator.setBackgroundResource(0)
}
holder.itemMainBinding.tvSubscription.text = ""
val json = subStorage?.decodeString(config.subscriptionId)
val json = subStorage?.decodeString(profile.subscriptionId)
if (!json.isNullOrBlank()) {
val sub = Gson().fromJson(json, SubscriptionItem::class.java)
holder.itemMainBinding.tvSubscription.text = sub.remarks
}

var shareOptions = share_method.asList()
when (config.configType) {
when (profile.configType) {
EConfigType.CUSTOM -> {
holder.itemMainBinding.tvType.text = mActivity.getString(R.string.server_customize_config)
shareOptions = shareOptions.takeLast(1)
}
EConfigType.VLESS -> {
holder.itemMainBinding.tvType.text = config.configType.name
holder.itemMainBinding.tvType.text = profile.configType.name
}
else -> {
holder.itemMainBinding.tvType.text = config.configType.name.lowercase()
holder.itemMainBinding.tvType.text = profile.configType.name.lowercase()
}
}

val strState = "${outbound?.getServerAddress()?.dropLast(3)}*** : ${outbound?.getServerPort() ?: ""}"
val strState = "${profile?.server?.dropLast(3)}*** : ${profile?.serverPort ?: ""}"

holder.itemMainBinding.tvStatistics.text = strState

Expand All @@ -107,7 +106,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
try {
when (i) {
0 -> {
if (config.configType == EConfigType.CUSTOM) {
if (profile.configType == EConfigType.CUSTOM) {
shareFullContent(guid)
} else {
val ivBinding = ItemQrcodeBinding.inflate(LayoutInflater.from(mActivity))
Expand All @@ -134,7 +133,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
holder.itemMainBinding.layoutEdit.setOnClickListener {
val intent = Intent().putExtra("guid", guid)
.putExtra("isRunning", isRunning)
if (config.configType == EConfigType.CUSTOM) {
if (profile.configType == EConfigType.CUSTOM) {
mActivity.startActivity(intent.setClass(mActivity, ServerCustomConfigActivity::class.java))
} else {
mActivity.startActivity(intent.setClass(mActivity, ServerActivity::class.java))
Expand Down
24 changes: 24 additions & 0 deletions V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.v2ray.ang.util
import com.google.gson.Gson
import com.tencent.mmkv.MMKV
import com.v2ray.ang.dto.AssetUrlItem
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.dto.ServerAffiliationInfo
import com.v2ray.ang.dto.ServerConfig
import com.v2ray.ang.dto.SubscriptionItem
Expand All @@ -11,6 +12,7 @@ import java.net.URI
object MmkvManager {
const val ID_MAIN = "MAIN"
const val ID_SERVER_CONFIG = "SERVER_CONFIG"
const val ID_PROFILE_CONFIG = "PROFILE_CONFIG"
const val ID_SERVER_RAW = "SERVER_RAW"
const val ID_SERVER_AFF = "SERVER_AFF"
const val ID_SUB = "SUB"
Expand All @@ -21,6 +23,7 @@ object MmkvManager {

private val mainStorage by lazy { MMKV.mmkvWithID(ID_MAIN, MMKV.MULTI_PROCESS_MODE) }
private val serverStorage by lazy { MMKV.mmkvWithID(ID_SERVER_CONFIG, MMKV.MULTI_PROCESS_MODE) }
private val profileStorage by lazy { MMKV.mmkvWithID(ID_PROFILE_CONFIG, MMKV.MULTI_PROCESS_MODE) }
private val serverAffStorage by lazy { MMKV.mmkvWithID(ID_SERVER_AFF, MMKV.MULTI_PROCESS_MODE) }
private val subStorage by lazy { MMKV.mmkvWithID(ID_SUB, MMKV.MULTI_PROCESS_MODE) }
private val assetStorage by lazy { MMKV.mmkvWithID(ID_ASSET, MMKV.MULTI_PROCESS_MODE) }
Expand All @@ -45,6 +48,17 @@ object MmkvManager {
return Gson().fromJson(json, ServerConfig::class.java)
}

fun decodeProfileConfig(guid: String): ProfileItem? {
if (guid.isBlank()) {
return null
}
val json = profileStorage?.decodeString(guid)
if (json.isNullOrBlank()) {
return null
}
return Gson().fromJson(json, ProfileItem::class.java)
}

fun encodeServerConfig(guid: String, config: ServerConfig): String {
val key = guid.ifBlank { Utils.getUuid() }
serverStorage?.encode(key, Gson().toJson(config))
Expand All @@ -56,6 +70,14 @@ object MmkvManager {
mainStorage?.encode(KEY_SELECTED_SERVER, key)
}
}
val profile = ProfileItem(
configType = config.configType,
subscriptionId = config.subscriptionId,
remarks = config.remarks,
server = config.getProxyOutbound()?.getServerAddress(),
serverPort = config.getProxyOutbound()?.getServerPort(),
)
profileStorage?.encode(key, Gson().toJson(profile))
return key
}

Expand All @@ -70,6 +92,7 @@ object MmkvManager {
serverList.remove(guid)
mainStorage?.encode(KEY_ANG_CONFIGS, Gson().toJson(serverList))
serverStorage?.remove(guid)
profileStorage?.remove(guid)
serverAffStorage?.remove(guid)
}

Expand Down Expand Up @@ -164,6 +187,7 @@ object MmkvManager {
fun removeAllServer() {
mainStorage?.clearAll()
serverStorage?.clearAll()
profileStorage?.clearAll()
serverAffStorage?.clearAll()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import com.v2ray.ang.AppConfig
import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.R
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.dto.ServerConfig
import com.v2ray.ang.dto.ServersCache
import com.v2ray.ang.dto.V2rayConfig
Expand Down Expand Up @@ -121,7 +122,14 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
val key = MmkvManager.encodeServerConfig("", config)
serverRawStorage?.encode(key, server)
serverList.add(0, key)
serversCache.add(0, ServersCache(key, config))
val profile = ProfileItem(
configType = config.configType,
subscriptionId = config.subscriptionId,
remarks = config.remarks,
server = config.getProxyOutbound()?.getServerAddress(),
serverPort = config.getProxyOutbound()?.getServerPort(),
)
serversCache.add(0, ServersCache(key, profile))
return true
} catch (e: Exception) {
e.printStackTrace()
Expand All @@ -140,14 +148,25 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
fun updateCache() {
serversCache.clear()
for (guid in serverList) {
val config = MmkvManager.decodeServerConfig(guid) ?: continue
if (subscriptionId.isNotEmpty() && subscriptionId != config.subscriptionId) {
var profile = MmkvManager.decodeProfileConfig(guid)
if (profile == null) {
val config = MmkvManager.decodeServerConfig(guid) ?: continue
profile = ProfileItem(
configType = config.configType,
subscriptionId = config.subscriptionId,
remarks = config.remarks,
server = config.getProxyOutbound()?.getServerAddress(),
serverPort = config.getProxyOutbound()?.getServerPort(),
)
MmkvManager.encodeServerConfig(guid, config)
}

if (subscriptionId.isNotEmpty() && subscriptionId != profile.subscriptionId) {
continue
}

// if (keywordFilter.isEmpty() || config.remarks.contains(keywordFilter)) {
serversCache.add(ServersCache(guid, config))
// }
serversCache.add(ServersCache(guid, profile))
}
}

Expand All @@ -159,9 +178,9 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {

getApplication<AngApplication>().toast(R.string.connection_test_testing)
for (item in serversCache) {
item.config.getProxyOutbound()?.let { outbound ->
val serverAddress = outbound.getServerAddress()
val serverPort = outbound.getServerPort()
item.profile.let { outbound ->
val serverAddress = outbound.server
val serverPort = outbound.serverPort
if (serverAddress != null && serverPort != null) {
tcpingTestScope.launch {
val testResult = SpeedtestUtil.tcping(serverAddress, serverPort)
Expand Down Expand Up @@ -236,27 +255,33 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
}

fun removeDuplicateServer() {
val deleteServer = mutableListOf<String>()
serversCache.forEachIndexed { index, it ->
val outbound = it.config.getProxyOutbound()
serversCache.forEachIndexed { index2, it2 ->
if (index2 > index) {
val outbound2 = it2.config.getProxyOutbound()
if (outbound == outbound2 && !deleteServer.contains(it2.guid)) {
deleteServer.add(it2.guid)
viewModelScope.launch(Dispatchers.Default) {
val deleteServer = mutableListOf<String>()
serversCache.forEachIndexed { index, it ->
val outbound = MmkvManager.decodeServerConfig(it.guid)?.getProxyOutbound()
serversCache.forEachIndexed { index2, it2 ->
if (index2 > index) {
val outbound2 = MmkvManager.decodeServerConfig(it2.guid)?.getProxyOutbound()
if (outbound == outbound2 && !deleteServer.contains(it2.guid)) {
deleteServer.add(it2.guid)
}
}
}
}
for (it in deleteServer) {
MmkvManager.removeServer(it)
}
launch(Dispatchers.Main) {
reloadServerList()
getApplication<AngApplication>().toast(
getApplication<AngApplication>().getString(
R.string.title_del_duplicate_config_count,
deleteServer.count()
)
)
}

}
for (it in deleteServer) {
MmkvManager.removeServer(it)
}
getApplication<AngApplication>().toast(
getApplication<AngApplication>().getString(
R.string.title_del_duplicate_config_count,
deleteServer.count()
)
)
}

fun copyAssets(assets: AssetManager) {
Expand Down

0 comments on commit 47166b9

Please sign in to comment.