1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
| import android.content.Context import android.content.res.ColorStateList import android.graphics.Color import android.util.AttributeSet import android.view.LayoutInflater import android.widget.FrameLayout import androidx.appcompat.widget.AppCompatTextView import androidx.core.content.ContextCompat import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.OnLifecycleEvent import com.yunda.android.framework.ui.YDLibApplication import com.yunda.transportapp.base.BuildConfig import com.yunda.transportapp.base.R import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.BufferedReader import java.io.InputStreamReader
class NetworkStatusView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : FrameLayout(context, attrs, defStyleAttr), LifecycleObserver {
private val statusTextView: AppCompatTextView private val coroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) private var monitoringJob: Job? = null
enum class NetworkStatus { NO_NETWORK, BAD_NETWORK, WEAK_NETWORK, AVERAGE_NETWORK, GOOD_NETWORK }
init { val view = LayoutInflater.from(context).inflate(R.layout.network_status_view, this, true) statusTextView = view.findViewById(R.id.statusTextView)
if (context is LifecycleOwner) { (context as LifecycleOwner).lifecycle.addObserver(this) } }
private suspend fun updateStatus(newStatus: NetworkStatus) { withContext(Dispatchers.Main){ when (newStatus) { NetworkStatus.NO_NETWORK -> { updateNetworkUI( "当前无法链接网络,请检查网络设置是否正常。", "#EC4444", R.drawable.icon_net_fail ) }
NetworkStatus.BAD_NETWORK -> { updateNetworkUI( "当前网络状态极差,请检查网络设置是否正常。", "#EC4444", R.drawable.icon_net_fail ) }
NetworkStatus.WEAK_NETWORK -> { updateNetworkUI( "当前网络状态较差,请小心驾驶。", "#F68B28", R.drawable.icon_net_moderate ) }
NetworkStatus.AVERAGE_NETWORK -> { updateNetworkUI( "当前网络状态良好,请小心驾驶。", "#14C97D", R.drawable.icon_net_good ) }
NetworkStatus.GOOD_NETWORK -> { updateNetworkUI( "当前网络状态极好,请小心驾驶。", "#3976F3", R.drawable.icon_net_ok ) } } } }
private fun updateNetworkUI(descStr: String, colorBg: String, iconResId: Int) { try { with(statusTextView) { text = descStr setCompoundDrawablesWithIntrinsicBounds( ContextCompat.getDrawable(YDLibApplication.INSTANCE, iconResId), null, null, null ) backgroundTintList = ColorStateList.valueOf(Color.parseColor(colorBg)) } } catch (e: Exception) { e.printStackTrace() }
}
private suspend fun checkNetworkSpeed(): NetworkStatus { return withContext(Dispatchers.IO) { try { val process = Runtime.getRuntime().exec("ping -c 1 www.baidu.com") val reader = BufferedReader(InputStreamReader(process.inputStream)) val output = reader.readLines() reader.close() val timeLine = output.find { it.contains("time=") } val timeValue = timeLine?.substringAfter("time=")?.substringBefore(" ms")?.toDoubleOrNull()
if (BuildConfig.DEBUG) { println("Ping time: $timeValue ms") } when { timeValue == null -> NetworkStatus.NO_NETWORK timeValue >= 0 && timeValue < 100 -> NetworkStatus.GOOD_NETWORK timeValue >= 100 && timeValue < 200 -> NetworkStatus.AVERAGE_NETWORK timeValue >= 200 && timeValue < 600 -> NetworkStatus.WEAK_NETWORK else -> NetworkStatus.BAD_NETWORK } } catch (e: Exception) { e.printStackTrace() NetworkStatus.NO_NETWORK } }
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME) fun startMonitoring() { monitoringJob = coroutineScope.launch { while (isActive) { val status = checkNetworkSpeed() updateStatus(status) delay(5000) } } }
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) fun stopMonitoring() { monitoringJob?.cancel() } }
|