fix: remove runBlocking(Dispatchers.Main) deadlock — app now starts
- NetworkBinder functions were suspend but never actually suspended (ConnectivityManager calls are synchronous) — made them plain fun - MainActivity.discoverNetworks() now calls them directly, no coroutine - Wrapped in try/catch so network discovery failure doesn't crash Activity - Removed unused awaitNetwork() extension + coroutine imports
This commit is contained in:
@@ -1,30 +1,20 @@
|
||||
package com.yarisobd.app
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.yarisobd.app.ui.theme.YarisOBDTheme
|
||||
import com.yarisobd.app.util.NetworkBinder
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
// Discovered at startup — null if the network isn't available
|
||||
private var piClient: OkHttpClient? = null
|
||||
private var serverClient: OkHttpClient? = null
|
||||
|
||||
@@ -32,8 +22,6 @@ class MainActivity : ComponentActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
|
||||
// Discover networks synchronously at startup (fast — just reads
|
||||
// ConnectivityManager state, no network I/O)
|
||||
discoverNetworks()
|
||||
|
||||
setContent {
|
||||
@@ -52,17 +40,22 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
private fun discoverNetworks() {
|
||||
val context = applicationContext
|
||||
|
||||
// Blocking is fine here — NetworkBinder discovery just reads
|
||||
// ConnectivityManager state, no network calls.
|
||||
runBlocking(Dispatchers.Main) {
|
||||
val piNetwork = NetworkBinder.findPiHotspotNetwork(context)
|
||||
try {
|
||||
val piNetwork = NetworkBinder.findPiHotspotNetwork(applicationContext)
|
||||
piClient = piNetwork?.let { NetworkBinder.createBoundClient(it) }
|
||||
Log.d(TAG, "Pi WiFi network: ${if (piClient != null) "bound" else "not found"}")
|
||||
|
||||
val cellNetwork = NetworkBinder.findCellularNetwork(context)
|
||||
?: NetworkBinder.findDefaultNetwork(context)
|
||||
val cellNetwork = NetworkBinder.findCellularNetwork(applicationContext)
|
||||
?: NetworkBinder.findDefaultNetwork(applicationContext)
|
||||
serverClient = cellNetwork?.let { NetworkBinder.createBoundClient(it) }
|
||||
Log.d(TAG, "Cellular/default network: ${if (serverClient != null) "bound" else "not found"}")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Network discovery failed", e)
|
||||
// Both clients stay null — screen shows "not found" state
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "MainActivity"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,16 +4,10 @@ import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkRequest
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import okhttp3.Dns
|
||||
import okhttp3.OkHttpClient
|
||||
import java.net.InetAddress
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.Proxy
|
||||
import java.net.Socket
|
||||
import javax.net.SocketFactory
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
/**
|
||||
* Discovers and binds OkHttp clients to specific Android [Network] objects
|
||||
@@ -30,7 +24,7 @@ object NetworkBinder {
|
||||
* Identified by: TRANSPORT_WIFI + NO NET_CAPABILITY_INTERNET
|
||||
* (the Pi hotspot has no internet gateway).
|
||||
*/
|
||||
suspend fun findPiHotspotNetwork(context: Context): Network? {
|
||||
fun findPiHotspotNetwork(context: Context): Network? {
|
||||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
|
||||
return cm.allNetworks.firstOrNull { network ->
|
||||
@@ -44,7 +38,7 @@ object NetworkBinder {
|
||||
* Finds the cellular network.
|
||||
* Identified by: TRANSPORT_CELLULAR + NET_CAPABILITY_INTERNET
|
||||
*/
|
||||
suspend fun findCellularNetwork(context: Context): Network? {
|
||||
fun findCellularNetwork(context: Context): Network? {
|
||||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
|
||||
return cm.allNetworks.firstOrNull { network ->
|
||||
@@ -98,23 +92,3 @@ object NetworkBinder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a network with the given [transport] to become available.
|
||||
* Used at app startup to wait for the Pi hotspot to connect before
|
||||
* making API calls.
|
||||
*/
|
||||
suspend fun ConnectivityManager.awaitNetwork(transport: Int): Network {
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
val callback = object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network) {
|
||||
continuation.resume(network)
|
||||
}
|
||||
}
|
||||
val request = NetworkRequest.Builder()
|
||||
.addTransportType(transport)
|
||||
.build()
|
||||
registerNetworkCallback(request, callback)
|
||||
continuation.invokeOnCancellation { unregisterNetworkCallback(callback) }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user